diff --git a/src/shell-integration/nushell/ghostty-ssh-integration.nu b/src/shell-integration/nushell/ghostty-ssh-integration.nu deleted file mode 100644 index 495b96c78..000000000 --- a/src/shell-integration/nushell/ghostty-ssh-integration.nu +++ /dev/null @@ -1,108 +0,0 @@ -# Enables SSH environment variable compatibility. -# Converts TERM from xterm-ghostty to xterm-256color -# 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> { - 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. -# Attempts to install Ghostty's terminfo entry using infocmp and tic when -# 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, - ssh_args: list -]: [nothing -> record>] { - mut ssh_opts = $ssh_opts - let ssh_cfg = ^ssh -G ...($ssh_args) - | lines - | parse "{key} {value}" - | where key in ["user", "hostname"] - | select key value - | transpose -rd - | default { user: $env.USER, hostname: "localhost" } - - let ssh_id = $"($ssh_cfg.user)@($ssh_cfg.hostname)" - let ghostty_bin = $env.GHOSTTY_BIN_DIR | path join "ghostty" - - let is_cached = ( - ^$ghostty_bin ...(["+ssh-cache", $"--host=($ssh_id)"]) - | complete - | $in.exit_code == 0 - ) - - if not $is_cached { - let ssh_opts_copy = $ssh_opts - let terminfo_data = try {^infocmp -0 -x xterm-ghostty} catch { - print "Warning: Could not generate terminfo data." - return {ssh_term: "xterm-256color", ssh_opts: $ssh_opts_copy} - } - - print $"Setting up xterm-ghostty terminfo on ($ssh_cfg.hostname)..." - - let ctrl_path = ( - try { - mktemp -td $"ghostty-ssh-($ssh_cfg.user).XXXXXX" - } catch { - $"/tmp/ghostty-ssh-($ssh_cfg.user).($nu.pid)" - } | path join "socket" - ) - - let master_parts = $ssh_opts ++ ["-o" "ControlMaster=yes" "-o" $"ControlPath=($ctrl_path)" "-o" "ControlPersist=60s"] ++ $ssh_args - - ($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' - ] - ) - | 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)"] - } - - return {ssh_term: "xterm-ghostty", ssh_opts: $ssh_opts} -} - -# SSH Integration -export def --wrapped ssh [...ssh_args: string]: any -> any { - if ($ssh_args | is-empty) { - return (^ssh) - } - mut session = {ssh_term: "", ssh_opts: []} - let shell_features = $env.GHOSTTY_SHELL_FEATURES | split row ',' - - if "ssh-env" in $shell_features { - $session = set_ssh_env - } - if "ssh-terminfo" in $shell_features { - $session = set_ssh_terminfo $session.ssh_opts $ssh_args - } - - let ssh_parts = $session.ssh_opts ++ $ssh_args - with-env {TERM: $session.ssh_term} { - ^ssh ...$ssh_parts - } -} - -# Removes Ghostty's data directory from XDG_DATA_DIRS -$env.XDG_DATA_DIRS = ( - $env.XDG_DATA_DIRS - | split row ':' - | where {|path| $path != $env.GHOSTTY_SHELL_INTEGRATION_XDG_DIR } - | str join ':' -) diff --git a/src/shell-integration/nushell/vendor/autoload/bootstrap-integration.nu b/src/shell-integration/nushell/vendor/autoload/bootstrap-integration.nu deleted file mode 100644 index 317ba62d3..000000000 --- a/src/shell-integration/nushell/vendor/autoload/bootstrap-integration.nu +++ /dev/null @@ -1,29 +0,0 @@ -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 - } - _ => { } -} diff --git a/src/shell-integration/nushell/vendor/autoload/ghostty.nu b/src/shell-integration/nushell/vendor/autoload/ghostty.nu index 467e3f529..6a6f83629 100644 --- a/src/shell-integration/nushell/vendor/autoload/ghostty.nu +++ b/src/shell-integration/nushell/vendor/autoload/ghostty.nu @@ -4,26 +4,128 @@ export module ghostty { $feature in ($env.GHOSTTY_SHELL_FEATURES | default "" | split row ',') } + # Enables SSH environment variable compatibility. + # Converts TERM from xterm-ghostty to xterm-256color + # 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> { + 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. + # Attempts to install Ghostty's terminfo entry using infocmp and tic when + # 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 + ssh_args: list + ]: [nothing -> record>] { + mut ssh_opts = $ssh_opts + let ssh_cfg = ^ssh -G ...($ssh_args) + | lines + | parse "{key} {value}" + | where key in ["user" "hostname"] + | select key value + | transpose -rd + | default {user: $env.USER hostname: "localhost"} + + let ssh_id = $"($ssh_cfg.user)@($ssh_cfg.hostname)" + let ghostty_bin = $env.GHOSTTY_BIN_DIR | path join "ghostty" + + let is_cached = ( + ^$ghostty_bin ...(["+ssh-cache" $"--host=($ssh_id)"]) + | complete + | $in.exit_code == 0 + ) + + if not $is_cached { + let ssh_opts_copy = $ssh_opts + let terminfo_data = try { ^infocmp -0 -x xterm-ghostty } catch { + print "Warning: Could not generate terminfo data." + return {ssh_term: "xterm-256color" ssh_opts: $ssh_opts_copy} + } + + print $"Setting up xterm-ghostty terminfo on ($ssh_cfg.hostname)..." + + let ctrl_path = ( + try { + mktemp -td $"ghostty-ssh-($ssh_cfg.user).XXXXXX" + } catch { + $"/tmp/ghostty-ssh-($ssh_cfg.user).($nu.pid)" + } | path join "socket" + ) + + let master_parts = $ssh_opts ++ ["-o" "ControlMaster=yes" "-o" $"ControlPath=($ctrl_path)" "-o" "ControlPersist=60s"] ++ $ssh_args + + ($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' + ] + ) + | 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)"] + } + + return {ssh_term: "xterm-ghostty" ssh_opts: $ssh_opts} + } + # Wrap `sudo` to preserve Ghostty's TERMINFO environment variable export def --wrapped sudo [ - ...args # Arguments to pass to `sudo` + ...args # Arguments to pass to `sudo` ] { mut sudo_args = $args if (has_feature "sudo") { - # Extract just the sudo options (before the command) - let sudo_options = ($args | take until {|arg| - not (($arg | str starts-with "-") or ($arg | str contains "=")) - }) - - # Prepend TERMINFO preservation flag if not using sudoedit - if (not ("-e" in $sudo_options or "--edit" in $sudo_options)) { - $sudo_args = ($args | prepend "--preserve-env=TERMINFO") + # Extract just the sudo options (before the command) + let sudo_options = ( + $args | take until {|arg| + not (($arg | str starts-with "-") or ($arg | str contains "=")) } + ) + + # Prepend TERMINFO preservation flag if not using sudoedit + if (not ("-e" in $sudo_options or "--edit" in $sudo_options)) { + $sudo_args = ($args | prepend "--preserve-env=TERMINFO") + } } ^sudo ...$sudo_args } + # Wrap `ssh` to provide ghostty `ssh-integration` + export def --wrapped ssh [...ssh_args: string]: any -> any { + if ($ssh_args | is-empty) { + return (^ssh) + } + mut session = {ssh_term: "" ssh_opts: []} + let shell_features = $env.GHOSTTY_SHELL_FEATURES | split row ',' + + if (has_feature "ssh-env") { + $session = set_ssh_env + } + if (has_feature "ssh-terminfo") { + $session = set_ssh_terminfo $session.ssh_opts $ssh_args + } + + let ssh_parts = $session.ssh_opts ++ $ssh_args + with-env {TERM: $session.ssh_term} { + ^ssh ...$ssh_parts + } + } } # Clean up XDG_DATA_DIRS by removing GHOSTTY_SHELL_INTEGRATION_XDG_DIR diff --git a/src/shell-integration/nushell/vendor/autoload/source-integration.nu b/src/shell-integration/nushell/vendor/autoload/source-integration.nu deleted file mode 100644 index 1c21833a4..000000000 --- a/src/shell-integration/nushell/vendor/autoload/source-integration.nu +++ /dev/null @@ -1,11 +0,0 @@ -# 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 })