diff options
| author | Gabriel Schneider <[email protected]> | 2026-09-28 19:36:58 -0300 |
|---|---|---|
| committer | Gabriel Schneider <[email protected]> | 2026-10-01 00:12:15 -0300 |
| commit | 1df6bd12fafbf97062f7844a23de208add75a843 (patch) | |
| tree | 78b61cfebeb12c40b679d053b457d2e28f232784 /src/edit.zig | |
| parent | 1f8de151e382755c1ce597f166ea4552e7f7e8d1 (diff) | |
| download | pardes-1df6bd12fafbf97062f7844a23de208add75a843.tar.gz pardes-1df6bd12fafbf97062f7844a23de208add75a843.zip | |
A pane tag wraps onto rows and can collapse to one, as acme's does
acme's frame wraps a tag at its right edge and the window grows to show
every row (wind.c wintaglines); Tagup/Tagdown shrink it to one row and back.
Pane tags used to be one row, scrolled sideways to the caret. Now a tag's
lines wrap at its width (one cell kept for the caret past a full row) and it
starts expanded; insert-mode Up on the first row collapses it, Down on the
last row expands it, and Alt-Up/Alt-Down do so in either mode. A word the
wrap breaks across rows is still one word to a click and a selection.
Column and workspace tags keep scrolling sideways.
Tests read body rows relative to the body's first row; the 41 snapshot
goldens that moved were re-recorded by name after a programmatic check that
each differs only by body rows shifting under the taller tags, and twelve
scripts whose clicks targeted fixed rows now click the same text.
Co-Authored-By: Claude Opus 5.5 <[email protected]>
Diffstat (limited to 'src/edit.zig')
| -rw-r--r-- | src/edit.zig | 24 |
1 files changed, 22 insertions, 2 deletions
diff --git a/src/edit.zig b/src/edit.zig index 1e480785..a194ef48 100644 --- a/src/edit.zig +++ b/src/edit.zig @@ -202,7 +202,7 @@ pub fn clipYank(p: *Pardes, pane: *Pane, main_only: bool) void { /// (the tag's lines first, the ones it shows) pub fn paneText(p: *Pardes, pane: *Pane) ![]u8 { const arena = p.scratch.allocator(); - const tag = try tagline.tagText(p, arena, pane); + const tag = (try tagline.shownTag(p, arena, pane)).text; const from = modal.lineStartOffset(tag, pane.tag_top); const cut = modal.lineStartOffset(tag, pane.tag_top + pane.tag_rows); const shown = if (cut < tag.len) tag[from .. cut - 1] else tag[from..]; @@ -299,13 +299,20 @@ pub fn selectionText(p: *Pardes, pane: *Pane, sl: Pane.Sel) ![]const u8 { return result; } const text = try paneText(p, pane); + const shown = try tagline.shownTag(p, arena, pane); var out: std.ArrayList(u8) = .empty; var it = std.mem.splitAny(u8, text, "\n"); var v: i32 = 0; var first = true; while (it.next()) |line| : (v += 1) { const cols = sweepCols(sl, v) orelse continue; - if (!first) try out.append(arena, '\n'); + // A row the tag's wrapping began carries on its text: no newline. + const soft = v > 0 and v < pane.tag_rows and std.mem.indexOfScalar( + usize, + shown.soft, + modal.lineStartOffset(shown.text, @as(usize, @intCast(v)) + pane.tag_top) -| 1, + ) != null; + if (!first and !soft) try out.append(arena, '\n'); first = false; // Past the first row a body row starts after its line numbers. const gutter: i32 = if (pane.file != null and v >= pane.tag_rows) panes.File.gutterWidth(pane) else 0; @@ -750,6 +757,19 @@ fn insertEdit(p: *Pardes, t: *Text, key: Key) void { Key.left, Key.right, Key.up, Key.down => { const lines = paneCursorLines(p, t) catch return; const cur0 = t.toModalCursor(); + // In a pane's tag, Up on its first line collapses it and Down + // on its last expands it, where they would move nothing; acme's + // arrows in a tag always do (plan9port text.c:776, Tagdown/Tagup). + if (t.what == .tag) if (t.pane()) |pane| { + if (key.cp == Key.up and cur0.row == 0) { + pane.tag_expanded = false; + return; + } + if (key.cp == Key.down and cur0.row + 1 >= lines.len) { + pane.tag_expanded = true; + return; + } + }; const nc = switch (key.cp) { Key.left => modal.charLeft(lines, cur0), Key.right => modal.charRight(lines, cur0), |
