summaryrefslogtreecommitdiff
path: root/src/output_pane.zig
diff options
context:
space:
mode:
authorGabriel Schneider <[email protected]>2026-07-30 23:35:45 -0300
committerGabriel Schneider <[email protected]>2026-08-01 15:02:07 -0300
commit19f7322100062b7c1adcde3376063ce6c1d8c72d (patch)
treeb76347dffe0347c29a38b4cad6031678683dba74 /src/output_pane.zig
parent753d5451ca7d09dbc5ff44f3c2dcf9a47fb87f96 (diff)
downloadpardes-19f7322100062b7c1adcde3376063ce6c1d8c72d.tar.gz
pardes-19f7322100062b7c1adcde3376063ce6c1d8c72d.zip
structure: backends into src/{tty,gui,lsp}, pane kinds and builtins into their own files
The core now lies FLAT at src/ and every subdirectory is one backend, so a file being in no directory at all is what says it is core. Pane-kind bodies leave pardes.zig for term_pane.zig / file_pane.zig / output_pane.zig, leaving it the layout, the event/effect machine and the generic render loop. Builtins are one struct each in builtins.zig, and the enum is folded out of the file's own declaration list at comptime — a zig file IS a struct, so the list of builtins and the builtins themselves are the same text. Adding one is writing a struct. Key paths deliberately stay one table for the config pass. Pure refactor: no golden moved.
Diffstat (limited to 'src/output_pane.zig')
-rw-r--r--src/output_pane.zig72
1 files changed, 72 insertions, 0 deletions
diff --git a/src/output_pane.zig b/src/output_pane.zig
new file mode 100644
index 00000000..4535495c
--- /dev/null
+++ b/src/output_pane.zig
@@ -0,0 +1,72 @@
+//! Output panes: acme's +Errors, a file pane with no file behind it, holding
+//! text the core produced itself (+Search results, +Help, the LSP answer
+//! buffers). The ONLY thing that makes one different from a file pane is that
+//! it cannot be saved — every mode, motion, chord and look works because it IS
+//! a file pane, and that reuse is the point.
+//!
+//! Thin on purpose, for now. The `f.output` tests still scattered through
+//! pardes.zig each ask a one-line question inside kind-agnostic code (does
+//! this pane claim a column? can it be saved? is it a doc?) and pulling them
+//! here would trade one line for a call. What belongs here is what an output
+//! pane KNOWS about itself, and today that is just how one is opened.
+const std = @import("std");
+const pardes = @import("pardes.zig");
+const Pardes = pardes.Pardes;
+const Pane = pardes.Pane;
+const file_pane = @import("file_pane.zig");
+
+/// `content` is gpa-owned and adopted. The name carries `dir` so looks inside
+/// the buffer resolve like anywhere else.
+pub fn open(p: *Pardes, id: usize, dir: []const u8, name: []const u8, content: []u8) !*Pane {
+ const path = try std.fmt.allocPrint(p.gpa, "{s}/{s}", .{ std.mem.trimEnd(u8, dir, "/"), name });
+ errdefer p.gpa.free(path);
+ const pane = try p.newDocPane(id);
+ pane.file = .{ .path = path, .content = content, .output = true };
+ pane.cur_pinned = true;
+ return pane;
+}
+
+/// 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.
+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;
+ } 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;
+ out.appendSlice(arena, row.line) catch return;
+ out.append(arena, '\n') catch return;
+ }
+ const content = p.gpa.dupe(u8, out.items) catch return;
+ for (p.panes, 0..) |slot, i| {
+ const hp = slot orelse continue;
+ const hf = if (hp.file) |*f| f else continue;
+ if (!hf.output or !std.mem.endsWith(u8, hf.path, "/+Help")) continue;
+ file_pane.setContent(p, hf, content);
+ hf.scroll = 0;
+ hp.cur_row = 0;
+ hp.msel.active = false;
+ p.active = i;
+ return;
+ }
+ const dir = if (pane.file) |f| (std.fs.path.dirname(f.path) orelse "/") else pane.cwdSlice();
+ const free = p.freeSlot() orelse {
+ p.gpa.free(content);
+ return;
+ };
+ const np = open(p, free, dir, "+Help", content) catch {
+ p.gpa.free(content);
+ return;
+ };
+ p.placeDoc(id, free, np);
+}