diff options
Diffstat (limited to 'src/output_pane.zig')
| -rw-r--r-- | src/output_pane.zig | 61 |
1 files changed, 48 insertions, 13 deletions
diff --git a/src/output_pane.zig b/src/output_pane.zig index 8c93709c..8ff98845 100644 --- a/src/output_pane.zig +++ b/src/output_pane.zig @@ -27,7 +27,7 @@ const config = @import("config.zig"); const lsp = @import("lsp/lsp.zig"); /// the installed fonts, for openFonts. GUI only, behind the same comptime /// branch builtins.zig imports it through — see the note there. -const fonts = if (pardes.platform == .gui) @import("gui/fonts.zig") else struct {}; +const fonts = if (pardes.font_picker) @import("fonts.zig") else struct {}; /// What opened this buffer — THE field, and the only input to `traits`. /// @@ -385,12 +385,13 @@ pub fn openThemes(p: *Pardes, id: usize) !void { /// stopping picks one. Everything that makes that work is already above; this /// is the same eight lines pointed at a different list. /// -/// GUI only, and the body says so rather than the signature: fonts.list and -/// the FontSel origin both exist only there, and a comptime-false `if` is what -/// keeps the tty build from analysing either. The dead parameters on that -/// build are the honest shape of "this platform cannot open one". +/// Only where the shell draws its own text, and the body says so rather than +/// the signature: fonts.list and the FontSel origin both exist only there, and +/// a comptime-false `if` is what keeps the tty build from analysing either. +/// The dead parameters on that build are the honest shape of "this platform +/// cannot open one". pub fn openFonts(p: *Pardes, id: usize) !void { - if (pardes.platform == .gui) { + if (pardes.font_picker) { const arena = p.scratch.allocator(); const font_list = fonts.list(arena, null); var len: usize = 0; @@ -437,7 +438,6 @@ fn openStepped(p: *Pardes, id: usize, from: Origin, text: []const u8) !void { /// 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 error.MissingPane; const full_header = "pardes builtins, and how to run each:\nSPC and its keys, a chord, a button, the\ntopbar - or the name, executed anywhere.\n\n"; const group_header = "pardes builtins under SPC"; var len: usize = if (prefix.len == 0) @@ -451,7 +451,6 @@ pub fn openHelp(p: *Pardes, id: usize, prefix: []const u8) !void { len += row.line.len + 1; } const content = try p.gpa.alloc(u8, len); - errdefer p.gpa.free(content); var at: usize = 0; if (prefix.len == 0) { @memcpy(content[0..full_header.len], full_header); @@ -476,15 +475,51 @@ pub fn openHelp(p: *Pardes, id: usize, prefix: []const u8) !void { at += 1; } std.debug.assert(at == content.len); - // the buffer says what made it, so finding the open one is asking that and - // not matching its name + // content is handed off unfreed on purpose: openRead adopts it or frees + // it, and nothing between the alloc above and this line can fail. + return openRead(p, id, .{ .cmd = .Help }, prefix, content); +} + +/// The Config builtin: WHERE the startup config file is, as one line of text. +/// +/// The PATH and not the file. `Look` on the line opens it when it exists, and +/// when it does not the path is still the entire answer — "put your Theme and +/// Font lines HERE" is the question this is asked, and a builtin that opened +/// an empty buffer instead would have said nothing. The core never resolved +/// it: the launcher did, before init (Options.startup_config_path), so this +/// prints what was actually consulted rather than recomputing a guess that +/// could differ from it. +pub fn openConfig(p: *Pardes, id: usize) !void { + const content = if (p.opts.startup_config_path) |path| + try std.fmt.allocPrint(p.gpa, "{s}\n", .{path}) + else + // the browser, and a native launch with no HOME to build one from + try p.gpa.dupe(u8, "no per-user config path\n"); + return openRead(p, id, .{ .cmd = .Config }, "", content); +} + +/// Open a buffer you READ, and go there: the shared tail of every builtin +/// whose answer is a document rather than a list. Asking again REFRESHES the +/// one already open instead of stacking a twin beside it — found by its +/// ORIGIN, never by matching its name, for the reason the whole file exists. +/// +/// The mirror of `openStepped`, and the difference is the two lines at the +/// ends: focus comes HERE (you asked to read it) where a results buffer +/// leaves you in the pane that asked, and n/N are not armed, because prose +/// has nowhere to step to. +/// +/// `content` is gpa-owned: adopted by the buffer, or freed here when there is +/// nowhere to put it. +fn openRead(p: *Pardes, id: usize, from: Origin, arg: []const u8, content: []u8) !void { + errdefer p.gpa.free(content); + const pane = p.panes[id] orelse return error.MissingPane; for (p.panes, 0..) |slot, i| { const hp = slot orelse continue; const hf = if (hp.file) |*f| f else continue; const ho = if (hf.output) |*o| o else continue; - if (!std.meta.eql(ho.from, Origin{ .cmd = .Help })) continue; + if (!std.meta.eql(ho.from, from)) continue; file_pane.setContent(p, hf, content); - setArg(ho, prefix); + setArg(ho, arg); hf.scroll = 0; hp.cur_row = 0; hp.msel.active = false; @@ -493,7 +528,7 @@ pub fn openHelp(p: *Pardes, id: usize, prefix: []const u8) !void { } const dir = if (pane.file) |f| (std.fs.path.dirname(f.path) orelse "/") else pane.cwdSlice(); const free = p.freeSlot() orelse return error.NoPaneSlots; - const np = try open(p, free, dir, .{ .cmd = .Help }, prefix, content); + const np = try open(p, free, dir, from, arg, content); p.placeDoc(id, free, np); p.active = free; } |
