diff options
| -rw-r--r-- | .agents/skills/pardes-9p/SKILL.md | 2 | ||||
| -rw-r--r-- | docs/config.md | 3 | ||||
| -rw-r--r-- | docs/fs.md | 2 | ||||
| -rw-r--r-- | src/Output.zig | 2 | ||||
| -rw-r--r-- | src/builtins.zig | 2 | ||||
| -rw-r--r-- | src/config.zig | 14 | ||||
| -rw-r--r-- | src/ninep/ctl.zig | 2 | ||||
| -rw-r--r-- | src/pardes.zig | 2 | ||||
| -rw-r--r-- | test/macos_e2e.swift | 2 | ||||
| -rw-r--r-- | test/output.zig | 3 | ||||
| -rw-r--r-- | test/snapshot.zig | 5 | ||||
| -rw-r--r-- | test/snapshots/shellset.snap | 4 |
12 files changed, 27 insertions, 16 deletions
diff --git a/.agents/skills/pardes-9p/SKILL.md b/.agents/skills/pardes-9p/SKILL.md index 61b117a5..0cd52715 100644 --- a/.agents/skills/pardes-9p/SKILL.md +++ b/.agents/skills/pardes-9p/SKILL.md @@ -149,7 +149,7 @@ the editor, not as a write error, so inspect the resulting pane, index, message or screen; only a malformed line fails the write itself. A word no builtin knows (a typo included) is a command line: written at a terminal at its prompt it is typed into that shell; from anywhere else it runs as a command -pane, a terminal whose child is the root ctl's `Shell` (fish unless set) +pane, a terminal whose child is the root ctl's `Shell` ($SHELL, else /bin/sh, unless set) running `-c` the line in the pane's directory, which ends showing `exit N` (a typo: `exit 127`) and logs `run <serial> <line>` and `exit <serial> <N|?>` -- `exec` reads back its serial, so follow `log` for the exit. The directory's next command reuses a finished diff --git a/docs/config.md b/docs/config.md index 40d0fb24..93190556 100644 --- a/docs/config.md +++ b/docs/config.md @@ -46,7 +46,8 @@ the browser still applies the compiled percentage to its DOM glyphs. The startup path is printed whether or not a file exists — that is usually when it is most useful — and is ordinary selectable text, so a right click on it opens the file. Shell follows the same requested/effective/pending model as -Font. `Compiled default shell` is the command built into the binary; `Shell +Font. `Default shell` is the one used while no `Shell` is set: `$SHELL`, the +user's login shell, else `/bin/sh`; an explicit `Shell` overrides it. `Shell effective (last spawn)` is the executable the native host really chose after installation lookup and fallback. A changed request remains pending until a terminal is spawned, because the core does not resolve native executables. @@ -304,7 +304,7 @@ same tree without leaving the process. is typed into that shell (and a terminal whose shell exits, `exit` typed or run, closes its pane). From anywhere else -- a file, a scratch, a tag, a terminal whose tty a program holds -- it runs as a command pane: a - terminal whose child is the root ctl's `Shell` (fish unless set) run + terminal whose child is the root ctl's `Shell` ($SHELL, else /bin/sh, unless set) run with `-c` and the line, in the pane's directory, with job control on (bash, sh, dash, zsh, ksh `-m`; fish `status job-control full`), which shows its output and then `exit N` (its tag reads `<dir> (<line>) diff --git a/src/Output.zig b/src/Output.zig index 2f462fd1..ee932768 100644 --- a/src/Output.zig +++ b/src/Output.zig @@ -665,7 +665,7 @@ pub fn openConfig(p: *Pardes, id: usize) !void { .startup_config_path = p.opts.startup_config_path, .platform = @tagName(pardes.platform), .theme_name = p.theme().name, - .compiled_default_shell = config.default_shell, + .compiled_default_shell = config.defaultShell(), .gui_shader_source_mode = if (gui_shader_source_mode) |mode| mode.label() else diff --git a/src/builtins.zig b/src/builtins.zig index 8c6228c0..f7104a8c 100644 --- a/src/builtins.zig +++ b/src/builtins.zig @@ -399,7 +399,7 @@ test "Ligatures is a setting only in the shell that shapes text" { .startup_config_path = null, .platform = @tagName(pardes.platform), .theme_name = p.theme().name, - .compiled_default_shell = config.default_shell, + .compiled_default_shell = config.defaultShell(), .hover_delay_frames = null, .native_images = false, .capabilities = capabilities, diff --git a/src/config.zig b/src/config.zig index fb38e4dd..a59fe18d 100644 --- a/src/config.zig +++ b/src/config.zig @@ -345,7 +345,15 @@ test "wheel drift guard" { try std.testing.expect(wheelTick(&g, false)); } -pub const default_shell = "fish"; +/// The shell when no `Shell` is set: the user's login shell ($SHELL), as a +/// terminal would start, else /bin/sh. An explicit `Shell` overrides it. +pub fn defaultShell() []const u8 { + if (comptime pardes.hosted) if (std.c.getenv("SHELL")) |s| { + const shell = std.mem.span(s); + if (shell.len > 0) return shell; + }; + return "/bin/sh"; +} // Minimum file gutter width, including the space after the line number. pub const PREFIX_W: u16 = 5; @@ -1364,7 +1372,7 @@ pub const Runtime = struct { try out.writeAll("Startup config: no per-user config path\n"); try out.print( "Platform: {s}\n" ++ - "Compiled default shell: {s}\n", + "Default shell ($SHELL, else /bin/sh): {s}\n", .{ context.platform, context.compiled_default_shell }, ); if (context.gui_shader_source_mode) |mode| @@ -1719,7 +1727,7 @@ pub const Runtime = struct { "TaglineSize 82\n", "Startup config: /tmp/pardes/init\n", "Platform: gui\n", - "Compiled default shell: /bin/sh\n", + "Default shell ($SHELL, else /bin/sh): /bin/sh\n", "GUI shader source: live GLSL compiled during this build\n", "Look hover delay: 18 frames\n", "Native images: on\n", diff --git a/src/ninep/ctl.zig b/src/ninep/ctl.zig index 8a35c381..0ab63fbb 100644 --- a/src/ninep/ctl.zig +++ b/src/ninep/ctl.zig @@ -399,7 +399,7 @@ pub fn writeSettingsOf(p: *Pardes, s: *const config.Runtime, w: *std.Io.Writer) .theme => try w.print("{s} {s}\n", .{ word, if (s == &p.settings) p.theme().name else pardes.themes[s.theme].name }), .shell => { const chosen = s.shell.requested.get(); - try w.print("{s} {s}\n", .{ word, if (chosen.len > 0) chosen else config.default_shell }); + try w.print("{s} {s}\n", .{ word, if (chosen.len > 0) chosen else config.defaultShell() }); }, .font => { const requested = s.font.requested_name.get(); diff --git a/src/pardes.zig b/src/pardes.zig index a0b11566..f2791e33 100644 --- a/src/pardes.zig +++ b/src/pardes.zig @@ -4925,7 +4925,7 @@ pub const Pardes = struct { pub fn shellBin(p: *const Pardes) []const u8 { const selected = p.settings.shell.requested.get(); - return if (selected.len == 0) config.default_shell else selected; + return if (selected.len == 0) config.defaultShell() else selected; } pub fn acknowledgeShell(p: *Pardes, id: usize, executable: []const u8, prompt_marks: bool) void { diff --git a/test/macos_e2e.swift b/test/macos_e2e.swift index 5f172f9d..2b0eedad 100644 --- a/test/macos_e2e.swift +++ b/test/macos_e2e.swift @@ -1251,7 +1251,7 @@ private func buildWorld(stem: String) throws -> String { // sources $HOME/.bashrc (host_io.Shell) — so this is what pins the // prompt to `$ ` and keeps the developer's history out of the capture. try "PS1='$ '\nHISTFILE=\n".write(toFile: "\(home)/.bashrc", atomically: true, encoding: .utf8) - // ...and the config is not empty, because the DEFAULT shell is fish, whose + // ...and the config is not empty, because the DEFAULT shell is $SHELL (fish, say), whose // prompt carries a hostname and whose greeting carries a version. A golden // taken against that is a golden for one machine. try "Shell bash\n".write(toFile: "\(pardesConfig)/init", atomically: true, encoding: .utf8) diff --git a/test/output.zig b/test/output.zig index 419bcca2..f3e61e93 100644 --- a/test/output.zig +++ b/test/output.zig @@ -544,10 +544,11 @@ test "Config prints the startup path and refreshes its one output" { for ([_][]const u8{ "Startup config: " ++ path ++ "\n", "Theme orchard\n", - "Shell requested (new panes) " ++ config.default_shell ++ " (default)\n", "Shell effective (last spawn) (none)\n", "Shell pending on\n", }) |line| try std.testing.expect(std.mem.indexOf(u8, out.content, line) != null); + var default_line: [256]u8 = undefined; + try std.testing.expect(std.mem.indexOf(u8, out.content, try std.fmt.bufPrint(&default_line, "Shell requested (new panes) {s} (default)\n", .{config.defaultShell()})) != null); try std.testing.expectEqualStrings(config.config_buffer, std.fs.path.basename(out.path)); try std.testing.expectEqual(panes.Output.Origin{ .cmd = .Config }, out.output.?.from); diff --git a/test/snapshot.zig b/test/snapshot.zig index 2fa8e89c..c49e7645 100644 --- a/test/snapshot.zig +++ b/test/snapshot.zig @@ -562,8 +562,9 @@ fn runScript(arena: std.mem.Allocator, exe_z: [:0]const u8, script_path: []const // XDG directory that points outside this per-snapshot fake home. const config_home = try std.fmt.allocPrintSentinel(arena, "{s}/.config", .{home}, 0); _ = setenv("XDG_CONFIG_HOME", config_home, 1); - // ...and it is not empty: the DEFAULT shell is fish, whose prompt carries - // a hostname and whose greeting carries a version, so a golden taken + // ...and it is not empty: the DEFAULT shell is $SHELL, whatever this + // machine's user logs in with (fish's prompt carries a hostname and its + // greeting a version), so a golden taken // against it would be a golden for this machine. Every script here runs // bash — the .bashrc above pins its prompt to `$ ` — and the fish path is // covered by host_io.Shell's unit tests instead. This is an ordinary diff --git a/test/snapshots/shellset.snap b/test/snapshots/shellset.snap index d2bacf38..ef8b02b9 100644 --- a/test/snapshots/shellset.snap +++ b/test/snapshots/shellset.snap @@ -2,8 +2,8 @@ # here is the case that has to hold on a machine you did not set up: the name # resolves to nothing, and the pane opens anyway. # -# That is not a corner — it is the DEFAULT's failure mode. pardes ships -# `Shell fish` as the default, and a box without fish must still get a working +# That is not a corner — it is the DEFAULT's failure mode. pardes defaults +# to $SHELL, which may name a shell the box lacks, and it must still get a working # shell rather than a pane whose child dies at exec and shows one EOF. So the # lookup falls back, and this is the proof: a name nothing resolves to, and the # new pane still greets and lists like any other. |
