mirror of
https://github.com/ghostty-org/ghostty.git
synced 2025-10-17 15:21:50 +00:00
fix: optimize SSH integration and improve error handling
- Replace dual-loop SSH config parsing with efficient single-pass case statement - Remove overly cautious timeout logic from cache checks for simplicity - Add base64 availability check with xterm-256color fallback when missing - Include hostname in terminfo setup messages for better UX - Maintain SendEnv/SetEnv dual approach for maximum OpenSSH compatibility (relying on SetEnv alone seems to drop some vars during my tests, despite them being explicitly included in AcceptEnv on the remote host)
This commit is contained in:
@@ -244,132 +244,116 @@ _ghostty_deferred_init() {
|
||||
}
|
||||
fi
|
||||
|
||||
# SSH Integration
|
||||
# SSH Integration
|
||||
if [[ "$GHOSTTY_SHELL_FEATURES" =~ (ssh-env|ssh-terminfo) ]]; then
|
||||
: "${GHOSTTY_SSH_CACHE_TIMEOUT:=5}"
|
||||
: "${GHOSTTY_SSH_CHECK_TIMEOUT:=3}"
|
||||
|
||||
# SSH wrapper that preserves Ghostty features across remote connections
|
||||
ssh() {
|
||||
emulate -L zsh
|
||||
setopt local_options no_glob_subst
|
||||
|
||||
local -a ssh_env ssh_opts
|
||||
|
||||
local ssh_env ssh_opts ssh_exported_vars
|
||||
ssh_env=()
|
||||
ssh_opts=()
|
||||
ssh_exported_vars=()
|
||||
|
||||
# Configure environment variables for remote session
|
||||
if [[ "$GHOSTTY_SHELL_FEATURES" =~ ssh-env ]]; then
|
||||
local -a ssh_env_vars=(
|
||||
ssh_opts+=(-o "SetEnv COLORTERM=truecolor")
|
||||
|
||||
if [[ -n "${TERM_PROGRAM+x}" ]]; then
|
||||
ssh_exported_vars+=("TERM_PROGRAM=${TERM_PROGRAM}")
|
||||
else
|
||||
ssh_exported_vars+=("TERM_PROGRAM")
|
||||
fi
|
||||
export "TERM_PROGRAM=ghostty"
|
||||
ssh_opts+=(-o "SendEnv TERM_PROGRAM")
|
||||
|
||||
if [[ -n "$TERM_PROGRAM_VERSION" ]]; then
|
||||
if [[ -n "${TERM_PROGRAM_VERSION+x}" ]]; then
|
||||
ssh_exported_vars+=("TERM_PROGRAM_VERSION=${TERM_PROGRAM_VERSION}")
|
||||
else
|
||||
ssh_exported_vars+=("TERM_PROGRAM_VERSION")
|
||||
fi
|
||||
ssh_opts+=(-o "SendEnv TERM_PROGRAM_VERSION")
|
||||
fi
|
||||
|
||||
ssh_env+=(
|
||||
"COLORTERM=truecolor"
|
||||
"TERM_PROGRAM=ghostty"
|
||||
)
|
||||
[[ -n "$TERM_PROGRAM_VERSION" ]] && ssh_env_vars+=("TERM_PROGRAM_VERSION=$TERM_PROGRAM_VERSION")
|
||||
|
||||
# Temporarily export variables for SSH transmission
|
||||
local -a ssh_exported_vars=()
|
||||
local ssh_v ssh_var_name
|
||||
for ssh_v in "${ssh_env_vars[@]}"; do
|
||||
ssh_var_name="${ssh_v%%=*}"
|
||||
|
||||
if [[ -n "${(P)ssh_var_name+x}" ]]; then
|
||||
ssh_exported_vars+=("$ssh_var_name=${(P)ssh_var_name}")
|
||||
else
|
||||
ssh_exported_vars+=("$ssh_var_name")
|
||||
fi
|
||||
|
||||
export "${ssh_v}"
|
||||
|
||||
# Use both SendEnv and SetEnv for maximum compatibility
|
||||
ssh_opts+=(-o "SendEnv $ssh_var_name")
|
||||
ssh_opts+=(-o "SetEnv $ssh_v")
|
||||
done
|
||||
|
||||
ssh_env+=("${ssh_env_vars[@]}")
|
||||
[[ -n "$TERM_PROGRAM_VERSION" ]] && ssh_env+=("TERM_PROGRAM_VERSION=$TERM_PROGRAM_VERSION")
|
||||
fi
|
||||
|
||||
# Install terminfo on remote host if needed
|
||||
if [[ "$GHOSTTY_SHELL_FEATURES" =~ ssh-terminfo ]]; then
|
||||
local ssh_config ssh_user ssh_hostname ssh_target
|
||||
local ssh_config ssh_user ssh_hostname
|
||||
ssh_config=$(command ssh -G "$@" 2>/dev/null)
|
||||
ssh_user=$(printf '%s\n' "${(@f)ssh_config}" | while IFS=' ' read -r ssh_key ssh_value; do
|
||||
[[ "$ssh_key" == "user" ]] && printf '%s\n' "$ssh_value" && break
|
||||
done)
|
||||
ssh_hostname=$(printf '%s\n' "${(@f)ssh_config}" | while IFS=' ' read -r ssh_key ssh_value; do
|
||||
[[ "$ssh_key" == "hostname" ]] && printf '%s\n' "$ssh_value" && break
|
||||
done)
|
||||
|
||||
while IFS=' ' read -r ssh_key ssh_value; do
|
||||
case "$ssh_key" in
|
||||
user) ssh_user="$ssh_value" ;;
|
||||
hostname) ssh_hostname="$ssh_value" ;;
|
||||
esac
|
||||
[[ -n "$ssh_user" && -n "$ssh_hostname" ]] && break
|
||||
done <<< "$ssh_config"
|
||||
|
||||
ssh_target="${ssh_user}@${ssh_hostname}"
|
||||
|
||||
if [[ -n "$ssh_hostname" ]]; then
|
||||
# Detect timeout command (BSD compatibility)
|
||||
local ssh_timeout_cmd=""
|
||||
if (( $+commands[timeout] )); then
|
||||
ssh_timeout_cmd="timeout"
|
||||
elif (( $+commands[gtimeout] )); then
|
||||
ssh_timeout_cmd="gtimeout"
|
||||
fi
|
||||
|
||||
# Check if terminfo is already cached
|
||||
local ssh_cache_check_success=false
|
||||
if (( $+commands[ghostty] )); then
|
||||
if [[ -n "$ssh_timeout_cmd" ]]; then
|
||||
$ssh_timeout_cmd "${GHOSTTY_SSH_CHECK_TIMEOUT}s" ghostty +ssh-cache --host="$ssh_target" >/dev/null 2>&1 && ssh_cache_check_success=true
|
||||
else
|
||||
ghostty +ssh-cache --host="$ssh_target" >/dev/null 2>&1 && ssh_cache_check_success=true
|
||||
fi
|
||||
ghostty +ssh-cache --host="$ssh_target" >/dev/null 2>&1 && ssh_cache_check_success=true
|
||||
fi
|
||||
|
||||
if [[ "$ssh_cache_check_success" == "true" ]]; then
|
||||
ssh_env+=(TERM=xterm-ghostty)
|
||||
elif (( $+commands[infocmp] )); then
|
||||
local ssh_terminfo
|
||||
|
||||
# Generate terminfo data (BSD base64 compatibility)
|
||||
if base64 --help 2>&1 | grep -q GNU; then
|
||||
ssh_terminfo=$(infocmp -0 -Q2 -q xterm-ghostty 2>/dev/null | base64 -w0 2>/dev/null)
|
||||
if ! (( $+commands[base64] )); then
|
||||
print "Warning: base64 command not available for terminfo installation." >&2
|
||||
ssh_env+=(TERM=xterm-256color)
|
||||
else
|
||||
ssh_terminfo=$(infocmp -0 -Q2 -q xterm-ghostty 2>/dev/null | base64 2>/dev/null | tr -d '\n')
|
||||
fi
|
||||
local ssh_terminfo ssh_base64_decode_cmd
|
||||
|
||||
if [[ -n "$ssh_terminfo" ]]; then
|
||||
print "Setting up Ghostty terminfo on remote host..." >&2
|
||||
local ssh_cpath_dir ssh_cpath
|
||||
|
||||
ssh_cpath_dir=$(mktemp -d "/tmp/ghostty-ssh-$ssh_user.XXXXXX" 2>/dev/null) || ssh_cpath_dir="/tmp/ghostty-ssh-$ssh_user.$$"
|
||||
ssh_cpath="$ssh_cpath_dir/socket"
|
||||
|
||||
local ssh_base64_decode_cmd
|
||||
# BSD vs GNU base64 compatibility
|
||||
if base64 --help 2>&1 | grep -q GNU; then
|
||||
ssh_base64_decode_cmd="base64 -d"
|
||||
ssh_terminfo=$(infocmp -0 -Q2 -q xterm-ghostty 2>/dev/null | base64 -w0 2>/dev/null)
|
||||
else
|
||||
ssh_base64_decode_cmd="base64 -D"
|
||||
ssh_terminfo=$(infocmp -0 -Q2 -q xterm-ghostty 2>/dev/null | base64 2>/dev/null | tr -d '\n')
|
||||
fi
|
||||
|
||||
if print "$ssh_terminfo" | $ssh_base64_decode_cmd | command ssh "${ssh_opts[@]}" -o ControlMaster=yes -o ControlPath="$ssh_cpath" -o ControlPersist=60s "$@" '
|
||||
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
|
||||
' 2>/dev/null; then
|
||||
print "Terminfo setup complete." >&2
|
||||
ssh_env+=(TERM=xterm-ghostty)
|
||||
ssh_opts+=(-o "ControlPath=$ssh_cpath")
|
||||
if [[ -n "$ssh_terminfo" ]]; then
|
||||
print "Setting up Ghostty terminfo on $ssh_hostname..." >&2
|
||||
local ssh_cpath_dir ssh_cpath
|
||||
|
||||
# Cache successful installation
|
||||
if [[ -n "$ssh_target" ]] && (( $+commands[ghostty] )); then
|
||||
{
|
||||
if [[ -n "$ssh_timeout_cmd" ]]; then
|
||||
$ssh_timeout_cmd "${GHOSTTY_SSH_CACHE_TIMEOUT}s" ghostty +ssh-cache --add="$ssh_target" >/dev/null 2>&1 || true
|
||||
else
|
||||
ssh_cpath_dir=$(mktemp -d "/tmp/ghostty-ssh-$ssh_user.XXXXXX" 2>/dev/null) || ssh_cpath_dir="/tmp/ghostty-ssh-$ssh_user.$$"
|
||||
ssh_cpath="$ssh_cpath_dir/socket"
|
||||
|
||||
if print "$ssh_terminfo" | $ssh_base64_decode_cmd | command ssh "${ssh_opts[@]}" -o ControlMaster=yes -o ControlPath="$ssh_cpath" -o ControlPersist=60s "$@" '
|
||||
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
|
||||
' 2>/dev/null; then
|
||||
print "Terminfo setup complete on $ssh_hostname." >&2
|
||||
ssh_env+=(TERM=xterm-ghostty)
|
||||
ssh_opts+=(-o "ControlPath=$ssh_cpath")
|
||||
|
||||
# Cache successful installation
|
||||
if [[ -n "$ssh_target" ]] && (( $+commands[ghostty] )); then
|
||||
{
|
||||
ghostty +ssh-cache --add="$ssh_target" >/dev/null 2>&1 || true
|
||||
fi
|
||||
} &!
|
||||
} &!
|
||||
fi
|
||||
else
|
||||
print "Warning: Failed to install terminfo." >&2
|
||||
ssh_env+=(TERM=xterm-256color)
|
||||
fi
|
||||
else
|
||||
print "Warning: Failed to install terminfo." >&2
|
||||
print "Warning: Could not generate terminfo data." >&2
|
||||
ssh_env+=(TERM=xterm-256color)
|
||||
fi
|
||||
else
|
||||
print "Warning: Could not generate terminfo data." >&2
|
||||
ssh_env+=(TERM=xterm-256color)
|
||||
fi
|
||||
else
|
||||
print "Warning: ghostty command not available for cache management." >&2
|
||||
@@ -380,21 +364,35 @@ _ghostty_deferred_init() {
|
||||
fi
|
||||
fi
|
||||
|
||||
# Ensure TERM is set when using ssh-env feature
|
||||
if [[ "$GHOSTTY_SHELL_FEATURES" =~ ssh-env ]]; then
|
||||
local ssh_term_set=false ssh_v
|
||||
for ssh_v in "${ssh_env[@]}"; do
|
||||
[[ "$ssh_v" =~ ^TERM= ]] && ssh_term_set=true && break
|
||||
done
|
||||
[[ "$ssh_term_set" == "false" && "$TERM" == "xterm-ghostty" ]] && ssh_env+=(TERM=xterm-256color)
|
||||
# Execute SSH with environment handling
|
||||
local ssh_term_override=""
|
||||
local ssh_v
|
||||
for ssh_v in "${ssh_env[@]}"; do
|
||||
if [[ "$ssh_v" =~ ^TERM=(.*)$ ]]; then
|
||||
ssh_term_override="${match[1]}"
|
||||
break
|
||||
fi
|
||||
done
|
||||
|
||||
if [[ "$GHOSTTY_SHELL_FEATURES" =~ ssh-env && -z "$ssh_term_override" ]]; then
|
||||
ssh_env+=(TERM=xterm-256color)
|
||||
ssh_term_override="xterm-256color"
|
||||
fi
|
||||
|
||||
command ssh "${ssh_opts[@]}" "$@"
|
||||
local ssh_ret=$?
|
||||
local ssh_ret
|
||||
if [[ -n "$ssh_term_override" ]]; then
|
||||
local ssh_original_term="$TERM"
|
||||
export TERM="$ssh_term_override"
|
||||
command ssh "${ssh_opts[@]}" "$@"
|
||||
ssh_ret=$?
|
||||
export TERM="$ssh_original_term"
|
||||
else
|
||||
command ssh "${ssh_opts[@]}" "$@"
|
||||
ssh_ret=$?
|
||||
fi
|
||||
|
||||
# Restore original environment variables
|
||||
if [[ "$GHOSTTY_SHELL_FEATURES" =~ ssh-env ]]; then
|
||||
local ssh_v
|
||||
for ssh_v in "${ssh_exported_vars[@]}"; do
|
||||
if [[ "$ssh_v" == *=* ]]; then
|
||||
export "${ssh_v}"
|
||||
|
Reference in New Issue
Block a user