diff options
| author | Gabriel Schneider <[email protected]> | 2026-09-28 09:05:35 -0300 |
|---|---|---|
| committer | Gabriel Schneider <[email protected]> | 2026-10-01 00:12:14 -0300 |
| commit | 0d04bc9214cccce42d74862b31376d49bdda3956 (patch) | |
| tree | b45286fe0847b08c76e6abd562f6e2f985322e17 /test | |
| parent | 66c0106691e4de925011f314200e85ee265b7861 (diff) | |
| download | pardes-0d04bc9214cccce42d74862b31376d49bdda3956.tar.gz pardes-0d04bc9214cccce42d74862b31376d49bdda3956.zip | |
Let s, S and | pressed in a tag answer for the tag's own text
A tag is a text like the body, so selecting on a regex and piping act on the
text they are pressed in: a prompt records the text it answers for, the tag
keeps the keyboard while it is typed, and a header's prompt goes on the active
pane's band. `/` still searches the body from anywhere, as acme's Look from a
tag searches the body.
Co-Authored-By: Claude Opus 5.5 <[email protected]>
Diffstat (limited to 'test')
| -rw-r--r-- | test/panes.zig | 55 |
1 files changed, 41 insertions, 14 deletions
diff --git a/test/panes.zig b/test/panes.zig index 9b800430..d8ed517f 100644 --- a/test/panes.zig +++ b/test/panes.zig @@ -293,6 +293,33 @@ const TagNavigationTests = struct { p.update(.{ .key = .{ .cp = cp } }); } + test "s, S and | in a tag answer for the tag's own text; / still searches the body" { + const p = try Pardes.init(std.testing.allocator, .{ .tty_only = true, .cols = 100, .rows = 20 }); + defer p.deinit(); + const pane = try p.setTestFile("Some body\n"); + try setTag(pane, " Save Del Snarf"); + key(p, ':'); + key(p, 'x'); // the tag's line + key(p, 's'); + try std.testing.expect(pane.prompt == .search and pane.prompt_for == .tag and pane.focus == .tag); + p.update(.{ .key = .{ .cp = 'S', .text = "S" } }); + key(p, Key.enter); + try std.testing.expect(pane.focus == .tag and pane.prompt == .none); + var ranges: [panes.Text.max_selections]modal.Selection = undefined; + const text = try pardes.edit.flatSurface(p, &pane.tag); + const got = pane.tag.ranges(text, 0, &ranges); + try std.testing.expectEqual(@as(usize, 2), got.n); + for (ranges[0..got.n]) |range| try std.testing.expectEqualStrings("S", text[@min(range.anchor, range.head)..@max(range.anchor, range.head)]); + // the body's selection is its own + try std.testing.expectEqual(@as(u8, 0), pane.body.nsel); + // `/` from the tag is the body's search, as acme's Look from a tag is + key(p, ','); + key(p, '/'); + try std.testing.expect(pane.prompt == .search and pane.prompt_for == .body and pane.focus == .body); + key(p, Key.escape); + try std.testing.expect(pane.prompt == .none and pane.focus == .body); + } + fn window(p: *Pardes, letter: u21) void { p.update(.{ .key = .{ .cp = 'w', .ctrl = true } }); key(p, letter); @@ -345,7 +372,7 @@ const TagNavigationTests = struct { try std.testing.expectEqual(@as(i32, 6), first.tag.cur_col); key(p, Key.escape); key(p, ':'); - p.startPrompt(first, .{ .search = config.search_marker }); + p.startPrompt(first, &first.body, .{ .search = config.search_marker }); key(p, Key.escape); key(p, ':'); try std.testing.expectEqual(@as(i32, 6), first.tag.cur_col); @@ -1483,7 +1510,7 @@ test "paste into pane commands and prompts never inserts into the body" { p.update(.{ .paste = " Custom\nCommand" }); try std.testing.expect(std.mem.indexOf(u8, pardes.tagline.curTail(pane), " Custom\nCommand") != null); p.update(.{ .key = .{ .cp = Key.escape } }); - p.startPrompt(pane, .{ .search = config.search_marker }); + p.startPrompt(pane, &pane.body, .{ .search = config.search_marker }); p.update(.{ .paste = "t\r\nwo" }); try std.testing.expectEqualStrings(config.search_marker ++ "two", pane.promptText().?); try std.testing.expect(std.mem.indexOf(u8, pardes.tagline.curTail(pane), " Custom\nCommand") != null); @@ -1806,9 +1833,9 @@ test "a prompt's entry and cancellation leave the tag, the body and its cursor a if (case.key) |key| { p.update(.{ .key = key }); } else if (case.save) { - p.startPrompt(pane, .save); + p.startPrompt(pane, &pane.body, .save); } else { - p.startPrompt(pane, .{ .search = config.search_marker }); + p.startPrompt(pane, &pane.body, .{ .search = config.search_marker }); } // The answer is typed into the prompt's own line, never the tag. try std.testing.expect(pane.focus == .body); @@ -1838,8 +1865,8 @@ test "a prompt opens whatever the tag already holds" { try setTag(pane, full); for (0..3) |case| { switch (case) { - 0 => p.startPrompt(pane, .{ .search = config.search_marker }), - 1 => p.startPrompt(pane, .save), + 0 => p.startPrompt(pane, &pane.body, .{ .search = config.search_marker }), + 1 => p.startPrompt(pane, &pane.body, .save), else => p.update(.{ .key = .{ .cp = '|' } }), } try std.testing.expect(pane.prompt != .none); @@ -1871,9 +1898,9 @@ test "a prompt owns the pipe behavior through cancellation and submission" { pane.body.cur_col = 2; pane.body.vsel = .{ .active = true, .row = 0, .col = 0, .explicit = true }; for (std.enums.values(modal.Normal.PipeBehavior)) |how| { - p.startPrompt(pane, .{ .pipe = .append }); + p.startPrompt(pane, &pane.body, .{ .pipe = .append }); p.update(.{ .key = .{ .cp = Key.escape } }); - p.startPrompt(pane, .{ .pipe = how }); + p.startPrompt(pane, &pane.body, .{ .pipe = how }); try std.testing.expectEqual(how, pane.prompt.pipe); p.update(.{ .key = .{ .cp = 'c', .text = "cat" } }); p.update(.{ .key = .{ .cp = Key.enter } }); @@ -1915,19 +1942,19 @@ test "prompt cancellation restores the selection before regex previews" { } test "a prompt that cannot be opened leaves the open one as it was" { - const Request = @typeInfo(@TypeOf(Pardes.startPrompt)).@"fn".params[2].type.?; + const Request = @typeInfo(@TypeOf(Pardes.startPrompt)).@"fn".params[3].type.?; for ([_]Request{ .{ .search = config.search_marker }, .save, .{ .pipe = .replace }, .{ .pipe = .ignore }, .{ .pipe = .insert }, .{ .pipe = .append } }) |request| { var failing = std.testing.FailingAllocator.init(std.testing.allocator, .{}); const p = try Pardes.init(failing.allocator(), .{ .tty_only = true }); defer p.deinit(); const pane = try p.setTestFile("one\n"); - p.startPrompt(pane, .{ .search = config.search_marker }); + p.startPrompt(pane, &pane.body, .{ .search = config.search_marker }); p.update(.{ .key = .{ .cp = 'p', .text = "prior" } }); pane.body.normal = .{ .count = 9, .prefix = .goto }; const previous_normal = pane.body.normal; _ = p.scratch.reset(.free_all); failing.fail_index = failing.alloc_index; - p.startPrompt(pane, request); + p.startPrompt(pane, &pane.body, request); try std.testing.expect(failing.has_induced_failure); try std.testing.expect(pane.prompt == .search); try std.testing.expectEqualStrings(config.search_marker ++ "prior", pane.promptText().?); @@ -1943,7 +1970,7 @@ test "Save's prompt starts from the pane's directory" { for ([_][]const u8{ "/dír space", "/dír space/", "" }) |dir| { try pane.setOwnedCwd(dir); const slash = if (dir.len == 0 or dir[dir.len - 1] != '/') "/" else ""; - p.startPrompt(pane, .save); + p.startPrompt(pane, &pane.body, .save); try std.testing.expect(pane.prompt == .save); const answer = pane.promptText().?; try std.testing.expect(std.mem.startsWith(u8, answer, config.save_marker)); @@ -1954,7 +1981,7 @@ test "Save's prompt starts from the pane's directory" { } test "a prompt opens with one allocation" { - const Request = @typeInfo(@TypeOf(Pardes.startPrompt)).@"fn".params[2].type.?; + const Request = @typeInfo(@TypeOf(Pardes.startPrompt)).@"fn".params[3].type.?; for ([_]Request{ .{ .search = config.search_marker }, .save, .{ .pipe = .replace }, .{ .pipe = .ignore }, .{ .pipe = .insert }, .{ .pipe = .append } }) |request| { var failing = std.testing.FailingAllocator.init(std.testing.allocator, .{}); const p = try Pardes.init(failing.allocator(), .{ .tty_only = true }); @@ -1962,7 +1989,7 @@ test "a prompt opens with one allocation" { const pane = try p.setTestFile("one\n"); _ = p.scratch.reset(.free_all); const before = failing.alloc_index; - p.startPrompt(pane, request); + p.startPrompt(pane, &pane.body, request); try std.testing.expectEqual(before + 1, failing.alloc_index); try std.testing.expect(pane.focus == .body and pane.input.mode == .insert); } |
