summaryrefslogtreecommitdiff
path: root/src/builtins.zig
diff options
context:
space:
mode:
Diffstat (limited to 'src/builtins.zig')
-rw-r--r--src/builtins.zig55
1 files changed, 55 insertions, 0 deletions
diff --git a/src/builtins.zig b/src/builtins.zig
index 5273cf37..be0956e0 100644
--- a/src/builtins.zig
+++ b/src/builtins.zig
@@ -852,6 +852,61 @@ pub const Tty9p = struct {
/// Fold the active pane's column into the one on its right, keeping its panes.
/// The horizontal mirror of the vertical stacking `New` does.
+/// Binds this terminal as a language's REPL, by the language's name as the
+/// syntax table has it: an exec made on the body of a file in that
+/// language -- a middle click, the execute key, a single word like `ls`
+/// as much as a selection -- and one made on this terminal's own body, is
+/// typed into it (bracketed paste if its program asked for that, else line
+/// by line, then Enter) instead of run. `Repl python` binds (again, it is
+/// already); `Repl -` unbinds; `Repl` bare says what it is bound as. With
+/// several bound for a language, the exec asks which.
+/// Still commands, whatever is bound: a word in a tag, `Exec <text>` run by
+/// name (typed, a 2-1 chord onto Exec, a ctl line), and a command word
+/// @`cmd` in the text, looked at or clicked.
+pub const Repl = struct {
+ pub const takes_arg = true;
+ pub fn run(c: Ctx) void {
+ const pane = c.pane;
+ if (!pane.isTerminal()) return c.p.reportFailure(c.id, "Repl: only a terminal is a REPL");
+ const arg = std.mem.trim(u8, c.arg orelse "", " \t\r\n");
+ var buf: [320]u8 = undefined;
+ var idbuf: [48]u8 = undefined;
+ if (arg.len == 0) {
+ if (pane.repl == null) return c.p.setMessage(c.id, "Repl: not bound");
+ return c.p.setMessage(c.id, std.fmt.bufPrint(&buf, "Repl: {s}", .{exec.replId(&idbuf, pane)}) catch "Repl");
+ }
+ if (std.mem.eql(u8, arg, "-")) {
+ pane.repl = null;
+ return c.p.setMessage(c.id, "Repl: unbound");
+ }
+ const grammars = @import("grammar_manifest.zig").all;
+ const lang: u8 = for (grammars, 0..) |g, i| {
+ if (g.exts.len > 0 and std.mem.eql(u8, g.name, arg)) break @intCast(i);
+ } else {
+ var w = std.Io.Writer.fixed(&buf);
+ w.print("Repl: no language \"{s}\"; one of", .{arg[0..@min(arg.len, 32)]}) catch {};
+ for (grammars) |g| if (g.exts.len > 0) w.print(" {s}", .{g.name}) catch break;
+ return c.p.reportFailure(c.id, w.buffered());
+ };
+ if (pane.repl) |r| if (r.lang == lang)
+ return c.p.setMessage(c.id, std.fmt.bufPrint(&buf, "Repl: {s}", .{exec.replId(&idbuf, pane)}) catch "Repl");
+ // The lowest letter no other REPL of the language has: freed ones
+ // come back.
+ var letter: u8 = 'a';
+ while (letter <= 'z') : (letter += 1) {
+ const taken = for (c.p.panes) |slot| {
+ const other = slot orelse continue;
+ if (other != pane) if (other.repl) |r| if (r.lang == lang and r.letter == letter) break true;
+ } else false;
+ if (!taken) break;
+ }
+ if (letter > 'z') return c.p.reportFailure(c.id, "Repl: every letter of the language is taken");
+ pane.repl = .{ .lang = lang, .letter = letter };
+ pane.repl_warned = false;
+ c.p.setMessage(c.id, std.fmt.bufPrint(&buf, "Repl: {s}", .{exec.replId(&idbuf, pane)}) catch "Repl");
+ }
+};
+
pub const Joincol = struct {
pub const scope: Scope = .session;
pub fn run(c: Ctx) void {