summaryrefslogtreecommitdiff
path: root/src/output_pane.zig
diff options
context:
space:
mode:
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);
+}