Merge pull request #1774 from il-k/elvish-integration-auto

feat(shell-integration): add automatic integration for Elvish
This commit is contained in:
Mitchell Hashimoto
2024-05-27 16:19:26 -07:00
committed by GitHub
6 changed files with 41 additions and 15 deletions

View File

@ -847,7 +847,7 @@ keybind: Keybinds = .{},
/// ///
/// * `detect` - Detect the shell based on the filename. /// * `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`. /// The default value is `detect`.
@"shell-integration": ShellIntegration = .detect, @"shell-integration": ShellIntegration = .detect,
@ -3412,6 +3412,7 @@ pub const ShellIntegration = enum {
none, none,
detect, detect,
bash, bash,
elvish,
fish, fish,
zsh, zsh,
}; };

View File

@ -22,6 +22,18 @@ Bash shell integration can also be sourced manually from `bash/ghostty.bash`.
### Elvish ### 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 <filename>`.
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 [Elvish](https://elv.sh) shell integration is supported by
the community and is not officially supported by Ghostty. We distribute 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. it for ease of access and use but do not provide support for it.

View File

@ -1,6 +1,6 @@
{ {
fn restore-xdg-dirs { 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 xdg-dirs = [(str:split ':' $E:XDG_DATA_DIRS)]
var len = (count $xdg-dirs) var len = (count $xdg-dirs)
@ -27,9 +27,9 @@
} else { } else {
set-env XDG_DATA_DIRS (str:join ':' $xdg-dirs) 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 restore-xdg-dirs
} }
} }
@ -117,4 +117,3 @@
edit:add-var sudo~ $sudo-with-terminfo~ edit:add-var sudo~ $sudo-with-terminfo~
} }
} }

View File

@ -6,7 +6,7 @@
function ghostty_restore_xdg_data_dir -d "restore the original XDG_DATA_DIR value" 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 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 return
end 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" set --function --path xdg_data_dirs "$XDG_DATA_DIRS"
# If our data dir is in the list then remove it. # 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] set --erase --function xdg_data_dirs[$index]
end 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 set --erase --global XDG_DATA_DIRS
end end
set --erase GHOSTTY_FISH_XDG_DIR set --erase GHOSTTY_SHELL_INTEGRATION_XDG_DIR
end end
function ghostty_exit -d "exit the shell integration setup" function ghostty_exit -d "exit the shell integration setup"

View File

@ -1024,6 +1024,7 @@ const Subprocess = struct {
.none => break :shell .{ null, default_shell_command }, .none => break :shell .{ null, default_shell_command },
.detect => null, .detect => null,
.bash => .bash, .bash => .bash,
.elvish => .elvish,
.fish => .fish, .fish => .fish,
.zsh => .zsh, .zsh => .zsh,
}; };

View File

@ -10,6 +10,7 @@ const log = std.log.scoped(.shell_integration);
/// Shell types we support /// Shell types we support
pub const Shell = enum { pub const Shell = enum {
bash, bash,
elvish,
fish, fish,
zsh, zsh,
}; };
@ -45,6 +46,7 @@ pub fn setup(
) !?ShellIntegration { ) !?ShellIntegration {
const exe = if (force_shell) |shell| switch (shell) { const exe = if (force_shell) |shell| switch (shell) {
.bash => "bash", .bash => "bash",
.elvish => "elvish",
.fish => "fish", .fish => "fish",
.zsh => "zsh", .zsh => "zsh",
} else exe: { } 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)) { if (std.mem.eql(u8, "fish", exe)) {
try setupFish(alloc_arena, resource_dir, env); try setupXdgDataDirs(alloc_arena, resource_dir, env);
break :shell .{ break :shell .{
.shell = .fish, .shell = .fish,
.command = command, .command = command,
@ -405,11 +415,14 @@ test "bash: preserve ENV" {
} }
} }
/// Setup the fish automatic shell integration. This works by /// Setup automatic shell integration for shells that include
/// modify XDG_DATA_DIRS to include the resource directory. /// their modules from paths in `XDG_DATA_DIRS` env variable.
/// Fish will automatically load configuration in XDG_DATA_DIRS ///
/// "fish/vendor_conf.d/*.fish". /// Path of shell-integration dir is prepended to `XDG_DATA_DIRS`.
fn setupFish( /// 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, alloc_arena: Allocator,
resource_dir: []const u8, resource_dir: []const u8,
env: *EnvMap, env: *EnvMap,
@ -426,7 +439,7 @@ fn setupFish(
// Set an env var so we can remove this from XDG_DATA_DIRS later. // 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 // This happens in the shell integration config itself. We do this
// so that our modifications don't interfere with other commands. // 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| { if (env.get("XDG_DATA_DIRS")) |old| {
// We have an old value, We need to prepend our value to it. // We have an old value, We need to prepend our value to it.