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.
///
/// * `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,
};

View File

@ -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 <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 community and is not officially supported by Ghostty. We distribute
it for ease of access and use but do not provide support for it.

View File

@ -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~
}
}

View File

@ -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"

View File

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

View File

@ -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.