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