Add current file search
This commit is contained in:
+51
-13
@@ -21,6 +21,7 @@ pub const Action = union(enum) {
|
||||
quit,
|
||||
open: []u8,
|
||||
symbol: symbol_mod.Symbol,
|
||||
search_file,
|
||||
repeat_rail,
|
||||
restore_last,
|
||||
not_built: Feature,
|
||||
@@ -37,6 +38,7 @@ const Mode = enum {
|
||||
idle,
|
||||
rail,
|
||||
symbol_rail,
|
||||
search_rail,
|
||||
open_prompt,
|
||||
};
|
||||
|
||||
@@ -60,6 +62,7 @@ pub const Leader = struct {
|
||||
.idle => return self.handleIdle(event),
|
||||
.rail => return self.handleRail(event),
|
||||
.symbol_rail => return self.handleSymbolRail(event),
|
||||
.search_rail => return self.handleSearchRail(event),
|
||||
.open_prompt => return self.handleOpenPrompt(event),
|
||||
}
|
||||
}
|
||||
@@ -68,8 +71,9 @@ pub const Leader = struct {
|
||||
if (self.message) |message| return message;
|
||||
return switch (self.mode) {
|
||||
.idle => "",
|
||||
.rail => "leader: s save q quit o open p symbols r repeat / search x close",
|
||||
.rail => "leader: w save q quit o open p symbols s search r repeat x close",
|
||||
.symbol_rail => symbol_mod.rail_status,
|
||||
.search_rail => "search: f current file p project s symbols",
|
||||
.open_prompt => "open: type path, Enter opens, Esc cancels",
|
||||
};
|
||||
}
|
||||
@@ -106,10 +110,14 @@ pub const Leader = struct {
|
||||
self.message = null;
|
||||
switch (event) {
|
||||
.text => |text| {
|
||||
if (std.mem.eql(u8, text, "s")) {
|
||||
if (std.mem.eql(u8, text, "w")) {
|
||||
self.mode = .idle;
|
||||
return .save;
|
||||
}
|
||||
if (std.mem.eql(u8, text, "s")) {
|
||||
self.mode = .search_rail;
|
||||
return .none;
|
||||
}
|
||||
if (std.mem.eql(u8, text, "q")) {
|
||||
self.mode = .idle;
|
||||
return .quit;
|
||||
@@ -127,11 +135,6 @@ pub const Leader = struct {
|
||||
self.mode = .idle;
|
||||
return .repeat_rail;
|
||||
}
|
||||
if (std.mem.eql(u8, text, "/")) {
|
||||
self.mode = .idle;
|
||||
self.message = "search is not built in this profile yet";
|
||||
return .{ .not_built = .search };
|
||||
}
|
||||
if (std.mem.eql(u8, text, "x")) {
|
||||
self.mode = .idle;
|
||||
self.message = "panel close is not built in this profile yet";
|
||||
@@ -165,6 +168,35 @@ pub const Leader = struct {
|
||||
}
|
||||
}
|
||||
|
||||
fn handleSearchRail(self: *Leader, event: input.Event) Action {
|
||||
self.message = null;
|
||||
switch (event) {
|
||||
.text => |text| {
|
||||
self.mode = .idle;
|
||||
if (std.mem.eql(u8, text, "f")) return .search_file;
|
||||
self.message = "search target is not built in this profile yet";
|
||||
return .{ .not_built = .search };
|
||||
},
|
||||
.key => |key| switch (key) {
|
||||
.escape, .backspace => {
|
||||
self.mode = .idle;
|
||||
self.message = "search cancelled";
|
||||
return .none;
|
||||
},
|
||||
else => {
|
||||
self.mode = .idle;
|
||||
self.message = "unknown search key";
|
||||
return .none;
|
||||
},
|
||||
},
|
||||
.unknown => {
|
||||
self.mode = .idle;
|
||||
self.message = "unknown search key";
|
||||
return .none;
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
fn handleSymbolRail(self: *Leader, event: input.Event) Action {
|
||||
self.message = null;
|
||||
switch (event) {
|
||||
@@ -241,14 +273,14 @@ fn expectActionTag(expected: std.meta.Tag(Action), action: Action) !void {
|
||||
try std.testing.expectEqual(expected, std.meta.activeTag(action));
|
||||
}
|
||||
|
||||
test "regular: space opens a visible leader rail and save dispatches" {
|
||||
test "regular: space opens a visible leader rail and write dispatches" {
|
||||
var leader = Leader.init(std.testing.allocator);
|
||||
defer leader.deinit();
|
||||
|
||||
try expectActionTag(.none, try leader.handleEvent(input.normalize(" ")));
|
||||
try std.testing.expectEqualStrings("leader: s save q quit o open p symbols r repeat / search x close", leader.status());
|
||||
try std.testing.expectEqualStrings("leader: w save q quit o open p symbols s search r repeat x close", leader.status());
|
||||
|
||||
try expectActionTag(.save, try leader.handleEvent(input.normalize("s")));
|
||||
try expectActionTag(.save, try leader.handleEvent(input.normalize("w")));
|
||||
try std.testing.expect(!leader.isActive());
|
||||
}
|
||||
|
||||
@@ -282,17 +314,23 @@ test "regular: leader open prompt collects UTF-8 path and backspace respects cod
|
||||
}
|
||||
}
|
||||
|
||||
test "regular: not-yet-built leader entries are explicit recoverable actions" {
|
||||
test "regular: search rail opens current-file search and rejects other targets" {
|
||||
var leader = Leader.init(std.testing.allocator);
|
||||
defer leader.deinit();
|
||||
|
||||
try expectActionTag(.none, try leader.handleEvent(input.normalize(" ")));
|
||||
const action = try leader.handleEvent(input.normalize("/"));
|
||||
try expectActionTag(.none, try leader.handleEvent(input.normalize("s")));
|
||||
try std.testing.expectEqualStrings("search: f current file p project s symbols", leader.status());
|
||||
try expectActionTag(.search_file, try leader.handleEvent(input.normalize("f")));
|
||||
|
||||
try expectActionTag(.none, try leader.handleEvent(input.normalize(" ")));
|
||||
try expectActionTag(.none, try leader.handleEvent(input.normalize("s")));
|
||||
const action = try leader.handleEvent(input.normalize("p"));
|
||||
switch (action) {
|
||||
.not_built => |feature| try std.testing.expectEqual(Feature.search, feature),
|
||||
else => return error.ExpectedNotBuiltAction,
|
||||
}
|
||||
try std.testing.expectEqualStrings("search is not built in this profile yet", leader.status());
|
||||
try std.testing.expectEqualStrings("search target is not built in this profile yet", leader.status());
|
||||
}
|
||||
|
||||
test "adversarial: unknown leader key does not dispatch and recovers to idle" {
|
||||
|
||||
Reference in New Issue
Block a user