summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/builtins.zig6
-rw-r--r--src/exec.zig23
-rw-r--r--src/mouse.zig4
-rw-r--r--src/pardes.zig38
4 files changed, 39 insertions, 32 deletions
diff --git a/src/builtins.zig b/src/builtins.zig
index a9bc38f9..557145cb 100644
--- a/src/builtins.zig
+++ b/src/builtins.zig
@@ -44,6 +44,10 @@ pub const Ctx = struct {
id: usize,
txt: []const u8,
arg: ?[]const u8,
+ /// Made by a gesture on the pane's body -- a middle click, the execute
+ /// key -- as acme's execute() asks of its Text (exec.c:122,169): an
+ /// Exec from a body may be a bound REPL's (exec.zig routeToRepl).
+ from_body: bool = false,
};
fn isEnabled(comptime T: type) bool {
@@ -397,7 +401,7 @@ pub const Exec = struct {
pub fn run(c: Ctx) void {
// the destination pane is Look's business (it focuses what answered);
// an execute deliberately leaves you where you were
- _ = exec.execute(c.p, c.id, c.arg orelse return);
+ _ = exec.executeFrom(c.p, c.id, c.arg orelse return, c.from_body);
}
};
diff --git a/src/exec.zig b/src/exec.zig
index 57eaad8f..dfef2dfd 100644
--- a/src/exec.zig
+++ b/src/exec.zig
@@ -69,7 +69,8 @@ pub fn chordEachSel(p: *Pardes, pane: *Pane, cmd: Builtin) bool {
var primary_active: ?usize = null;
for (texts[0..made], 0..) |txt, i| {
- runBuiltin(p, cmd, id, "", txt);
+ // Every selection is the body's, each one sent as the first is.
+ runBuiltinFrom(p, cmd, id, "", txt, true);
if (i == got.pri) primary_active = p.active;
const still = p.panes[id] orelse break;
if (still.serial != serial) break;
@@ -498,12 +499,15 @@ const max_exec_depth = 8;
/// child is `$SHELL -c` the line, which shows its output and `exit N` when
/// done, and which Kill signals. Answers the pane it went to.
pub fn execute(p: *Pardes, id: usize, txt: []const u8) ?usize {
+ return executeFrom(p, id, txt, false);
+}
+
+/// `execute` for text a gesture took from `id`'s body when `from_body`:
+/// such text may be a bound REPL's. Run by name (`Exec ...`, whose line
+/// comes back through `execute`) or written as a command word, never.
+pub fn executeFrom(p: *Pardes, id: usize, txt: []const u8, from_body: bool) ?usize {
const pane = p.panes[id] orelse return null;
- // Made by a gesture on a body, it may be a bound REPL's; run by name
- // (`Exec ...`, which runs through here again) or written in a command
- // word, it never is.
- const gesture = p.exec_from_body and config.commandWord(std.mem.trim(u8, txt, " \t\r\n")) == null;
- p.exec_from_body = false;
+ const gesture = from_body and config.commandWord(std.mem.trim(u8, txt, " \t\r\n")) == null;
const cmd = commandText(txt);
if (cmd.len == 0) return null;
if (p.exec_depth == 0) p.noteHaptic(.exec);
@@ -663,6 +667,11 @@ pub fn applyStartupConfig(p: *Pardes) void {
}
pub fn runBuiltin(p: *Pardes, b: Builtin, id: usize, txt: []const u8, arg: ?[]const u8) void {
+ runBuiltinFrom(p, b, id, txt, arg, false);
+}
+
+/// `runBuiltin` saying whether a gesture on the pane's body made it.
+pub fn runBuiltinFrom(p: *Pardes, b: Builtin, id: usize, txt: []const u8, arg: ?[]const u8, from_body: bool) void {
if (!normal.multiOnce(p)) return; // a builtin is per-keystroke, never per-cursor
const pane = p.panes[id] orelse return;
// A builtin says its own name before it runs, so a tagline click is
@@ -672,7 +681,7 @@ pub fn runBuiltin(p: *Pardes, b: Builtin, id: usize, txt: []const u8, arg: ?[]co
p.setMessage(id, @tagName(b));
pane.msg_announcement = true;
}
- const c: builtins.Ctx = .{ .p = p, .pane = pane, .id = id, .txt = txt, .arg = arg };
+ const c: builtins.Ctx = .{ .p = p, .pane = pane, .id = id, .txt = txt, .arg = arg, .from_body = from_body };
builtins.registry.dispatch(b, c);
}
diff --git a/src/mouse.zig b/src/mouse.zig
index f222b5da..1cfe6dbb 100644
--- a/src/mouse.zig
+++ b/src/mouse.zig
@@ -720,9 +720,7 @@ fn dispatchPointerBuiltin(
const operand = text orelse return;
if (gesture) |g| if (reportGesture(p, id, cmd, operand, g.on_tag, g.operand, arg != null)) return;
// A middle click on a body is the exec a bound REPL may take.
- p.exec_from_body = cmd == config.exec_cmd and gesture != null and !gesture.?.on_tag;
- defer p.exec_from_body = false;
- exec.runBuiltin(p, cmd, id, "", exec.withArg(p, operand, arg));
+ exec.runBuiltinFrom(p, cmd, id, "", exec.withArg(p, operand, arg), gesture != null and !gesture.?.on_tag);
}
fn mirrorTtySelection(p: *Pardes, pane: *Pane) void {
diff --git a/src/pardes.zig b/src/pardes.zig
index 12de47fa..872ea171 100644
--- a/src/pardes.zig
+++ b/src/pardes.zig
@@ -1465,16 +1465,22 @@ test "a REPL bound for a language takes the exec made on a body in it; tags, Exe
Sent.drain(p);
// A click on the file's body, a single word: typed into the REPL.
- p.exec_from_body = true;
- try std.testing.expectEqual(@as(?usize, 1), exec.execute(p, 0, "ls"));
+ try std.testing.expectEqual(@as(?usize, 1), exec.executeFrom(p, 0, "ls", true));
Sent.drain(p);
try std.testing.expectEqualStrings("ls\r", Sent.said(1));
try std.testing.expect(!Sent.spawned);
try std.testing.expect(file.msg_sent);
try std.testing.expectEqualStrings("\u{2192} python-a", file.msg[0..file.msg_len]);
+ // Several selections executed at once: each is sent, not the first.
+ {
+ const text = try edit.flatSurface(p, &file.body);
+ file.body.setRanges(text, &.{ .{ .anchor = 0, .head = 8 }, .{ .anchor = 9, .head = 11 } }, &.{}, 0, true);
+ try std.testing.expect(exec.chordEachSel(p, file, .Exec));
+ Sent.drain(p);
+ try std.testing.expectEqualStrings("print(1)\rls\r", Sent.said(1));
+ }
// Its own body too.
- p.exec_from_body = true;
- try std.testing.expectEqual(@as(?usize, 1), exec.execute(p, 1, "x = 1"));
+ try std.testing.expectEqual(@as(?usize, 1), exec.executeFrom(p, 1, "x = 1", true));
Sent.drain(p);
try std.testing.expectEqualStrings("x = 1\r", Sent.said(1));
@@ -1485,8 +1491,7 @@ test "a REPL bound for a language takes the exec made on a body in it; tags, Exe
try std.testing.expect(p.executeBuiltinLine(0, "Exec ls"));
Sent.drain(p);
try std.testing.expect(Sent.spawned and Sent.len[1] == 0);
- p.exec_from_body = true;
- _ = exec.execute(p, 0, "@`ls`");
+ _ = exec.executeFrom(p, 0, "@`ls`", true);
Sent.drain(p);
try std.testing.expect(Sent.spawned and Sent.len[1] == 0);
@@ -1494,16 +1499,14 @@ test "a REPL bound for a language takes the exec made on a body in it; tags, Exe
try std.testing.expect(p.executeBuiltinLine(2, "Repl python"));
try std.testing.expectEqualStrings("python-b", exec.replId(&idbuf, p.panes[2].?));
Sent.drain(p);
- p.exec_from_body = true;
- try std.testing.expectEqual(@as(?usize, null), exec.execute(p, 0, "print(2)"));
+ try std.testing.expectEqual(@as(?usize, null), exec.executeFrom(p, 0, "print(2)", true));
try std.testing.expectEqual(Pane.Prompt.repl_choice, file.prompt);
try std.testing.expect(std.mem.indexOf(u8, file.promptText().?, "a b") != null);
p.update(.{ .key = .{ .cp = 'b' } });
Sent.drain(p);
try std.testing.expectEqualStrings("print(2)\r", Sent.said(2));
try std.testing.expect(Sent.len[1] == 0 and file.prompt == .none);
- p.exec_from_body = true;
- _ = exec.execute(p, 0, "print(3)");
+ _ = exec.executeFrom(p, 0, "print(3)", true);
p.update(.{ .key = .{ .cp = Key.escape } });
Sent.drain(p);
try std.testing.expect(Sent.len[1] == 0 and Sent.len[2] == 0);
@@ -1512,8 +1515,7 @@ test "a REPL bound for a language takes the exec made on a body in it; tags, Exe
// sent nothing, and nothing runs: it says so.
host.taken[1] = false;
host.taken[2] = false;
- p.exec_from_body = true;
- _ = exec.execute(p, 0, "import os");
+ _ = exec.executeFrom(p, 0, "import os", true);
Sent.drain(p);
try std.testing.expect(Sent.len[1] == 0 and Sent.len[2] == 0 and !Sent.spawned);
try std.testing.expect(std.mem.indexOf(u8, file.msg[0..file.msg_len], "no program running") != null);
@@ -4121,10 +4123,6 @@ pub const Pardes = struct {
chord_arg: ?[]u8 = null,
/// how many `execute` calls are on the stack — see max_exec_depth
exec_depth: u8 = 0,
- /// The exec under way was made by a gesture on a pane's body -- a
- /// middle click, the execute key -- and so may go to a REPL bound for
- /// the text's language; one run by name, `Exec ...`, never does.
- exec_from_body: bool = false,
/// An exec waiting on the REPL question (`Pane.Prompt.repl_choice`):
/// the pane it came from, the language, and the text, owned.
repl_ask: ?struct { from: u32, lang: u8, text: []u8 } = null,
@@ -5380,9 +5378,6 @@ pub const Pardes = struct {
return;
}
edit.pinPaneCursor(p, &pane.body);
- // The execute key on a body is the exec a bound REPL may take.
- p.exec_from_body = cmd == config.exec_cmd;
- defer p.exec_from_body = false;
const explicit = (p.native_images and pane.hasPdfSelection()) or
(pane.body.vsel.active and pane.body.vsel.explicit) or pane.body.msel.active;
if (explicit) {
@@ -5391,13 +5386,14 @@ pub const Pardes = struct {
pane.body.vsel.active = false;
pane.body.msel.active = false;
pane.body.select = false;
- exec.runBuiltin(p, cmd, p.active, "", txt);
+ // The execute key on a body: text a bound REPL may take.
+ exec.runBuiltinFrom(p, cmd, p.active, "", txt, true);
return;
}
}
const sel = look.expandedSel(p, pane, look.cursorWordSel(p, pane)) orelse return;
const word = edit.selectionText(p, pane, sel) catch return;
- exec.runBuiltin(p, cmd, p.active, "", word);
+ exec.runBuiltinFrom(p, cmd, p.active, "", word, true);
return;
}
if (t.mode == .normal and t.what == .body and pane.hasPdf()) return normal.handlePdfNormal(p, pane, key);