diff options
| -rw-r--r-- | src/builtins.zig | 6 | ||||
| -rw-r--r-- | src/exec.zig | 23 | ||||
| -rw-r--r-- | src/mouse.zig | 4 | ||||
| -rw-r--r-- | src/pardes.zig | 38 |
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); |
