diff options
Diffstat (limited to 'src/config.zig')
| -rw-r--r-- | src/config.zig | 62 |
1 files changed, 58 insertions, 4 deletions
diff --git a/src/config.zig b/src/config.zig index 65ac397b..394f9ca3 100644 --- a/src/config.zig +++ b/src/config.zig @@ -59,10 +59,16 @@ pub const leader: []const Chord = &.{.{ .cp = ' ' }}; pub const leader_help: u8 = '?'; /// SPC leader: ONE key path per builtin, the whole remapping surface. An -/// EnumArray, so a new enum field is a compile error until it has a path. -/// Groups are just shared first letters (f files, h docs, c columns, t -/// toggles, s session, l language, w windows). -pub const leader_path = std.EnumArray(Builtin, []const u8).init(.{ +/// EnumArray, so a new enum field is a compile error until someone has DECIDED +/// its path. Groups are just shared first letters (f files, h docs, c columns, +/// t toggles, s session, l language, w windows). +/// +/// `null` = this builtin's shortcut is not a leader path. Look and Exec are +/// the two: their shortcuts are Enter/Tab and the two mouse buttons below, and +/// a third spelling under SPC would be a key that does nothing you cannot +/// already do with the key your hand is on. The option is the honest type — +/// "every builtin has a leader path" was only ever true by accident. +pub const leader_path = std.EnumArray(Builtin, ?[]const u8).init(.{ .Help = &[_]u8{leader_help}, // The whole LANGUAGE group lives under `l`, and pardes's own builtins keep // the letters they always had — `SPC d` is Del, `SPC k` is Kill. @@ -117,6 +123,9 @@ pub const leader_path = std.EnumArray(Builtin, []const u8).init(.{ .Up = "wk", .Right = "wl", .Toggleterm = "wt", + // the two acme verbs: keys and buttons, no leader path — see above + .Look = null, + .Exec = null, }); // ---- the acme chords ---- @@ -134,6 +143,15 @@ pub const exec_button: Mouse.Button = .middle; /// sweep, focus, place the cursor, and the left half of every acme chord pub const select_button: Mouse.Button = .left; +/// ...and WHAT those four run. Look and Exec are ORDINARY builtins — the same +/// kind of thing Save and Grep are, executable by name wherever text lives +/// (`Look main.zig` in a tag does what a right click on `main.zig` does) — so +/// the four bindings above are bindings like any other, and these two lines +/// are the whole of what makes them special. Point `look_cmd` at `.Grep` and +/// Enter greps. +pub const look_cmd: Builtin = .Look; +pub const exec_cmd: Builtin = .Exec; + // ---- windows ---- /// helix's window prefix. It stays despite `SPC w` covering the same four @@ -278,6 +296,42 @@ pub fn isFileChar(c: u8) bool { }; } +/// `` @`ls -la` `` — a word that names a COMMAND to run rather than a file to +/// open. Both halves are named here because they are a CHOICE: the `@` marks +/// it as ours (it is already a file char, so it can never split a path) and +/// the backquotes hold a command line with spaces in it, which is the whole +/// point — a file-ish word cannot. Respell them here and nowhere else. +pub const cmd_open = "@`"; +pub const cmd_close: u8 = '`'; + +/// The command inside `` @`...` ``, or null when `w` is not one. +pub fn commandWord(w: []const u8) ?[]const u8 { + if (w.len <= cmd_open.len or !std.mem.startsWith(u8, w, cmd_open)) return null; + if (w[w.len - 1] != cmd_close) return null; + return w[cmd_open.len .. w.len - 1]; +} + +/// The bounds of the word at `col` in `line` — THE expansion a no-drag +/// look/execute click and the tag chord both use. +/// +/// A `` @`...` `` run is taken WHOLE and wins outright: a backtick is not a +/// file char, so the plain scan below would stop dead inside one and hand a +/// look the fragment `ls` out of `` @`ls -la` ``. Acme does exactly this for +/// its own `<`/`|`/`>` command words. Otherwise it is the file-ish word. +pub fn wordBounds(line: []const u8, col: usize) struct { lo: usize, hi: usize } { + var i: usize = 0; + while (std.mem.indexOfPos(u8, line, i, cmd_open)) |o| { + const close = std.mem.indexOfScalarPos(u8, line, o + cmd_open.len, cmd_close) orelse break; + if (col >= o and col <= close) return .{ .lo = o, .hi = close + 1 }; + i = close + 1; + } + var lo = col; + while (lo > 0 and isFileChar(line[lo - 1])) lo -= 1; + var hi = col; + while (hi < line.len and isFileChar(line[hi])) hi += 1; + return .{ .lo = lo, .hi = hi }; +} + /// separates a path from its LINE and COL: `main.zig:100:7`. Must be a member /// of isFileChar or the suffix would not be part of the word in the first /// place. |
