summaryrefslogtreecommitdiff
path: root/src/output_pane.zig
diff options
context:
space:
mode:
authorGabriel Schneider <[email protected]>2026-07-31 02:40:11 -0300
committerGabriel Schneider <[email protected]>2026-08-01 15:02:08 -0300
commit7022d738dba00049e820e969cabc34ecbeaea465 (patch)
tree28d32929255ba21144d579e210a658f6c1fb1943 /src/output_pane.zig
parent0bfa4615988c0d1bcaa38453375760c60076c5ea (diff)
downloadpardes-7022d738dba00049e820e969cabc34ecbeaea465.tar.gz
pardes-7022d738dba00049e820e969cabc34ecbeaea465.zip
Help lists every builtin and every way to reach it
Not a second builtin: Help already rendered "every builtin with a leader path and the key that runs it", and the ask is "every builtin and every shortcut" — the same listing with three more rows and one more column. A new builtin would have been a second renderer over a superset of the same rows, and the two would drift the first time a column moved. The prefix filter is now the degenerate case of the index rather than a separate mode: SPC h ? reads the same array with prefix "h", and the path-less builtins fall out on their own because an empty path starts with nothing. The shortcut column is folded, never typed: chordName spells a chord from Key's OWN declarations, so a new special key names itself and an unnamed non-printable codepoint is a compile error instead of garbage; shortcuts() walks the cmd columns of window_keys and jump_keys, look_cmd/exec_cmd with their keys and buttons, and topbar_str. Retarget a binding in config.zig and this re-renders. So Look reads `enter, right-click`, Back reads `C-o`, Kill reads `topbar`, and Theme reads nothing at all — which is the information. Not a picker, deliberately: n/N stepping a list holding Kill, Del and Delcol would end the session. The names are live text, so middle-click the one you want. Alt-n, Alt-c, the tty toggle and the cut/paste chords cannot appear — they are inline handlers that reach no builtin, so there is no row to put them on. Make one a struct with a cmd column beside its binding and it appears for free. Three goldens moved, all of them the +Help buffer's contents.
Diffstat (limited to 'src/output_pane.zig')
-rw-r--r--src/output_pane.zig36
1 files changed, 28 insertions, 8 deletions
diff --git a/src/output_pane.zig b/src/output_pane.zig
index a0583506..9c004dff 100644
--- a/src/output_pane.zig
+++ b/src/output_pane.zig
@@ -123,6 +123,14 @@ pub fn traits(o: Origin) Traits {
// rows are `location text`, so n/N walk them
.search => .{ .name = config.search_buffer, .steps = true },
.cmd => |b| switch (b) {
+ // The builtin index. Neither steppable nor executable, and that is
+ // a decision rather than an omission: its rows are not locations
+ // (a look on `SPC` would go looking for a file called SPC), and
+ // `executes` — which is exactly what makes ThemeSel a picker —
+ // would mean walking the list runs Kill, Del and Delcol in turn.
+ // Wearing a theme is free; wearing Kill ends the session. The
+ // names in it are still live text, so middle-clicking the ONE you
+ // want does the picking, which is all a picker was for.
.Help => .{ .name = config.help_buffer },
// the focus history, one location per row: not a search, but the
// same kind of list, so n/N walk it and a row is a look target
@@ -303,24 +311,36 @@ fn openStepped(p: *Pardes, id: usize, from: Origin, text: []const u8) void {
pane.search_row = null;
}
-/// The Help builtin: every builtin reachable from `prefix` (empty = all
-/// of them) with the keys that run it, written into an output buffer
-/// (acme's +Errors) — ordinary text, so the names in it are LIVE: middle-
-/// click `Tutor` there and the tutor opens. Reuses the open +Help buffer
-/// instead of piling panes up, and focus follows: you asked to read it.
+/// The Help builtin: THE INDEX of builtins — every one of them, and every way
+/// to run it — filtered to what `prefix` can still reach, written into an
+/// output buffer (acme's +Errors). Ordinary text, so the names in it are LIVE:
+/// middle-click `Tutor` there and the tutor opens. Reuses the open +Help
+/// buffer instead of piling panes up, and focus follows: you asked to read it.
+///
+/// ONE builtin and not two. The complete index and the mid-chord "what can
+/// `SPC h` still reach" are the same array (pardes.builtin_rows) read with a
+/// different prefix — the empty one matches every row, including the builtins
+/// SPC cannot reach at all, so the reference page IS the filter's degenerate
+/// case. A second builtin would have been a second renderer over a superset of
+/// these rows, and the two would have drifted the first time a column moved.
pub fn openHelp(p: *Pardes, id: usize, prefix: []const u8) void {
const pane = p.panes[id] orelse return;
const arena = p.scratch.allocator();
var out: std.ArrayList(u8) = .empty;
if (prefix.len == 0) {
- out.appendSlice(arena, "pardes builtins - SPC then the keys,\nor execute the name anywhere\n\n") catch return;
+ // the header names the four KINDS of shortcut a row's columns can
+ // hold, because a blank column is only readable once you know what
+ // would have been in it
+ out.appendSlice(arena, "pardes builtins, and how to run each:\nSPC and its keys, a chord, a button, the\ntopbar - or the name, executed anywhere.\n\n") catch return;
} else {
out.appendSlice(arena, "pardes builtins under SPC") catch return;
for (prefix) |c| out.appendSlice(arena, &[_]u8{ ' ', c }) catch return;
out.appendSlice(arena, "\n\n") catch return;
}
- for (pardes.leader_rows) |row| {
- if (!std.mem.startsWith(u8, row.path, prefix)) continue;
+ for (pardes.builtin_rows) |row| {
+ // a path-less builtin filters as the empty path: in the full listing
+ // (which starts with nothing) and out of every group
+ if (!std.mem.startsWith(u8, row.path orelse "", prefix)) continue;
out.appendSlice(arena, row.line) catch return;
out.append(arena, '\n') catch return;
}