diff --git a/src/config/Config.zig b/src/config/Config.zig index 2d540e895..eb2cf0915 100644 --- a/src/config/Config.zig +++ b/src/config/Config.zig @@ -847,7 +847,7 @@ keybind: Keybinds = .{}, /// /// * `detect` - Detect the shell based on the filename. /// -/// * `bash`, `fish`, `zsh` - Use this specific shell injection scheme. +/// * `bash`, `elvish`, `fish`, `zsh` - Use this specific shell injection scheme. /// /// The default value is `detect`. @"shell-integration": ShellIntegration = .detect, @@ -3412,6 +3412,7 @@ pub const ShellIntegration = enum { none, detect, bash, + elvish, fish, zsh, }; diff --git a/src/shell-integration/README.md b/src/shell-integration/README.md index c27b45891..4a8579f8a 100644 --- a/src/shell-integration/README.md +++ b/src/shell-integration/README.md @@ -22,6 +22,18 @@ Bash shell integration can also be sourced manually from `bash/ghostty.bash`. ### Elvish +For [Elvish](https://elv.sh), `$GHOSTTY_RESOURCES_DIR/src/shell-integration` +contains an `./elvish/lib/ghostty-integration.elv` file. + +Elvish, on startup, searches for paths defined in `XDG_DATA_DIRS` +variable for `./elvish/lib/*.elv` files and imports them. They are thus +made available for use as modules by way of `use `. + +Ghostty launches Elvish, passing the environment with `XDG_DATA_DIRS`prepended +with `$GHOSTTY_RESOURCES_DIR/src/shell-integration`. It contains +`./elvish/lib/ghostty-integration.elv`. The user can then import it +by `use ghostty-integration`, which will run the integration routines. + The [Elvish](https://elv.sh) shell integration is supported by the community and is not officially supported by Ghostty. We distribute it for ease of access and use but do not provide support for it. diff --git a/src/shell-integration/elvish/lib/ghostty-integration.elv b/src/shell-integration/elvish/lib/ghostty-integration.elv index 6af878ba5..bd86b5e2a 100644 --- a/src/shell-integration/elvish/lib/ghostty-integration.elv +++ b/src/shell-integration/elvish/lib/ghostty-integration.elv @@ -1,6 +1,6 @@ { fn restore-xdg-dirs { - var integration-dir = $E:GHOSTTY_FISH_XDG_DIR + var integration-dir = $E:GHOSTTY_SHELL_INTEGRATION_XDG_DIR var xdg-dirs = [(str:split ':' $E:XDG_DATA_DIRS)] var len = (count $xdg-dirs) @@ -27,9 +27,9 @@ } else { set-env XDG_DATA_DIRS (str:join ':' $xdg-dirs) } - unset-env GHOSTTY_FISH_XDG_DIR + unset-env GHOSTTY_SHELL_INTEGRATION_XDG_DIR } - if (and (has-env GHOSTTY_FISH_XDG_DIR) (has-env XDG_DATA_DIRS)) { + if (and (has-env GHOSTTY_SHELL_INTEGRATION_XDG_DIR) (has-env XDG_DATA_DIRS)) { restore-xdg-dirs } } @@ -117,4 +117,3 @@ edit:add-var sudo~ $sudo-with-terminfo~ } } - diff --git a/src/shell-integration/fish/vendor_conf.d/ghostty-shell-integration.fish b/src/shell-integration/fish/vendor_conf.d/ghostty-shell-integration.fish old mode 100755 new mode 100644 index fb3088865..6ccec3933 --- a/src/shell-integration/fish/vendor_conf.d/ghostty-shell-integration.fish +++ b/src/shell-integration/fish/vendor_conf.d/ghostty-shell-integration.fish @@ -6,7 +6,7 @@ function ghostty_restore_xdg_data_dir -d "restore the original XDG_DATA_DIR value" # If we don't have our own data dir then we don't need to do anything. - if not set -q GHOSTTY_FISH_XDG_DIR + if not set -q GHOSTTY_SHELL_INTEGRATION_XDG_DIR return end @@ -19,7 +19,7 @@ function ghostty_restore_xdg_data_dir -d "restore the original XDG_DATA_DIR valu set --function --path xdg_data_dirs "$XDG_DATA_DIRS" # If our data dir is in the list then remove it. - if set --function index (contains --index "$GHOSTTY_FISH_XDG_DIR" $xdg_data_dirs) + if set --function index (contains --index "$GHOSTTY_SHELL_INTEGRATION_XDG_DIR" $xdg_data_dirs) set --erase --function xdg_data_dirs[$index] end @@ -30,7 +30,7 @@ function ghostty_restore_xdg_data_dir -d "restore the original XDG_DATA_DIR valu set --erase --global XDG_DATA_DIRS end - set --erase GHOSTTY_FISH_XDG_DIR + set --erase GHOSTTY_SHELL_INTEGRATION_XDG_DIR end function ghostty_exit -d "exit the shell integration setup" diff --git a/src/termio/Exec.zig b/src/termio/Exec.zig index 9063ca67f..1287600eb 100644 --- a/src/termio/Exec.zig +++ b/src/termio/Exec.zig @@ -1024,6 +1024,7 @@ const Subprocess = struct { .none => break :shell .{ null, default_shell_command }, .detect => null, .bash => .bash, + .elvish => .elvish, .fish => .fish, .zsh => .zsh, }; diff --git a/src/termio/shell_integration.zig b/src/termio/shell_integration.zig index fb57595f0..392fb5b48 100644 --- a/src/termio/shell_integration.zig +++ b/src/termio/shell_integration.zig @@ -10,6 +10,7 @@ const log = std.log.scoped(.shell_integration); /// Shell types we support pub const Shell = enum { bash, + elvish, fish, zsh, }; @@ -45,6 +46,7 @@ pub fn setup( ) !?ShellIntegration { const exe = if (force_shell) |shell| switch (shell) { .bash => "bash", + .elvish => "elvish", .fish => "fish", .zsh => "zsh", } else exe: { @@ -68,8 +70,16 @@ pub fn setup( }; } + if (std.mem.eql(u8, "elvish", exe)) { + try setupXdgDataDirs(alloc_arena, resource_dir, env); + break :shell .{ + .shell = .elvish, + .command = command, + }; + } + if (std.mem.eql(u8, "fish", exe)) { - try setupFish(alloc_arena, resource_dir, env); + try setupXdgDataDirs(alloc_arena, resource_dir, env); break :shell .{ .shell = .fish, .command = command, @@ -405,11 +415,14 @@ test "bash: preserve ENV" { } } -/// Setup the fish automatic shell integration. This works by -/// modify XDG_DATA_DIRS to include the resource directory. -/// Fish will automatically load configuration in XDG_DATA_DIRS -/// "fish/vendor_conf.d/*.fish". -fn setupFish( +/// Setup automatic shell integration for shells that include +/// their modules from paths in `XDG_DATA_DIRS` env variable. +/// +/// Path of shell-integration dir is prepended to `XDG_DATA_DIRS`. +/// It is also saved in `GHOSTTY_SHELL_INTEGRATION_XDG_DIR` variable +/// so that the shell can refer to it and safely remove this directory +/// from `XDG_DATA_DIRS` when integration is complete. +fn setupXdgDataDirs( alloc_arena: Allocator, resource_dir: []const u8, env: *EnvMap, @@ -426,7 +439,7 @@ fn setupFish( // Set an env var so we can remove this from XDG_DATA_DIRS later. // This happens in the shell integration config itself. We do this // so that our modifications don't interfere with other commands. - try env.put("GHOSTTY_FISH_XDG_DIR", integ_dir); + try env.put("GHOSTTY_SHELL_INTEGRATION_XDG_DIR", integ_dir); if (env.get("XDG_DATA_DIRS")) |old| { // We have an old value, We need to prepend our value to it.