From afe51fc6c3675a6aa8ab2f5caf64796b65597c2c Mon Sep 17 00:00:00 2001 From: Gabriel Schneider Date: Wed, 30 Sep 2026 23:26:13 -0300 Subject: A pane's child runs with PAGER=cat and GIT_PAGER=cat where the user's environment sets neither, so a pty/run or a command pane never hangs in a pager git log or man run through pty/run, or in a command pane, sat in less at its first screen: no one presses q, and the run never answers. The child's environment now names cat as the pager when the inherited one names none; a user's own PAGER or GIT_PAGER is kept. It is every pane child's, a terminal's shell too, since a pty/run's line runs in it. Co-Authored-By: Claude Opus 5.5 --- src/host_io.zig | 30 +++++++++++++++++++++++++++++- 1 file changed, 29 insertions(+), 1 deletion(-) diff --git a/src/host_io.zig b/src/host_io.zig index ebe910aa..1fab3729 100644 --- a/src/host_io.zig +++ b/src/host_io.zig @@ -1268,6 +1268,18 @@ pub const ChildEnv = struct { slots[n] = entry; n += 1; } + // No pager to wait in: a pty/run or a command pane's output is read + // whole, and less would hold it at its first screen for ever. Only + // where the inherited environment chose none. + for (defaults) |default| { + const set = for (libc.environ[0..i]) |entry| { + if (std.mem.eql(u8, name(entry.?), name(default))) break true; + } else false; + if (set) continue; + if (n + own.len + 2 > slots.len) return null; + slots[n] = default; + n += 1; + } for (own) |mine| { slots[n] = mine; n += 1; @@ -1275,6 +1287,9 @@ pub const ChildEnv = struct { slots[n] = null; return @ptrCast(slots); } + + /// Set for a pane's child only when the user's environment has none. + const defaults = [_][*:0]const u8{ "PAGER=cat", "GIT_PAGER=cat" }; }; test "the child environment replaces the launcher's terminal identity exactly once" { @@ -1304,6 +1319,10 @@ test "the child environment replaces the launcher's terminal identity exactly on var colorterms: usize = 0; var probes: usize = 0; var dumb = false; + var pagers: usize = 0; + var git_pagers: usize = 0; + var pager_cat = false; + var git_pager_cat = false; var i: usize = 0; while (envp[i]) |entry| : (i += 1) { const line = std.mem.span(entry); @@ -1311,7 +1330,16 @@ test "the child environment replaces the launcher's terminal identity exactly on if (std.mem.startsWith(u8, line, "COLORTERM=")) colorterms += 1; if (std.mem.eql(u8, line, "TERM=dumb")) dumb = true; if (std.mem.eql(u8, line, "PARDES_CHILD_ENV_PROBE=1")) probes += 1; - } + if (std.mem.startsWith(u8, line, "PAGER=")) pagers += 1; + if (std.mem.startsWith(u8, line, "GIT_PAGER=")) git_pagers += 1; + if (std.mem.eql(u8, line, "PAGER=cat")) pager_cat = true; + if (std.mem.eql(u8, line, "GIT_PAGER=cat")) git_pager_cat = true; + } + // A pager only where the user named none: cat, so nothing waits in less. + try std.testing.expectEqual(@as(usize, 1), pagers); + try std.testing.expectEqual(@as(usize, 1), git_pagers); + if (std.c.getenv("PAGER") == null) try std.testing.expect(pager_cat); + if (std.c.getenv("GIT_PAGER") == null) try std.testing.expect(git_pager_cat); try std.testing.expectEqual(@as(usize, 1), terms); try std.testing.expectEqual(@as(usize, 1), colorterms); try std.testing.expectEqual(@as(usize, 1), probes); -- cgit v1.3