summaryrefslogtreecommitdiff
path: root/src/config.zig
diff options
context:
space:
mode:
Diffstat (limited to 'src/config.zig')
-rw-r--r--src/config.zig122
1 files changed, 119 insertions, 3 deletions
diff --git a/src/config.zig b/src/config.zig
index e9595a2a..d6ea7358 100644
--- a/src/config.zig
+++ b/src/config.zig
@@ -58,6 +58,11 @@ pub const leader_path = paths: {
.Repl = null,
.Kill = null,
.Exit = "q",
+ .Get = null,
+ .Putall = null,
+ .Incl = null,
+ .Tab = null,
+ .Zerox = null,
.ClipYank = "y",
.ClipYankMain = "Y",
.ClipPaste = "p",
@@ -81,9 +86,11 @@ pub const leader_path = paths: {
.Placement = "cp",
.BootShell = null,
.LookWord = null,
+ .DirLook = null,
.Pager = null,
.PagerColor = null,
.TermImages = null,
+ .JumpScope = null,
.Debug = "td",
.Msg = null,
.Colors = "tc",
@@ -296,6 +303,8 @@ pub const pdf_pane_builtins_str = "Tty PdfSections PdfTint Collapse Del";
pub const file_pane_builtins_str = "Save Tty Collapse Del";
pub const terminal_pane_builtins_str = "Tty Save Mode Filter Collapse Del";
pub const command_pane_builtins_str = "Kill Save Collapse Del";
+/// A directory pane's (Dir.zig): Get reads it again, as acme's does.
+pub const dir_pane_builtins_str = "Get Tty Collapse Del";
// Each mode badge is one codepoint.
pub const tag_normal = " ";
@@ -394,7 +403,15 @@ pub fn defaultShell() []const u8 {
// Minimum file gutter width, including the space after the line number.
pub const PREFIX_W: u16 = 5;
+/// acme's Incl's C defaults: where a look at `stdio.h` finds it.
+pub const default_incl = [_][]const u8{ "/usr/include", "/usr/local/include" };
+
pub const tab_width: u16 = 4;
+/// The width a tab is drawn and counted at now: `Tab N` (Runtime.tab) sets
+/// it, a new session starts it at tab_width. ponytail: one for the process,
+/// as the session's setting is one; per pane would mean handing a pane to
+/// every width function (File.graphemeDisplayWidth and its ~130 callers).
+pub var tab_now: u16 = tab_width;
comptime {
if (tab_width == 0) @compileError("config.tab_width must be greater than zero");
}
@@ -774,6 +791,9 @@ pub const Runtime = struct {
/// next place in that pane, wrapping; `list`, what pardes did before,
/// lists every place in a +Search pane (look.zig, lookWord).
look_word: LookWord = .search,
+ /// A directory looked at: `pane`, acme's, a pane listing it (Dir.zig);
+ /// `terminal`, what pardes did before, `ls` in a terminal there.
+ dir_look: DirLook = .pane,
/// What a terminal's shell pages through (host_io.ChildEnv): `pardes`,
/// PAGER and GIT_PAGER set to `pardes -`, a +Pager pane, where the
/// user's environment set neither; `off`, the environment as it is.
@@ -785,15 +805,24 @@ pub const Runtime = struct {
/// (yazi's previews): `real`, as pixels where the shell can, or
/// `petscii`, as glyph art. The Petscii builtin flips one pane.
term_images: TermImages = .real,
+ /// What Back and Forward keep to (Pardes.jumpBy): `file`, the places in
+ /// the focused pane's file first, other files only once those run out
+ /// that way; `all`, every place in the order it was jumped to.
+ jump_scope: JumpScope = .file,
+ /// acme's Tab: a tab's width in cells, in every pane (config.tab_now
+ /// is what the drawing and the column arithmetic read).
+ tab: u16 = tab_width,
pub const ShaderAnimation = enum { off, on, always };
pub const Placement = enum { acme, pardes };
pub const BootShell = enum { keep, replace };
pub const LookWord = enum { search, list };
+ pub const DirLook = enum { pane, terminal };
pub const Pager = enum { pardes, off };
pub const TermImages = enum { real, petscii };
+ pub const JumpScope = enum { file, all };
/// A setting that is one of a few words, each an enum field of Runtime.
- pub const Choice = enum { placement, boot_shell, look_word, pager, term_images };
+ pub const Choice = enum { placement, boot_shell, look_word, dir_look, pager, term_images, jump_scope };
/// shadow: a soft drop shadow. rim: a light hairline along the top of
/// the focused pane's tag rows. auto: a shadow on a light page; on a
@@ -980,6 +1009,7 @@ pub const Runtime = struct {
/// A percentage, 0 through 100.
inactive_dim,
grip_width,
+ tab,
transition: animation.Transition,
scene: Scene,
/// A Shadertoy file into the post chain or out of it; `off` empties
@@ -1058,9 +1088,12 @@ pub const Runtime = struct {
.{ .word = "Placement", .action = .{ .choice = .placement }, .doc = "Where a new pane goes: acme, as makenewwindow does, or pardes, the older rules." },
.{ .word = "BootShell", .action = .{ .choice = .boot_shell }, .doc = "A document dropped where a lone untouched shell stands: keep the shell, or replace it." },
.{ .word = "LookWord", .action = .{ .choice = .look_word }, .doc = "A plain word looked at: search selects its next place in the pane, list lists every place in a +Search." },
+ .{ .word = "DirLook", .action = .{ .choice = .dir_look }, .doc = "A directory looked at: pane, a pane listing it as acme's directory window, or terminal, ls in a terminal there." },
.{ .word = "Pager", .action = .{ .choice = .pager }, .doc = "What a terminal's commands page through: pardes, a +Pager pane (pardes -), or off, the environment's own; for terminals started after it." },
.{ .word = "PagerColor", .action = .{ .toggle = .pager_color }, .doc = "A +Pager keeps its program's colours, on or off; for the next text paged." },
.{ .word = "TermImages", .action = .{ .choice = .term_images }, .doc = "How a new terminal draws its program's kitty graphics: real, as pixels where it can, or petscii, as glyph art." },
+ .{ .word = "JumpScope", .action = .{ .choice = .jump_scope }, .doc = "What Back and Forward keep to: file, the focused pane's file until it runs out that way, or all, every place in order." },
+ .{ .word = "Tab", .action = .tab, .doc = "A tab's width in cells, 1 through 16, in every pane; bare, it says the width." },
};
pub fn find(name: []const u8) ?Setting {
@@ -1261,6 +1294,12 @@ pub const Runtime = struct {
if (percent < 50 or percent > 300) return false;
state.grip_width = percent;
},
+ .tab => {
+ const text = std.mem.trim(u8, argument orelse return false, " \t\r\n");
+ const width = std.fmt.parseInt(u16, text, 10) catch return false;
+ if (width < 1 or width > 16) return false;
+ state.tab = width;
+ },
.theme, .font => return false,
}
return true;
@@ -1296,6 +1335,7 @@ pub const Runtime = struct {
return choices(action) orelse switch (action) {
.inactive_dim, .window_opacity, .window_blur => "0-100 (a percentage)",
.grip_width => "50-300 (a percentage)",
+ .tab => "1-16 (cells)",
.tagline_size => std.fmt.comptimePrint("{d}-{d} (a percentage)", .{ tagline_percent_min, tagline_percent_max }),
.message_ms => std.fmt.comptimePrint("0-{d} (milliseconds)", .{message_ms_max}),
.shell => "a path of at most 255 bytes; bare, $SHELL, else /bin/sh",
@@ -1458,6 +1498,7 @@ pub const Runtime = struct {
try out.print("# {s} unsupported\n", .{setting.word}),
.motion => try out.print("{s} {s}\n", .{ setting.word, @tagName(state.motion) }),
.inactive_dim => try out.print("{s} {d}\n", .{ setting.word, state.inactive_dim }),
+ .tab => try out.print("{s} {d}\n", .{ setting.word, state.tab }),
.grip_width => if (setting.enabled(context.capabilities))
try out.print("{s} {d}\n", .{ setting.word, state.grip_width })
else
@@ -1745,13 +1786,16 @@ pub const Runtime = struct {
.placement => "pardes",
.boot_shell => "replace",
.look_word => "list",
+ .dir_look => "terminal",
.pager => "off",
.term_images => "petscii",
+ .jump_scope => "all",
},
.lift => "rim",
.motion => "playful",
.inactive_dim => "35",
.grip_width => "200",
+ .tab => "8",
else => null,
};
try std.testing.expect(apply(&state, setting, argument));
@@ -1817,13 +1861,16 @@ pub const Runtime = struct {
.placement => "Placement pardes\n",
.boot_shell => "BootShell replace\n",
.look_word => "LookWord list\n",
+ .dir_look => "DirLook terminal\n",
.pager => "Pager off\n",
.term_images => "TermImages petscii\n",
+ .jump_scope => "JumpScope all\n",
},
.lift => "Lift rim\n",
.motion => "Motion playful\n",
.inactive_dim => "InactiveDim 35\n",
.grip_width => "GripWidth 200\n",
+ .tab => "Tab 8\n",
.theme, .font => unreachable,
};
try std.testing.expect(std.mem.indexOf(u8, report, expected) != null);
@@ -2101,9 +2148,16 @@ const doc_typ = struct {
}
}
+ /// The other build's builtins (docs/typ/builtins-*.json), so the docs
+ /// may name a window-only word in a terminal build's test, and back.
+ var other_build: []const u8 = "";
+
fn word(w: []const u8) bool {
const name = w[0 .. std.mem.indexOfScalar(u8, w, '+') orelse w.len];
- return std.meta.stringToEnum(Builtin, name) != null;
+ if (std.meta.stringToEnum(Builtin, name) != null) return true;
+ var buf: [96]u8 = undefined;
+ const needle = std.fmt.bufPrint(&buf, "{{\"name\": \"{s}\",", .{name}) catch return false;
+ return std.mem.indexOf(u8, other_build, needle) != null;
}
fn chord(tok: []const u8) ?Chord {
@@ -2181,7 +2235,7 @@ const doc_typ = struct {
if (w.end > 0) w.writeByte(' ') catch return false;
w.writeAll(x[0 .. std.mem.indexOfScalar(u8, x, '+') orelse x.len]) catch return false;
}
- const tags = [_][]const u8{ topbar_str, @import("tagline.zig").column_tag_default, pane_builtins_str, pdf_pane_builtins_str, file_pane_builtins_str, terminal_pane_builtins_str, command_pane_builtins_str };
+ const tags = [_][]const u8{ topbar_str, @import("tagline.zig").column_tag_default, pane_builtins_str, pdf_pane_builtins_str, file_pane_builtins_str, terminal_pane_builtins_str, command_pane_builtins_str, dir_pane_builtins_str };
for (tags) |d| if (std.mem.eql(u8, d, w.buffered())) return true;
return false;
}
@@ -2195,6 +2249,10 @@ test "docs/typ names only words, keys and default tags that exist" {
var dir = try std.Io.Dir.cwd().openDir(io, @import("doc_typ").dir, .{ .iterate = true });
defer dir.close(io);
var found: [3]std.ArrayList([]const u8) = @splat(.empty);
+ for ([_][]const u8{ "builtins-tty.json", "builtins-gui.json" }) |f| {
+ const text = dir.readFileAlloc(io, f, gpa, .limited(1 << 20)) catch continue;
+ doc_typ.other_build = try std.mem.concat(gpa, u8, &.{ doc_typ.other_build, text });
+ }
var it = dir.iterate();
while (try it.next(io)) |entry| if (entry.kind == .file and std.mem.endsWith(u8, entry.name, ".typ")) {
const source = try dir.readFileAlloc(io, entry.name, gpa, .limited(1 << 20));
@@ -2331,3 +2389,61 @@ test "the tutor names only words, keys, paths and default tags that exist" {
}
}
}
+
+test "reference.typ's #fstree is the tree the session serves, file for file" {
+ const tree = @import("ninep/tree.zig");
+ var arena: std.heap.ArenaAllocator = .init(std.testing.allocator);
+ defer arena.deinit();
+ const gpa = arena.allocator();
+ const io = std.testing.io;
+ var dir = try std.Io.Dir.cwd().openDir(io, @import("doc_typ").dir, .{});
+ defer dir.close(io);
+ const source = try dir.readFileAlloc(io, "reference.typ", gpa, .limited(1 << 20));
+ const open = "#fstree(```";
+ const start = (std.mem.indexOf(u8, source, open) orelse return error.NoFsTree) + open.len;
+ const end = std.mem.indexOfPos(u8, source, start, "```)") orelse return error.NoFsTree;
+
+ // what the reference draws: a path per line, from its indent
+ var drawn: std.StringArrayHashMapUnmanaged(void) = .empty;
+ var stack: [8][]const u8 = undefined;
+ var lines = std.mem.tokenizeScalar(u8, source[start..end], '\n');
+ while (lines.next()) |line| {
+ const body = std.mem.trimStart(u8, line, " ");
+ if (body.len == 0) continue;
+ const depth = (line.len - body.len) / 2;
+ const name = body[0 .. std.mem.indexOfScalar(u8, body, ' ') orelse body.len];
+ stack[depth] = name;
+ var path: std.ArrayList(u8) = .empty;
+ for (stack[0 .. depth + 1]) |part| try path.appendSlice(gpa, part);
+ try drawn.put(gpa, path.items, {});
+ }
+
+ // what the session serves: tree.zig's files, and fs.zig's os/ and src/
+ var served: std.StringArrayHashMapUnmanaged(void) = .empty;
+ for (std.enums.values(tree.TopFile)) |f| switch (f) {
+ .root => {},
+ .new => try served.put(gpa, "pane/new", {}),
+ else => try served.put(gpa, if (f.dir()) try std.fmt.allocPrint(gpa, "{s}/", .{f.fileName()}) else f.fileName(), {}),
+ };
+ try served.put(gpa, "os/", {});
+ try served.put(gpa, "src/", {});
+ try served.put(gpa, "pane/<n>/", {});
+ for (std.enums.values(tree.PaneFile)) |f| if (f != .dir) {
+ const under = if (f.inPty() and f != .pty) "pane/<n>/pty/" else "pane/<n>/";
+ try served.put(gpa, try std.fmt.allocPrint(gpa, "{s}{s}{s}", .{ under, f.fileName(), if (f.isDir()) "/" else "" }), {});
+ };
+ try served.put(gpa, "col/<n>/", {});
+ for (std.enums.values(tree.ColFile)) |f| if (f != .dir)
+ try served.put(gpa, try std.fmt.allocPrint(gpa, "col/<n>/{s}", .{f.fileName()}), {});
+
+ var drift = false;
+ for (served.keys()) |k| if (!drawn.contains(k)) {
+ std.debug.print("reference.typ's tree lacks {s}\n", .{k});
+ drift = true;
+ };
+ for (drawn.keys()) |k| if (!served.contains(k)) {
+ std.debug.print("reference.typ's tree has {s}, which the session does not serve\n", .{k});
+ drift = true;
+ };
+ if (drift) return error.FsTreeDrift;
+}