diff options
Diffstat (limited to 'src/output_pane.zig')
| -rw-r--r-- | src/output_pane.zig | 72 |
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); +} |
