Alternative approach by unconditionally setting xdgDataDirs and checking features with nu
parent
d69e16c168
commit
07f4ef8e47
|
|
@ -76,6 +76,18 @@ allowing us to automatically integrate with the shell. For details
|
|||
on the Fish startup process, see the
|
||||
[Fish documentation](https://fishshell.com/docs/current/language.html).
|
||||
|
||||
### Nushell
|
||||
|
||||
For `nushell` Ghostty prepends to the `XDG_DATA_DIRS` directory. Nushell automatically
|
||||
loads configuration files in `<XDG_DATA_DIRS>/nushell/vendor/autoload/*.nu` on startup. These
|
||||
directories are represented in `Nu` by `$nu.vendor-autoload-dirs`. For more details see
|
||||
|
||||
[Nushell documentation](https://www.nushell.sh/book/configuration.html#configuration-overview)
|
||||
|
||||
> [!NOTE]
|
||||
>
|
||||
> Ghostty implements concretely the `ssh-*` features. The rest of the features are supported mostly out of the box by Nushell.
|
||||
|
||||
### Zsh
|
||||
|
||||
For `zsh`, Ghostty sets `ZDOTDIR` so that it loads our configuration
|
||||
|
|
@ -90,17 +102,3 @@ fi
|
|||
```
|
||||
|
||||
Shell integration requires Zsh 5.1+.
|
||||
|
||||
### Nushell
|
||||
|
||||
For `nushell` Ghostty prepends to the `XDG_DATA_DIRS` directory. Nushell automatically
|
||||
loads configuration files in `<XDG_DATA_DIRS>/nushell/vendor/autoload/*.nu` on startup. These
|
||||
directories are represented in `Nu` by `$nu.vendor-autoload-dirs`. For more details see
|
||||
|
||||
[Nushell documentation](https://www.nushell.sh/book/configuration.html#configuration-overview)
|
||||
|
||||
> [!NOTE]
|
||||
>
|
||||
> Ghostty only prepends to `XDG_DATA_DIRS` in the case where the `ssh-*` features are enabled.
|
||||
> Nushell supports most features out of the box, so other shell integration features are not
|
||||
> necessary.
|
||||
|
|
|
|||
|
|
@ -3,7 +3,10 @@
|
|||
# and propagates COLORTERM, TERM_PROGRAM, and TERM_PROGRAM_VERSION
|
||||
# check your sshd_config on remote host to see if these variables are accepted
|
||||
def set_ssh_env []: nothing -> record<ssh_term: string, ssh_opts: list<string>> {
|
||||
return {ssh_term: "xterm-256color", ssh_opts: ["-o", "SetEnv COLORTERM=truecolor", "-o", "SendEnv TERM_PROGRAM TERM_PROGRAM_VERSION"]}
|
||||
return {
|
||||
ssh_term: "xterm-256color",
|
||||
ssh_opts: ["-o", "SetEnv COLORTERM=truecolor", "-o", "SendEnv TERM_PROGRAM TERM_PROGRAM_VERSION"]
|
||||
}
|
||||
}
|
||||
|
||||
# Enables automatic terminfo installation on remote hosts.
|
||||
|
|
@ -11,7 +14,10 @@ def set_ssh_env []: nothing -> record<ssh_term: string, ssh_opts: list<string>>
|
|||
# connecting to hosts that lack it.
|
||||
# Requires infocmp to be available locally and tic to be available on remote hosts.
|
||||
# Caches installations to avoid repeat installations.
|
||||
def set_ssh_terminfo [ssh_opts: list<string>, ssh_args: list<string>] {
|
||||
def set_ssh_terminfo [
|
||||
ssh_opts: list<string>,
|
||||
ssh_args: list<string>
|
||||
]: [nothing -> record<ssh_term: string, ssh_opts: list<string>>] {
|
||||
mut ssh_opts = $ssh_opts
|
||||
let ssh_cfg = ^ssh -G ...($ssh_args)
|
||||
| lines
|
||||
|
|
@ -47,25 +53,24 @@ def set_ssh_terminfo [ssh_opts: list<string>, ssh_args: list<string>] {
|
|||
} | path join "socket"
|
||||
)
|
||||
|
||||
let master_parts = $ssh_opts ++ ["-o", "ControlMaster=yes", "-o", $"ControlPath=($ctrl_path)", "-o", "ControlPersist=60s"] ++ $ssh_args
|
||||
let master_parts = $ssh_opts ++ ["-o" "ControlMaster=yes" "-o" $"ControlPath=($ctrl_path)" "-o" "ControlPersist=60s"] ++ $ssh_args
|
||||
|
||||
let terminfo_present = (
|
||||
^ssh ...($master_parts ++ ["infocmp", "xterm-ghostty"])
|
||||
| complete
|
||||
| $in.exit_code == 0
|
||||
($terminfo_data) | ^ssh ...(
|
||||
$master_parts ++
|
||||
[
|
||||
'
|
||||
infocmp xterm-ghostty >/dev/null 2>&1 && exit 0
|
||||
command -v tic >/dev/null 2>&1 || exit 1
|
||||
mkdir -p ~/.terminfo 2>/dev/null && tic -x - 2>/dev/null && exit 0
|
||||
exit 1'
|
||||
]
|
||||
)
|
||||
|
||||
if (not $terminfo_present) {
|
||||
(
|
||||
$terminfo_data
|
||||
| ^ssh ...($master_parts ++ ["mkdir", "-p", "~/.terminfo", "&&", "tic", "-x", "-"])
|
||||
)
|
||||
| complete
|
||||
| if $in.exit_code != 0 {
|
||||
print "Warning: Failed to install terminfo."
|
||||
return {ssh_term: "xterm-256color", ssh_opts: $ssh_opts}
|
||||
}
|
||||
| complete
|
||||
| if $in.exit_code != 0 {
|
||||
print "Warning: Failed to install terminfo."
|
||||
return {ssh_term: "xterm-256color" ssh_opts: $ssh_opts}
|
||||
}
|
||||
|
||||
^$ghostty_bin ...(["+ssh-cache", $"--add=($ssh_id)"]) o+e>| ignore
|
||||
$ssh_opts ++= ["-o", $"ControlPath=($ctrl_path)"]
|
||||
}
|
||||
|
|
@ -74,7 +79,7 @@ def set_ssh_terminfo [ssh_opts: list<string>, ssh_args: list<string>] {
|
|||
}
|
||||
|
||||
# SSH Integration
|
||||
export def --wrapped ssh [...ssh_args: string] {
|
||||
export def --wrapped ssh [...ssh_args: string]: any -> any {
|
||||
if ($ssh_args | is-empty) {
|
||||
return (^ssh)
|
||||
}
|
||||
|
|
@ -0,0 +1,29 @@
|
|||
let enable_integration = $env.GHOSTTY_SHELL_FEATURES | split row ','
|
||||
| where ($it in ["ssh-env" "ssh-terminfo"])
|
||||
| is-not-empty
|
||||
|
||||
let ghostty_ssh_file = $env.GHOSTTY_RESOURCES_DIR
|
||||
| path join "shell-integration" "nushell" "ghostty-ssh-integration.nu"
|
||||
|
||||
let ssh_integration_file = $nu.data-dir | path join "ghostty-ssh-integration.nu"
|
||||
let ssh_file_exists = $ssh_integration_file | path exists
|
||||
|
||||
# TOD0: In case of an update to the `ghostty-ssh-integration.nu` file
|
||||
# the file wont be updated here, so we need to support
|
||||
# saving the new file once there is an update
|
||||
|
||||
match [$enable_integration $ssh_file_exists] {
|
||||
[true false] => {
|
||||
# $nu.data-dir is not created by default
|
||||
# https://www.nushell.sh/book/configuration.html#startup-variables
|
||||
$nu.data-dir | path exists | if (not $in) { mkdir $nu.data-dir }
|
||||
open $ghostty_ssh_file | save $ssh_integration_file
|
||||
}
|
||||
[false true] => {
|
||||
# We need to check if the user disabled `ssh-integration` and thus
|
||||
# the integration file needs to be removed so it doesnt get sourced by
|
||||
# the `source-integration.nu` file
|
||||
rm $ssh_integration_file
|
||||
}
|
||||
_ => { }
|
||||
}
|
||||
|
|
@ -0,0 +1,11 @@
|
|||
# Sourcing the `ghostty-integration.nu` cant be on the
|
||||
# `bootstrap-integration.nu` file because it tries to resolve the `sourced`
|
||||
# file at parsing time, which would make it source nothing.
|
||||
|
||||
# But here we rely on the fact that `boostrap-integration.nu` gets parsed
|
||||
# and executed first, and then we can count on `ssh_integration_file` being available
|
||||
|
||||
#https://www.nushell.sh/book/thinking_in_nu.html#example-dynamically-generating-source
|
||||
|
||||
const ssh_integration_file = $nu.data-dir | path join "ghostty-ssh-integration.nu"
|
||||
source (if ($ssh_integration_file | path exists) { $ssh_integration_file } else { null })
|
||||
|
|
@ -68,7 +68,6 @@ pub fn setup(
|
|||
command,
|
||||
env,
|
||||
exe,
|
||||
features,
|
||||
);
|
||||
|
||||
// Setup our feature env vars
|
||||
|
|
@ -83,7 +82,6 @@ fn setupShell(
|
|||
command: config.Command,
|
||||
env: *EnvMap,
|
||||
exe: []const u8,
|
||||
features: config.ShellIntegrationFeatures,
|
||||
) !?ShellIntegration {
|
||||
if (std.mem.eql(u8, "bash", exe)) {
|
||||
// Apple distributes their own patched version of Bash 3.2
|
||||
|
|
@ -132,7 +130,9 @@ fn setupShell(
|
|||
}
|
||||
|
||||
if (std.mem.eql(u8, "nu", exe)) {
|
||||
try setupNu(alloc_arena, resource_dir, env, features);
|
||||
// Sets up XDG_DATA_DIRS so that it can be picked automatically by
|
||||
// nushell on startup.
|
||||
try setupXdgDataDirs(alloc_arena, resource_dir, env);
|
||||
return null;
|
||||
}
|
||||
|
||||
|
|
@ -659,19 +659,6 @@ test "xdg: existing XDG_DATA_DIRS" {
|
|||
try testing.expectEqualStrings("./shell-integration:/opt/share", env.get("XDG_DATA_DIRS").?);
|
||||
}
|
||||
|
||||
/// Setup the nushell shell integration. This works by setting
|
||||
/// XDG_DATA_DIRS so that it can be picked automatically by
|
||||
/// nushell on startup.
|
||||
/// Only implements `ssh-*` shell features. Rest are not supported.
|
||||
fn setupNu(alloc_arena: Allocator, resource_dir: []const u8, env: *EnvMap, features: config.ShellIntegrationFeatures) !void {
|
||||
// This makes sure that `Nu` loads our integration file
|
||||
// and wraps the `ssh` function only if the `ssh` features
|
||||
// are enabled.
|
||||
// Otherwise, it does not do anything.
|
||||
if (features.@"ssh-env" or features.@"ssh-terminfo") {
|
||||
try setupXdgDataDirs(alloc_arena, resource_dir, env);
|
||||
}
|
||||
}
|
||||
/// Setup the zsh automatic shell integration. This works by setting
|
||||
/// ZDOTDIR to our resources dir so that zsh will load our config. This
|
||||
/// config then loads the true user config.
|
||||
|
|
|
|||
Loading…
Reference in New Issue