diff options
| author | Gabriel Schneider <[email protected]> | 2026-09-28 00:01:57 -0300 |
|---|---|---|
| committer | Gabriel Schneider <[email protected]> | 2026-10-01 00:12:14 -0300 |
| commit | 23f430573efe4f6ef55b0180aa0d742ff4eca1d9 (patch) | |
| tree | da2157ba73d6abff4b1674541433294fb6c2daa9 /src/panes.zig | |
| parent | 9584b0682b45f17aaa42157540947904d867777a (diff) | |
| download | pardes-23f430573efe4f6ef55b0180aa0d742ff4eca1d9.tar.gz pardes-23f430573efe4f6ef55b0180aa0d742ff4eca1d9.zip | |
Make a pane's tag a Text edited with the body's own keys
The tag was a fixed buffer with its own one-line editor, a cursor measured
across the path, and a hijack of the body's mode while it was typed into.
It is now the pane's second Text: its own characters after the computed
prefix (path, dirty marker, PDF page), which is never stored in it, so a
rename or a dirty marker never moves its cursor. Normal and insert mode are
the body's, undo included; `:` moves the keyboard between body and tag, the
tag remembers its cursor and starts on Save, and executing a word from it
hands the keyboard back. The mouse still sees the prefix: a sweep selects
across it and a click on the path drafts a new name.
Co-Authored-By: Claude Opus 5.5 <[email protected]>
Diffstat (limited to 'src/panes.zig')
| -rw-r--r-- | src/panes.zig | 66 |
1 files changed, 23 insertions, 43 deletions
diff --git a/src/panes.zig b/src/panes.zig index c26065ca..720f655f 100644 --- a/src/panes.zig +++ b/src/panes.zig @@ -69,9 +69,14 @@ pub const Pane = struct { /// Del from the keyboard with open panes both above and below: which /// one takes the rows. Nothing is typed; one key answers. del_side, + /// A new name for the file, drafted in place of the path on the + /// tagline after a click there; Enter commits it, as a buffer name + /// and never a disk rename. + name, }; pub const Cwd = union(enum) { none, inherited: *Pane, owned: []u8 }; + pub const Focus = enum { body, tag }; terminal: ?*Terminal.State = null, gpa: std.mem.Allocator, serial: u32 = 0, @@ -97,8 +102,9 @@ pub const Pane = struct { pdf: PdfSlot = if (Pdf.enabled) null else {}, prompt: Prompt = .none, /// The answer to an open prompt: its marker and what is typed after it, - /// edited in insert mode and shown on the notice band. It is its own text - /// so a prompt never touches the tag. + /// edited in insert mode and shown on the notice band, or a name draft + /// shown on the tagline in place of the path. It is its own text so a + /// prompt never touches the tag. input: Text = .{ .what = .input }, search_pane: ?usize = null, search_row: ?usize = null, @@ -107,23 +113,12 @@ pub const Pane = struct { nsel_snap: u8 = 0, sel_snap_pri: u8 = 0, sel_snap_expl: bool = false, - /// the editable tag tail: a bounded one-line command buffer. Input that - /// does not fit is refused atomically. - tag_tail: [limits.max_tag_tail]u8 = undefined, - tag_tail_len: usize = 0, - tag_init: bool = false, - tag_edit: bool = false, - tag_sel: bool = false, - /// the body mode a tag edit hijacked (tags are always insert); terminals - /// restore it on exit so clicking the tag never changes the pane's mode - tag_mode: Text.Mode = .normal, - tag_col: u16 = 0, - tag_saved_col: ?u16 = null, - tag_anchor: u16 = 0, - /// Filename edits are staged separately from the live buffer identity. - /// Enter commits the name; leaving tag editing discards the draft. - tag_name: [limits.host_path_cap]u8 = undefined, - tag_name_len: ?u16 = null, + /// The tag: what the user keeps after the computed prefix (the path, the + /// dirty marker, a PDF's page), its cursor, selections and undo. The + /// prefix is never stored in it, so it never moves the tag's cursor. + tag: Text = .{ .what = .tag }, + /// Which of the pane's texts the keyboard types into. + focus: Focus = .body, /// Display columns hidden to reveal the tag caret; tag addresses stay whole. tag_scroll: u16 = 0, cwd: Cwd = .none, @@ -297,9 +292,15 @@ pub const Pane = struct { return null; } - pub fn tagSlice(p: *const Pane) []const u8 { - return p.tag_tail[0..p.tag_tail_len]; + /// Add `text` to the end of the tag's own text, which starts out as the + /// default a pane of its kind shows. + pub fn appendTag(pane: *Pane, text: []const u8) !void { + const had = pane.tag.own orelse pardes.Pardes.defaultTail(pane); + const grown = try std.mem.concat(pane.gpa, u8, &.{ had, text }); + if (pane.tag.own) |old| pane.gpa.free(old); + pane.tag.own = grown; } + /// Close an open prompt, answered or not. Its answer goes with it, and an /// s/S preview keeps whatever it last previewed. pub fn closePrompt(pane: *Pane) void { @@ -313,33 +314,12 @@ pub const Pane = struct { /// painter of the band reads. pub fn promptText(p: *const Pane) ?[]const u8 { return switch (p.prompt) { - .none => null, + .none, .name => null, .del_side => config.del_question, else => p.input.own orelse "", }; } - pub fn appendTag(p: *Pane, text: []const u8) bool { - if (text.len > p.tag_tail.len - p.tag_tail_len) return false; - @memcpy(p.tag_tail[p.tag_tail_len..][0..text.len], text); - p.tag_tail_len += text.len; - return true; - } - - pub fn insertTagByte(p: *Pane, at: usize, byte: u8) bool { - if (at > p.tag_tail_len or p.tag_tail_len == p.tag_tail.len) return false; - std.mem.copyBackwards(u8, p.tag_tail[at + 1 .. p.tag_tail_len + 1], p.tag_tail[at..p.tag_tail_len]); - p.tag_tail[at] = byte; - p.tag_tail_len += 1; - return true; - } - - pub fn removeTagByte(p: *Pane, at: usize) void { - if (at >= p.tag_tail_len) return; - std.mem.copyForwards(u8, p.tag_tail[at .. p.tag_tail_len - 1], p.tag_tail[at + 1 .. p.tag_tail_len]); - p.tag_tail_len -= 1; - } - pub fn cwdSlice(p: *const Pane) []const u8 { return switch (p.cwd) { .none => "", |
