From a9de2b51ab76a43250a4d6c41a0ddd54e6970049 Mon Sep 17 00:00:00 2001 From: Gabriel Schneider Date: Mon, 28 Sep 2026 09:16:36 -0300 Subject: Let the keyboard reach a tag's path, read-only The tag's computed path, dirty marker and page were out of the keyboard's reach: its cursor lived in the text after them. It now lives in the tag as shown, as in acme where the name is ordinary text at the start of the tag, so `0` goes to the line's start and motions select and yank the path. The path stays read-only: an edit that would change it is refused and leaves the cursor where it was, and typing into a file's path drafts a new name as a click on it does. Sync moves the tag's positions when the prefix changes length, so a rename or the dirty marker still never moves the cursor off the text after it. Co-Authored-By: Claude Opus 5.5 --- src/body_layer.zig | 16 +++++++--------- 1 file changed, 7 insertions(+), 9 deletions(-) (limited to 'src/body_layer.zig') diff --git a/src/body_layer.zig b/src/body_layer.zig index ff1f903c..f9e26b10 100644 --- a/src/body_layer.zig +++ b/src/body_layer.zig @@ -925,8 +925,7 @@ pub fn paintPaneTag(p: *Pardes, arena: std.mem.Allocator, pane: *Pane, r: Rect, .{ .row = 0, .at = @min(lines[0].len, @as(usize, @intCast(@max(0, pane.input.cur_col)))) } else if (pane.focus == .tag and pane.prompt == .none and pane.tag.cur_row >= top and pane.tag.cur_row < top + rows) caret: { const row: usize = @intCast(pane.tag.cur_row - top); - const lead: usize = if (row + top == 0) prefix_len else 0; - break :caret .{ .row = row, .at = @min(lines[row].len, lead + @as(usize, @intCast(@max(0, pane.tag.cur_col)))) }; + break :caret .{ .row = row, .at = @min(lines[row].len, @as(usize, @intCast(@max(0, pane.tag.cur_col)))) }; } else null; if (caret) |at| { const line = lines[at.row]; @@ -968,19 +967,18 @@ pub fn paintPaneTag(p: *Pardes, arena: std.mem.Allocator, pane: *Pane, r: Rect, // time. A range of one grapheme is the block cursor, not a selection. if (pane.focus == .tag) { var ranges: [Text.max_selections]modal.Selection = undefined; - const got = pane.tag.ranges(tail, 0, &ranges); + const got = pane.tag.ranges(whole, 0, &ranges); for (ranges[0..got.n]) |range| { const lo = @min(range.anchor, range.head); const hi = @max(range.anchor, range.head); - if (modal.nextGrapheme(tail, lo) >= hi) continue; - const first = modal.positionAt(tail, lo); - const last = modal.positionAt(tail, hi); + if (modal.nextGrapheme(whole, lo) >= hi) continue; + const first = modal.positionAt(whole, lo); + const last = modal.positionAt(whole, hi); var row = @max(first.row, top); while (row <= last.row and row < top + rows) : (row += 1) { const line = lines[row - top]; - const lead: usize = if (row == 0) prefix_len else 0; - const from = lead + if (row == first.row) first.col else 0; - const to = @min(line.len, lead + if (row == last.row) last.col else modal.lineSlice(tail, row).len); + const from = if (row == first.row) first.col else 0; + const to = @min(line.len, if (row == last.row) last.col else line.len); var col = panes.File.rawDisplayCol(line, from) -| pane.tag_scroll; const end = panes.File.rawDisplayCol(line, to); const y = tag_y + @as(u16, @intCast(row - top)); -- cgit v1.3