diff options
| author | Gabriel Schneider <[email protected]> | 2026-09-30 20:57:49 -0300 |
|---|---|---|
| committer | Gabriel Schneider <[email protected]> | 2026-10-01 00:12:17 -0300 |
| commit | 6a815117d242688c947a1788e4ffda9ff2bce959 (patch) | |
| tree | 311853ee7195e7b1cbd32cf130ec0f3458f72b2c | |
| parent | c2a1b54651be6b2532d48825d913b747a0edbea8 (diff) | |
| download | pardes-6a815117d242688c947a1788e4ffda9ff2bce959.tar.gz pardes-6a815117d242688c947a1788e4ffda9ff2bce959.zip | |
A shell command from the workspace's or a column's tag runs as a command pane in the session's directory, never typed into the terminal with the keyboard
A command clicked in a header tag, or written to /tagexec or a
column's exec, was typed into the active terminal when it sat at an
empty prompt, so it ran in that pane's directory and left no run or
exit record. It now always gets a command pane of its own in the
session's directory, as acme's row and column tags have no directory
but the session's. tags.md writes the rule down: pane words act on the
column's active pane, a column's words on the column, shell commands
as their own panes, and over 9P a pane's word is refused.
Co-Authored-By: Claude Opus 5.5 <[email protected]>
| -rw-r--r-- | docs/tags.md | 23 | ||||
| -rw-r--r-- | src/exec.zig | 7 | ||||
| -rw-r--r-- | src/ninep/cols.zig | 21 | ||||
| -rw-r--r-- | test/snapshots/headersweep-restored.golden | 23 | ||||
| -rw-r--r-- | test/snapshots/headersweep.golden | 39 |
5 files changed, 78 insertions, 35 deletions
diff --git a/docs/tags.md b/docs/tags.md index eb16cb2a..81ae99a7 100644 --- a/docs/tags.md +++ b/docs/tags.md @@ -1,12 +1,23 @@ # Tags and columns Pardes has three levels of command text: the workspace tag, a tag per -column, and each pane's tag. A column tag's words act on that column and run -in its active pane (its first pane when focus comes from another column). A -command or `Tty` run from the workspace or a column tag starts in the -session's directory (where pardes started), as acme's row and column tags -have none of their own; one run from a pane's tag or text starts in that -pane's directory. Over 9P the tags are `/tag`, `/col/<n>/tag` and +column, and each pane's tag. The rule for the workspace and column tags: + +- A builtin that acts on a pane (`Del`, `Save`, `Undo`) acts on the + column's active pane (its first pane when focus comes from another + column); from the workspace tag, on the pane with the keyboard. +- A column's own words (`New`, `Tty`, `Delcol`) act on that column. +- A shell command runs as a command pane of its own, with `run` and `exit` + records, in the session's directory (where pardes started), as acme's row + and column tags have none of their own. It is never typed into the + terminal that has the keyboard. `Tty` starts there too. +- Over 9P (`/tagexec`, `col/<n>/exec`) there is no click to say which pane + is meant, so a pane's word written there is refused, pointing at + `pane/<n>/ctl`; the tag's own words and shell commands run as above. + +One run from a pane's tag or text starts in that pane's directory, and a +shell command there is typed into the pane when it is a terminal at its +prompt. Over 9P the tags are `/tag`, `/col/<n>/tag` and `/pane/<n>/tag` ([fs.md](fs.md#columns-and-tags)). ## Default words diff --git a/src/exec.zig b/src/exec.zig index ea20f969..2b3ca40c 100644 --- a/src/exec.zig +++ b/src/exec.zig @@ -728,7 +728,10 @@ pub fn executeFrom(p: *Pardes, id: usize, txt: []const u8, from_body: bool) ?usi p.reportFailure(id, std.fmt.bufPrint(&said, "{s} is {s}, invalid here", .{ word, why }) catch "GUI-only, invalid here"); return null; } - if (!takesCommandLine(p, id)) return runCommand(p, id, cmd); + // A command from a column's or the workspace's tag is that tag's: a + // command pane in the session's directory, never typed into whichever + // terminal has the keyboard. + if (p.exec_header or !takesCommandLine(p, id)) return runCommand(p, id, cmd); panes.terminal.padOutputBelowEdits(p, id); panes.terminal.noteCommand(pane, cmd); if (panes.terminal.queuePendingCommand(pane, cmd) catch |err| { @@ -771,7 +774,7 @@ fn runCommand(p: *Pardes, from: usize, line: []const u8) ?usize { // would hang that job up. // From a column's tag, only a finished pane in that column is reused, // as the new one goes in that column (placeNew). - const reuse: ?usize = if (p.exec_column == null and src != null and src.?.command != null and src.?.command_done and !src.?.command_pty) from else for (p.panes, 0..) |slot, i| { + const reuse: ?usize = if (!p.exec_header and p.exec_column == null and src != null and src.?.command != null and src.?.command_done and !src.?.command_pty) from else for (p.panes, 0..) |slot, i| { const other = slot orelse continue; if (p.exec_column) |c| if (if (layout.findPane(p, i)) |f| f.col != c else true) continue; if (other.command != null and other.command_done and !other.command_pty and std.mem.eql(u8, other.cwdSlice(), dir)) break i; diff --git a/src/ninep/cols.zig b/src/ninep/cols.zig index 7afcfbd8..6828612c 100644 --- a/src/ninep/cols.zig +++ b/src/ninep/cols.zig @@ -426,6 +426,27 @@ test "Help and Find at /tagexec act in the session's directory, not the keyboard } } +test "a shell command at /tagexec or a column's exec is a command pane in the session's directory, never typed into the keyboard's terminal" { + if (comptime !pardes.hosted) return; + const p = try Pardes.init(testing.allocator, .{ .tty_only = true, .cols = 80, .rows = 30 }); + defer p.deinit(); + while (p.nextEffect()) |_| {} + const term = p.panes[p.active].?; + try testing.expect(pardes.exec.takesCommandLine(p, p.active)); + const col_exec = tree.Node.ofCol(layout.columnSerial(p, 0), .exec); + for ([_]u64{ @intFromEnum(tree.TopFile.tagexec), col_exec }) |node| { + p.active = p.paneBySerial(term.serial).?; + const before = p.next_serial; + const r = th.wr(p, node, "echo from-the-tag\n"); + try testing.expectEqual(tree.Status.ok, r.reply.status); + try testing.expectEqualStrings("", r.pty()); + try testing.expectEqual(before + 1, p.next_serial); + const made = p.panes[p.paneBySerial(p.next_serial).?].?; // the newest + try testing.expectEqualStrings("echo from-the-tag", made.command.?); + try testing.expectEqualStrings(p.sessionDir(), made.cwdSlice()); + } +} + test "New and Tty run at /tagexec and a column's exec, with no pane at all too" { const p = try th.withFile(testing.allocator, "x\n"); defer p.deinit(); diff --git a/test/snapshots/headersweep-restored.golden b/test/snapshots/headersweep-restored.golden index 38b505e7..176520dd 100644 --- a/test/snapshots/headersweep-restored.golden +++ b/test/snapshots/headersweep-restored.golden @@ -20,7 +20,7 @@ |18: 0-0 d,#608269, 1-59 d,#0d1410, 60-60 d,#608269, 61-119 d,#0d1410, |19: 0-0 d,#608269, 1-59 d,#0d1410, 60-60 d,#608269, 61-119 d,#0d1410, |20: 0-0 d,#608269, 1-59 d,#0d1410, 60-60 d,#608269, 61-119 d,#0d1410, -== snap col-swept grid=120x21 cursor=4,9 +== snap col-swept grid=120x21 cursor=4,7 |Newcol Joincol Find Grep Help Changelog Tutor Dump Themes Config Debug Exit Restore /tmp/pardes-snap/headersweep-restore | New Tty Find Grep Joincol Delcol echo RE''STORED-COL New Tty Find Grep Joincol Delcol | /tmp/pardes-snap/headersweep-restored/cwd Tty+bash Save M /tmp/pardes-snap/headersweep-restored/cwd Tty+bash Save M @@ -28,22 +28,27 @@ | $ ls $ ls | $ $ | ── restored history ── ── restored history ── -| echo RE''STORED-COL -| RESTORED-COL +| +| | | | | /tmp/pardes-snap/headersweep-restored/cwd Tty+bash Save M | ode Filter Collapse Del -| $ ls | $ | ── restored history ── +| +| /tmp/pardes-snap/headersweep-restored/cwd (echo RE''STORE +| D-COL) exit 0 Kill Save Collapse Del +| exit 0 == style ws-sweeping grid=120x21 |0: 0-100 #b2c3b8,#1d2824, 101-108 #f5f7ee,#5b7e5a, 109-119 #b2c3b8,#1d2824, |1: 0-1 d,#887455, 2-2 d,#314738, 3-59 #becfc4,#314738, 60-61 #becfc4,#887455, 62-62 #becfc4,#1d2824, 63-119 #b2c3b8,#1d2824, -|7: 0-0 d,#608269, 1-1 d,#0d1410, 2-59 #e5eee5,#0d1410, 60-60 #e5eee5,#608269, 61-119 #e5eee5,#0d1410, -|8: 0-0 d,#608269, 1-1 d,#0d1410, 2-59 #e5eee5,#0d1410, 60-60 #e5eee5,#608269, 61-119 #e5eee5,#0d1410, -== snap ws-swept grid=120x21 cursor=4,11 +|15: 0-0 d,#608269, 1-1 d,#0d1410, 2-23 #e5eee5,#0d1410,f 24-59 #e5eee5,#0d1410, 60-60 #e5eee5,#608269, 61-119 #e5eee5,#0d1410, +|16: 0-0 d,#152019, 1-59 d,#0d1410, 60-60 d,#608269, 61-119 d,#0d1410, +|17: 0-1 d,#496656, 2-2 d,#1d2824, 3-59 #b2c3b8,#1d2824, 60-60 #b2c3b8,#608269, 61-119 #b2c3b8,#0d1410, +|18: 0-2 d,#1d2824, 3-59 #b2c3b8,#1d2824, 60-60 #b2c3b8,#608269, 61-119 #b2c3b8,#0d1410, +|19: 0-0 d,#152019, 1-1 d,#0d1410, 2-59 #e5eee5,#0d1410, 60-60 #e5eee5,#608269, 61-119 #e5eee5,#0d1410, +== snap ws-swept grid=120x21 cursor=4,7 |0: Newcol Joincol Find Grep Help Changelog Tutor Dump Themes Config Debug Exit Restore /tmp/pardes-snap/headersweep-rest ec -|9: echo RE''STORED-WS -|10: RESTORED-WS +|18: D-WS) exit 0 Kill Save Collapse Del diff --git a/test/snapshots/headersweep.golden b/test/snapshots/headersweep.golden index 38004c08..c22120ca 100644 --- a/test/snapshots/headersweep.golden +++ b/test/snapshots/headersweep.golden @@ -20,15 +20,15 @@ |18: 0-0 d,#608269, 1-59 d,#0d1410, 60-60 d,#608269, 61-119 d,#0d1410, |19: 0-0 d,#608269, 1-59 d,#0d1410, 60-60 d,#608269, 61-119 d,#0d1410, |20: 0-0 d,#608269, 1-59 d,#0d1410, 60-60 d,#608269, 61-119 d,#0d1410, -== snap col-swept grid=120x21 cursor=4,8 +== snap col-swept grid=120x21 cursor=4,6 |Newcol Joincol Find Grep Help Changelog Tutor Dump Themes Config Debug Exit | New Tty Find Grep Joincol Delcol echo SW''EPT-COL New Tty Find Grep Joincol Delcol | /tmp/pardes-snap/headersweep/cwd Tty+bash Save Mode Filte /tmp/pardes-snap/headersweep/cwd Tty+bash Save Mode Filte | r Collapse Del r Collapse Del | ls ls | hay.txt hay.txt -| echo SW''EPT-COL -| SWEPT-COL +| +| | | | @@ -37,24 +37,27 @@ | r Collapse Del | ls | hay.txt -== snap ws-swept grid=120x21 cursor=4,10 +| +| /tmp/pardes-snap/headersweep/cwd (echo SW''EPT-COL) exit +| 0 Kill Save Collapse Del +| exit 0 +== snap ws-swept grid=120x21 cursor=4,6 |0: Newcol Joincol Find Grep Help Changelog Tutor Dump Themes Config Debug Exit echo SW''EPT-WS -|8: echo SW''EPT-WS -|9: SWEPT-WS -== snap ws-looked grid=120x21 cursor=7,19 +|17: /tmp/pardes-snap/headersweep/cwd (echo SW''EPT-WS) exit 0 +|18: Kill Save Collapse Del +== snap ws-looked grid=120x21 cursor=7,9 |0: Newcol Joincol Find Grep Help Changelog Tutor Dump Themes Config Debug Exit echo SW''EPT-WS xxhay.txtxx -|17: /tmp/pardes-snap/headersweep/cwd/hay.txt Save Tty Collaps -|18: e Del -|19: 1 ZQNEEDLE -== snap cancelled grid=120x21 cursor=7,19 +|7: /tmp/pardes-snap/headersweep/cwd/hay.txt Save Tty Collaps +|8: e Del +|9: 1 ZQNEEDLE +== snap cancelled grid=120x21 cursor=7,9 == style selected grid=120x21 |1: 0-1 d,#887455, 2-2 d,#1d2824, 3-59 #b2c3b8,#1d2824, 60-61 #b2c3b8,#887455, 62-62 #b2c3b8,#314738, 63-70 #becfc4,#314738, 71-79 #f5f7ee,#3c614a, 80-80 #f5f7ee,#314738, 81-119 #becfc4,#314738, |2: 0-1 d,#496656, 2-2 d,#1d2824, 3-35 #b2c3b8,#1d2824, 36-44 #d3b0d9,#1d2824, 45-59 #b2c3b8,#1d2824, 60-61 #b2c3b8,#add38a, 62-62 #b2c3b8,#314738, 63-95 #becfc4,#314738, 96-104 #dfbce5,#314738, 105-119 #becfc4,#314738, |3: 0-2 d,#1d2824, 3-59 #b2c3b8,#1d2824, 60-62 #b2c3b8,#314738, 63-119 #becfc4,#314738, -|6: 0-0 d,#608269, 1-1 d,#0d1410, 2-59 #e5eee5,#0d1410, 60-60 #e5eee5,#608269, 61-119 #e5eee5,#0d1410, -|7: 0-0 d,#608269, 1-1 d,#0d1410, 2-59 #e5eee5,#0d1410, 60-60 #e5eee5,#608269, 61-119 #e5eee5,#0d1410, -|8: 0-0 d,#608269, 1-1 d,#0d1410, 2-59 #e5eee5,#0d1410, 60-60 #e5eee5,#608269, 61-119 #e5eee5,#0d1410, -|9: 0-0 d,#608269, 1-1 d,#0d1410, 2-59 #e5eee5,#0d1410, 60-60 #e5eee5,#608269, 61-119 #e5eee5,#0d1410, -|17: 0-1 d,#496656, 2-2 d,#1d2824, 3-35 #b2c3b8,#1d2824, 36-43 #d3b0d9,#1d2824, 44-59 #b2c3b8,#1d2824, 60-60 #b2c3b8,#608269, 61-119 #b2c3b8,#0d1410, -|18: 0-2 d,#1d2824, 3-59 #b2c3b8,#1d2824, 60-60 #b2c3b8,#608269, 61-119 #b2c3b8,#0d1410, -|19: 0-0 d,#608269, 1-4 d,#0d1410, 5-6 #59675c,#0d1410, 7-59 #e5eee5,#0d1410, 60-60 #e5eee5,#608269, 61-119 #e5eee5,#0d1410, +|7: 0-1 d,#496656, 2-2 d,#1d2824, 3-35 #b2c3b8,#1d2824, 36-43 #d3b0d9,#1d2824, 44-59 #b2c3b8,#1d2824, 60-60 #b2c3b8,#608269, 61-119 #b2c3b8,#0d1410, +|8: 0-2 d,#1d2824, 3-59 #b2c3b8,#1d2824, 60-60 #b2c3b8,#608269, 61-119 #b2c3b8,#0d1410, +|9: 0-0 d,#608269, 1-4 d,#0d1410, 5-6 #59675c,#0d1410, 7-59 #e5eee5,#0d1410, 60-60 #e5eee5,#608269, 61-119 #e5eee5,#0d1410, +|17: 0-1 d,#496656, 2-2 d,#1d2824, 3-59 #b2c3b8,#1d2824, 60-60 #b2c3b8,#608269, 61-119 #b2c3b8,#0d1410, +|18: 0-3 d,#1d2824, 4-59 #b2c3b8,#1d2824, 60-60 #b2c3b8,#608269, 61-119 #b2c3b8,#0d1410, +|19: 0-0 d,#152019, 1-1 d,#0d1410, 2-59 #e5eee5,#0d1410, 60-60 #e5eee5,#608269, 61-119 #e5eee5,#0d1410, |
