summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/exec.zig6
-rw-r--r--src/mouse.zig2
-rw-r--r--src/ninep/cols.zig22
-rw-r--r--src/pardes.zig25
4 files changed, 52 insertions, 3 deletions
diff --git a/src/exec.zig b/src/exec.zig
index bb4309a4..484b85d7 100644
--- a/src/exec.zig
+++ b/src/exec.zig
@@ -310,12 +310,12 @@ pub fn spawnV9fsTty(p: *Pardes, from: usize) void {
}
fn spawnTtyWithMount(p: *Pardes, from: usize, v9fs: bool) ?*Pane {
- const src = p.panes[from] orelse return null;
+ if (p.panes[from] == null) return null;
const free = p.freeSlot() orelse {
p.reportError(from, "Tty", error.NoPaneSlots);
return null;
};
- const nt = p.newShell(free, Pardes.paneDir(src)) catch |err| {
+ const nt = p.newShell(free, p.execDir(from)) catch |err| {
p.reportError(from, "Tty", err);
return null;
};
@@ -577,7 +577,7 @@ fn runCommand(p: *Pardes, from: usize, line: []const u8) ?usize {
return null;
}
const src = p.panes[from] orelse return null;
- const dir = Pardes.paneDir(src);
+ const dir = p.execDir(from);
// Not one whose pty a job it left behind still prints to: reusing it
// would hang that job up.
const reuse: ?usize = if (src.command != null and src.command_done and !src.command_pty) from else for (p.panes, 0..) |slot, i| {
diff --git a/src/mouse.zig b/src/mouse.zig
index 1ca53017..6b58a489 100644
--- a/src/mouse.zig
+++ b/src/mouse.zig
@@ -385,6 +385,8 @@ pub fn handleMouse(p: *Pardes, m: Mouse) void {
// A column tag's command acts on that column, empty or not.
p.exec_column = column;
defer p.exec_column = null;
+ p.exec_header = true;
+ defer p.exec_header = false;
if (word.len > 0) {
if (m.button == config.exec_button) {
const named = std.meta.stringToEnum(Builtin, word);
diff --git a/src/ninep/cols.zig b/src/ninep/cols.zig
index ad7d30f8..c55c1e73 100644
--- a/src/ninep/cols.zig
+++ b/src/ninep/cols.zig
@@ -140,6 +140,8 @@ pub fn writeCtl(p: *Pardes, req: Req, serial: u32) Reply {
const col = layout.columnBySerial(p, serial) orelse return Reply.fail(req.tag, E.NOENT);
p.exec_column = col;
defer p.exec_column = null;
+ p.exec_header = true;
+ defer p.exec_header = false;
if (pardes.ctlfs.ctl.runBuiltin(p, req, p.active, line)) |refusal| return refusal;
}
return .{ .tag = req.tag, .written = @intCast(req.data.len) };
@@ -163,6 +165,8 @@ pub fn writeExec(p: *Pardes, req: Req, serial: ?u32) Reply {
if (p.panes[p.active] == null) return Reply.fail(req.tag, E.NOENT);
p.exec_column = col;
defer p.exec_column = null;
+ p.exec_header = true;
+ defer p.exec_header = false;
pardes.ctlfs.ctl.run(p, p.active, true, line, true);
}
return .{ .tag = req.tag, .written = @intCast(req.data.len) };
@@ -315,3 +319,21 @@ test "tagexec runs a word as a click in the workspace tag; exec files read back
try testing.expectEqual(tree.Status.ok, th.wr(p, Node.ofCol(right, .exec), "Msg from a column\n").reply.status);
try testing.expect(th.logHas(p, "msg - from a column\n"));
}
+
+test "a word run from the workspace's or a column's tag runs in the session's directory, a pane's in its own" {
+ const p = try th.withFile(testing.allocator, "x\n");
+ defer p.deinit();
+ const session = p.sessionDir();
+ try testing.expect(!std.mem.eql(u8, session, pardes.Pardes.paneDir(p.panes[0].?))); // the file is elsewhere
+ const dirs = [_]u64{ @intFromEnum(tree.TopFile.tagexec), Node.ofCol(layout.columnSerial(p, 0), .exec) };
+ for (dirs) |node| {
+ try testing.expectEqual(tree.Status.ok, th.wr(p, node, "true\n").reply.status);
+ const made = p.paneBySerial(p.fs.results[0]).?;
+ try testing.expectEqualStrings(session, pardes.Pardes.paneDir(p.panes[made].?));
+ try p.removePane(made, null);
+ }
+ const from_pane = p.panes[0].?.serial;
+ _ = th.wr(p, Node.of(from_pane, .exec), "true\n");
+ const made = p.paneBySerial(p.fs.results[0]).?;
+ try testing.expectEqualStrings(pardes.Pardes.paneDir(p.panes[0].?), pardes.Pardes.paneDir(p.panes[made].?));
+}
diff --git a/src/pardes.zig b/src/pardes.zig
index ac6d52cd..42f1b6e4 100644
--- a/src/pardes.zig
+++ b/src/pardes.zig
@@ -4275,6 +4275,12 @@ pub const Pardes = struct {
/// (exec.placeNew): closed at the step's end, once whatever made them
/// is done with them.
unplaced: std.StaticBitSet(MAX_PANES) = .initEmpty(),
+ /// The running word came from the workspace's or a column's tag, which
+ /// have no directory of their own: it runs in the session's
+ /// (`sessionDir`), as acme's row and column tags do.
+ exec_header: bool = false,
+ session_dir: [limits.host_path_cap]u8 = undefined,
+ session_dir_len: ?u16 = null,
/// acme's activecol (dat.c:37), by column serial, 0 for none: the
/// column last typed in (acme.c:487), clicked in with the select button
/// (acme.c:659), dropped into by a grip (acme.c:640), or given a new
@@ -5776,6 +5782,8 @@ pub const Pardes = struct {
// A column tag's command acts on that column, empty or not.
p.exec_column = if (header != null) p.header_column else null;
defer p.exec_column = null;
+ p.exec_header = header != null;
+ defer p.exec_header = false;
// Out of the tag or header FIRST: Del frees the pane, Kill
// and Restore the whole session.
if (header != null) tagline.exitHeader(p) else pane.focus = .body;
@@ -5878,6 +5886,23 @@ pub const Pardes = struct {
// ---- search (`/`, Find, n/N): results into an output buffer, look the rows ----
+ /// Where pardes started: the directory of what runs from a header.
+ pub fn sessionDir(p: *Pardes) []const u8 {
+ if (p.session_dir_len) |n| return p.session_dir[0..n];
+ if (comptime !hosted) return "/";
+ if (std.c.getcwd(&p.session_dir, p.session_dir.len) == null) return "/";
+ const n: u16 = @intCast(std.mem.indexOfScalar(u8, &p.session_dir, 0) orelse return "/");
+ p.session_dir_len = n;
+ return p.session_dir[0..n];
+ }
+
+ /// The directory a word run from pane `id`'s text or tag runs in, or,
+ /// from a header, the session's.
+ pub fn execDir(p: *Pardes, id: usize) []const u8 {
+ if (p.exec_header) return p.sessionDir();
+ return paneDir(p.panes[id] orelse return p.sessionDir());
+ }
+
pub fn paneDir(pane: *const Pane) []const u8 {
switch (pane.cwd) {
.inherited => |src| return paneDir(src),