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)pull/7608/head
parent
5ec18f426c
commit
a22074a85c
|
|
@ -97,131 +97,116 @@ fi
|
|||
|
||||
# SSH Integration
|
||||
if [[ "$GHOSTTY_SHELL_FEATURES" =~ ssh-(env|terminfo) ]]; then
|
||||
: "${GHOSTTY_SSH_CACHE_TIMEOUT:=5}"
|
||||
: "${GHOSTTY_SSH_CHECK_TIMEOUT:=3}"
|
||||
|
||||
# SSH wrapper that preserves Ghostty features across remote connections
|
||||
ssh() {
|
||||
local ssh_env=() ssh_opts=()
|
||||
builtin 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
|
||||
builtin 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"
|
||||
)
|
||||
if [[ -n "$TERM_PROGRAM_VERSION" ]]; then
|
||||
ssh_env_vars+=("TERM_PROGRAM_VERSION=$TERM_PROGRAM_VERSION")
|
||||
ssh_env+=("TERM_PROGRAM_VERSION=$TERM_PROGRAM_VERSION")
|
||||
fi
|
||||
|
||||
# Temporarily export variables for SSH transmission
|
||||
local -a ssh_exported_vars=()
|
||||
for ssh_v in "${ssh_env_vars[@]}"; do
|
||||
local ssh_var_name="${ssh_v%%=*}"
|
||||
|
||||
if [[ -n "${!ssh_var_name+x}" ]]; then
|
||||
ssh_exported_vars+=("$ssh_var_name=${!ssh_var_name}")
|
||||
else
|
||||
ssh_exported_vars+=("$ssh_var_name")
|
||||
fi
|
||||
|
||||
builtin 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[@]}")
|
||||
fi
|
||||
|
||||
# Install terminfo on remote host if needed
|
||||
if [[ "$GHOSTTY_SHELL_FEATURES" =~ ssh-terminfo ]]; then
|
||||
builtin local ssh_config ssh_user ssh_hostname
|
||||
ssh_config=$(builtin command ssh -G "$@" 2>/dev/null)
|
||||
ssh_user=$(echo "$ssh_config" | while IFS=' ' read -r ssh_key ssh_value; do
|
||||
[[ "$ssh_key" == "ssh_user" ]] && echo "$ssh_value" && break
|
||||
done)
|
||||
ssh_hostname=$(echo "$ssh_config" | while IFS=' ' read -r ssh_key ssh_value; do
|
||||
[[ "$ssh_key" == "hostname" ]] && echo "$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 command -v timeout >/dev/null 2>&1; then
|
||||
ssh_timeout_cmd="timeout"
|
||||
elif command -v gtimeout >/dev/null 2>&1; then
|
||||
ssh_timeout_cmd="gtimeout"
|
||||
fi
|
||||
|
||||
# Check if terminfo is already cached
|
||||
local ssh_cache_check_success=false
|
||||
if command -v ghostty >/dev/null 2>&1; 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
|
||||
builtin local ssh_cache_check_success=false
|
||||
if builtin command -v ghostty >/dev/null 2>&1; then
|
||||
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 builtin command -v infocmp >/dev/null 2>&1; then
|
||||
builtin 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 ! builtin command -v base64 >/dev/null 2>&1; then
|
||||
builtin echo "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
|
||||
builtin local ssh_terminfo ssh_base64_decode_cmd
|
||||
|
||||
if [[ -n "$ssh_terminfo" ]]; then
|
||||
builtin echo "Setting up Ghostty terminfo on remote host..." >&2
|
||||
builtin 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 builtin echo "$ssh_terminfo" | $ssh_base64_decode_cmd | builtin 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
|
||||
builtin echo "Terminfo setup complete." >&2
|
||||
ssh_env+=(TERM=xterm-ghostty)
|
||||
ssh_opts+=(-o "ControlPath=$ssh_cpath")
|
||||
if [[ -n "$ssh_terminfo" ]]; then
|
||||
builtin echo "Setting up Ghostty terminfo on $ssh_hostname..." >&2
|
||||
builtin local ssh_cpath_dir ssh_cpath
|
||||
|
||||
# Cache successful installation
|
||||
if [[ -n "$ssh_target" ]] && command -v ghostty >/dev/null 2>&1; then
|
||||
(
|
||||
set +m
|
||||
{
|
||||
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 builtin echo "$ssh_terminfo" | $ssh_base64_decode_cmd | builtin 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
|
||||
builtin echo "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" ]] && builtin command -v ghostty >/dev/null 2>&1; then
|
||||
(
|
||||
set +m
|
||||
{
|
||||
ghostty +ssh-cache --add="$ssh_target" >/dev/null 2>&1 || true
|
||||
fi
|
||||
} &
|
||||
)
|
||||
} &
|
||||
)
|
||||
fi
|
||||
else
|
||||
builtin echo "Warning: Failed to install terminfo." >&2
|
||||
ssh_env+=(TERM=xterm-256color)
|
||||
fi
|
||||
else
|
||||
builtin echo "Warning: Failed to install terminfo." >&2
|
||||
builtin echo "Warning: Could not generate terminfo data." >&2
|
||||
ssh_env+=(TERM=xterm-256color)
|
||||
fi
|
||||
else
|
||||
builtin echo "Warning: Could not generate terminfo data." >&2
|
||||
ssh_env+=(TERM=xterm-256color)
|
||||
fi
|
||||
else
|
||||
builtin echo "Warning: ghostty command not available for cache management." >&2
|
||||
|
|
@ -234,22 +219,30 @@ if [[ "$GHOSTTY_SHELL_FEATURES" =~ ssh-(env|terminfo) ]]; then
|
|||
fi
|
||||
fi
|
||||
|
||||
# Ensure TERM is set when using ssh-env feature
|
||||
if [[ "$GHOSTTY_SHELL_FEATURES" =~ ssh-env ]]; then
|
||||
local ssh_term_set=false
|
||||
for ssh_v in "${ssh_env[@]}"; do
|
||||
if [[ "$ssh_v" =~ ^TERM= ]]; then
|
||||
ssh_term_set=true
|
||||
break
|
||||
fi
|
||||
done
|
||||
if [[ "$ssh_term_set" == "false" && "$TERM" == "xterm-ghostty" ]]; then
|
||||
ssh_env+=(TERM=xterm-256color)
|
||||
# Execute SSH with environment handling
|
||||
builtin local ssh_term_override=""
|
||||
for ssh_v in "${ssh_env[@]}"; do
|
||||
if [[ "$ssh_v" =~ ^TERM=(.*)$ ]]; then
|
||||
ssh_term_override="${BASH_REMATCH[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
|
||||
|
||||
builtin command ssh "${ssh_opts[@]}" "$@"
|
||||
local ssh_ret=$?
|
||||
if [[ -n "$ssh_term_override" ]]; then
|
||||
builtin local ssh_original_term="$TERM"
|
||||
builtin export TERM="$ssh_term_override"
|
||||
builtin command ssh "${ssh_opts[@]}" "$@"
|
||||
local ssh_ret=$?
|
||||
builtin export TERM="$ssh_original_term"
|
||||
else
|
||||
builtin command ssh "${ssh_opts[@]}" "$@"
|
||||
local ssh_ret=$?
|
||||
fi
|
||||
|
||||
# Restore original environment variables
|
||||
if [[ "$GHOSTTY_SHELL_FEATURES" =~ ssh-env ]]; then
|
||||
|
|
|
|||
|
|
@ -100,50 +100,41 @@
|
|||
|
||||
# SSH Integration
|
||||
use str
|
||||
use re
|
||||
|
||||
if (or (str:contains $E:GHOSTTY_SHELL_FEATURES ssh-env) (str:contains $E:GHOSTTY_SHELL_FEATURES ssh-terminfo)) {
|
||||
var GHOSTTY_SSH_CACHE_TIMEOUT = (if (has-env GHOSTTY_SSH_CACHE_TIMEOUT) { echo $E:GHOSTTY_SSH_CACHE_TIMEOUT } else { echo 5 })
|
||||
var GHOSTTY_SSH_CHECK_TIMEOUT = (if (has-env GHOSTTY_SSH_CHECK_TIMEOUT) { echo $E:GHOSTTY_SSH_CHECK_TIMEOUT } else { echo 3 })
|
||||
|
||||
# SSH wrapper that preserves Ghostty features across remote connections
|
||||
fn ssh {|@args|
|
||||
var ssh-env = []
|
||||
var ssh-opts = []
|
||||
var ssh-exported-vars = []
|
||||
|
||||
# Configure environment variables for remote session
|
||||
if (str:contains $E:GHOSTTY_SHELL_FEATURES ssh-env) {
|
||||
var ssh-env-vars = [
|
||||
COLORTERM=truecolor
|
||||
TERM_PROGRAM=ghostty
|
||||
]
|
||||
set ssh-opts = [$@ssh-opts -o "SetEnv COLORTERM=truecolor"]
|
||||
|
||||
if (has-env TERM_PROGRAM) {
|
||||
set ssh-exported-vars = [$@ssh-exported-vars "TERM_PROGRAM="$E:TERM_PROGRAM]
|
||||
} else {
|
||||
set ssh-exported-vars = [$@ssh-exported-vars "TERM_PROGRAM"]
|
||||
}
|
||||
set-env TERM_PROGRAM ghostty
|
||||
set ssh-opts = [$@ssh-opts -o "SendEnv TERM_PROGRAM"]
|
||||
|
||||
if (has-env TERM_PROGRAM_VERSION) {
|
||||
set ssh-env-vars = [$@ssh-env-vars TERM_PROGRAM_VERSION=$E:TERM_PROGRAM_VERSION]
|
||||
}
|
||||
|
||||
# Store original values for restoration
|
||||
var ssh-exported-vars = []
|
||||
for ssh-v $ssh-env-vars {
|
||||
var ssh-var-name = (str:split &max=2 = $ssh-v)[0]
|
||||
|
||||
if (has-env $ssh-var-name) {
|
||||
var original-value = (get-env $ssh-var-name)
|
||||
set ssh-exported-vars = [$@ssh-exported-vars $ssh-var-name=$original-value]
|
||||
if (has-env TERM_PROGRAM_VERSION) {
|
||||
set ssh-exported-vars = [$@ssh-exported-vars "TERM_PROGRAM_VERSION="$E:TERM_PROGRAM_VERSION]
|
||||
} else {
|
||||
set ssh-exported-vars = [$@ssh-exported-vars $ssh-var-name]
|
||||
set ssh-exported-vars = [$@ssh-exported-vars "TERM_PROGRAM_VERSION"]
|
||||
}
|
||||
|
||||
# Export the variable
|
||||
var ssh-var-parts = (str:split &max=2 = $ssh-v)
|
||||
set-env $ssh-var-parts[0] $ssh-var-parts[1]
|
||||
|
||||
# Use both SendEnv and SetEnv for maximum compatibility
|
||||
set ssh-opts = [$@ssh-opts -o "SendEnv "$ssh-var-name]
|
||||
set ssh-opts = [$@ssh-opts -o "SetEnv "$ssh-v]
|
||||
set ssh-opts = [$@ssh-opts -o "SendEnv TERM_PROGRAM_VERSION"]
|
||||
}
|
||||
|
||||
set ssh-env = [$@ssh-env $@ssh-env-vars]
|
||||
set ssh-env = [
|
||||
"COLORTERM=truecolor"
|
||||
"TERM_PROGRAM=ghostty"
|
||||
]
|
||||
if (has-env TERM_PROGRAM_VERSION) {
|
||||
set ssh-env = [$@ssh-env "TERM_PROGRAM_VERSION="$E:TERM_PROGRAM_VERSION]
|
||||
}
|
||||
}
|
||||
|
||||
# Install terminfo on remote host if needed
|
||||
|
|
@ -160,52 +151,28 @@
|
|||
|
||||
for line (str:split "\n" $ssh-config) {
|
||||
var parts = (str:split " " $line)
|
||||
if (and (> (count $parts) 1) (eq $parts[0] user)) {
|
||||
set ssh-user = $parts[1]
|
||||
}
|
||||
if (and (> (count $parts) 1) (eq $parts[0] hostname)) {
|
||||
set ssh-hostname = $parts[1]
|
||||
if (> (count $parts) 1) {
|
||||
if (eq $parts[0] user) {
|
||||
set ssh-user = $parts[1]
|
||||
} elif (eq $parts[0] hostname) {
|
||||
set ssh-hostname = $parts[1]
|
||||
}
|
||||
if (and (not-eq $ssh-user "") (not-eq $ssh-hostname "")) {
|
||||
break
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
var ssh-target = $ssh-user"@"$ssh-hostname
|
||||
|
||||
if (not-eq $ssh-hostname "") {
|
||||
# Detect timeout command (BSD compatibility)
|
||||
var ssh-timeout-cmd = ""
|
||||
try {
|
||||
external timeout --help >/dev/null 2>&1
|
||||
set ssh-timeout-cmd = timeout
|
||||
} catch {
|
||||
try {
|
||||
external gtimeout --help >/dev/null 2>&1
|
||||
set ssh-timeout-cmd = gtimeout
|
||||
} catch {
|
||||
# no timeout command available
|
||||
}
|
||||
}
|
||||
|
||||
# Check if terminfo is already cached
|
||||
var ssh-cache-check-success = $false
|
||||
try {
|
||||
external ghostty --help >/dev/null 2>&1
|
||||
if (not-eq $ssh-timeout-cmd "") {
|
||||
try {
|
||||
external $ssh-timeout-cmd $GHOSTTY_SSH_CHECK_TIMEOUT"s" ghostty +ssh-cache --host=$ssh-target >/dev/null 2>&1
|
||||
set ssh-cache-check-success = $true
|
||||
} catch {
|
||||
# cache check failed
|
||||
}
|
||||
} else {
|
||||
try {
|
||||
external ghostty +ssh-cache --host=$ssh-target >/dev/null 2>&1
|
||||
set ssh-cache-check-success = $true
|
||||
} catch {
|
||||
# cache check failed
|
||||
}
|
||||
}
|
||||
external ghostty +ssh-cache --host=$ssh-target >/dev/null 2>&1
|
||||
set ssh-cache-check-success = $true
|
||||
} catch {
|
||||
# ghostty not available
|
||||
# cache check failed
|
||||
}
|
||||
|
||||
if $ssh-cache-check-success {
|
||||
|
|
@ -213,74 +180,68 @@
|
|||
} else {
|
||||
try {
|
||||
external infocmp --help >/dev/null 2>&1
|
||||
|
||||
# Generate terminfo data (BSD base64 compatibility)
|
||||
var ssh-terminfo = ""
|
||||
|
||||
try {
|
||||
var base64-help = (external base64 --help 2>&1 | slurp)
|
||||
if (str:contains $base64-help GNU) {
|
||||
set ssh-terminfo = (external infocmp -0 -Q2 -q xterm-ghostty 2>/dev/null | external base64 -w0 2>/dev/null | slurp)
|
||||
} else {
|
||||
set ssh-terminfo = (external infocmp -0 -Q2 -q xterm-ghostty 2>/dev/null | external base64 2>/dev/null | external tr -d '\n' | slurp)
|
||||
}
|
||||
} catch {
|
||||
set ssh-terminfo = ""
|
||||
}
|
||||
|
||||
if (not-eq $ssh-terminfo "") {
|
||||
echo "Setting up Ghostty terminfo on remote host..." >&2
|
||||
var ssh-cpath-dir = ""
|
||||
try {
|
||||
set ssh-cpath-dir = (external mktemp -d "/tmp/ghostty-ssh-"$ssh-user".XXXXXX" 2>/dev/null | slurp)
|
||||
} catch {
|
||||
set ssh-cpath-dir = "/tmp/ghostty-ssh-"$ssh-user"."(randint 10000 99999)
|
||||
}
|
||||
var ssh-cpath = $ssh-cpath-dir"/socket"
|
||||
external base64 --help >/dev/null 2>&1
|
||||
|
||||
# Generate terminfo data (BSD base64 compatibility)
|
||||
var ssh-terminfo = ""
|
||||
var ssh-base64-decode-cmd = ""
|
||||
try {
|
||||
var base64-help = (external base64 --help 2>&1 | slurp)
|
||||
if (str:contains $base64-help GNU) {
|
||||
set ssh-base64-decode-cmd = "base64 -d"
|
||||
set ssh-terminfo = (external infocmp -0 -Q2 -q xterm-ghostty 2>/dev/null | external base64 -w0 2>/dev/null | slurp)
|
||||
} else {
|
||||
set ssh-base64-decode-cmd = "base64 -D"
|
||||
set ssh-terminfo = (external infocmp -0 -Q2 -q xterm-ghostty 2>/dev/null | external base64 2>/dev/null | external tr -d '\n' | slurp)
|
||||
}
|
||||
} catch {
|
||||
set ssh-base64-decode-cmd = "base64 -d"
|
||||
set ssh-terminfo = ""
|
||||
}
|
||||
|
||||
var terminfo-install-success = $false
|
||||
try {
|
||||
echo $ssh-terminfo | external sh -c $ssh-base64-decode-cmd | external ssh $@ssh-opts -o ControlMaster=yes -o ControlPath=$ssh-cpath -o ControlPersist=60s $@args '
|
||||
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
|
||||
' >/dev/null 2>&1
|
||||
set terminfo-install-success = $true
|
||||
} catch {
|
||||
set terminfo-install-success = $false
|
||||
}
|
||||
if (not-eq $ssh-terminfo "") {
|
||||
echo "Setting up Ghostty terminfo on "$ssh-hostname"..." >&2
|
||||
var ssh-cpath-dir = ""
|
||||
try {
|
||||
set ssh-cpath-dir = (external mktemp -d "/tmp/ghostty-ssh-"$ssh-user".XXXXXX" 2>/dev/null | slurp)
|
||||
} catch {
|
||||
set ssh-cpath-dir = "/tmp/ghostty-ssh-"$ssh-user"."(randint 10000 99999)
|
||||
}
|
||||
var ssh-cpath = $ssh-cpath-dir"/socket"
|
||||
|
||||
if $terminfo-install-success {
|
||||
echo "Terminfo setup complete." >&2
|
||||
set ssh-env = [$@ssh-env TERM=xterm-ghostty]
|
||||
set ssh-opts = [$@ssh-opts -o ControlPath=$ssh-cpath]
|
||||
var terminfo-install-success = $false
|
||||
try {
|
||||
echo $ssh-terminfo | external sh -c $ssh-base64-decode-cmd | external ssh $@ssh-opts -o ControlMaster=yes -o ControlPath=$ssh-cpath -o ControlPersist=60s $@args '
|
||||
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
|
||||
' >/dev/null 2>&1
|
||||
set terminfo-install-success = $true
|
||||
} catch {
|
||||
set terminfo-install-success = $false
|
||||
}
|
||||
|
||||
# Cache successful installation
|
||||
if (and (not-eq $ssh-target "") (has-external ghostty)) {
|
||||
if (not-eq $ssh-timeout-cmd "") {
|
||||
external $ssh-timeout-cmd $GHOSTTY_SSH_CACHE_TIMEOUT"s" ghostty +ssh-cache --add=$ssh-target >/dev/null 2>&1 &
|
||||
} else {
|
||||
if $terminfo-install-success {
|
||||
echo "Terminfo setup complete on "$ssh-hostname"." >&2
|
||||
set ssh-env = [$@ssh-env TERM=xterm-ghostty]
|
||||
set ssh-opts = [$@ssh-opts -o ControlPath=$ssh-cpath]
|
||||
|
||||
# Cache successful installation
|
||||
if (and (not-eq $ssh-target "") (has-external ghostty)) {
|
||||
external ghostty +ssh-cache --add=$ssh-target >/dev/null 2>&1 &
|
||||
}
|
||||
} else {
|
||||
echo "Warning: Failed to install terminfo." >&2
|
||||
set ssh-env = [$@ssh-env TERM=xterm-256color]
|
||||
}
|
||||
} else {
|
||||
echo "Warning: Failed to install terminfo." >&2
|
||||
echo "Warning: Could not generate terminfo data." >&2
|
||||
set ssh-env = [$@ssh-env TERM=xterm-256color]
|
||||
}
|
||||
} else {
|
||||
echo "Warning: Could not generate terminfo data." >&2
|
||||
} catch {
|
||||
echo "Warning: base64 command not available for terminfo installation." >&2
|
||||
set ssh-env = [$@ssh-env TERM=xterm-256color]
|
||||
}
|
||||
} catch {
|
||||
|
|
@ -295,25 +256,36 @@
|
|||
}
|
||||
}
|
||||
|
||||
# Ensure TERM is set when using ssh-env feature
|
||||
if (str:contains $E:GHOSTTY_SHELL_FEATURES ssh-env) {
|
||||
var ssh-term-set = $false
|
||||
for ssh-v $ssh-env {
|
||||
if (str:has-prefix $ssh-v TERM=) {
|
||||
set ssh-term-set = $true
|
||||
break
|
||||
}
|
||||
}
|
||||
if (and (not $ssh-term-set) (eq $E:TERM xterm-ghostty)) {
|
||||
set ssh-env = [$@ssh-env TERM=xterm-256color]
|
||||
# Execute SSH with environment handling
|
||||
var ssh-term-override = ""
|
||||
for ssh-v $ssh-env {
|
||||
if (str:has-prefix $ssh-v TERM=) {
|
||||
set ssh-term-override = (str:trim-prefix $ssh-v TERM=)
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
if (and (str:contains $E:GHOSTTY_SHELL_FEATURES ssh-env) (eq $ssh-term-override "")) {
|
||||
set ssh-env = [$@ssh-env TERM=xterm-256color]
|
||||
set ssh-term-override = xterm-256color
|
||||
}
|
||||
|
||||
var ssh-ret = 0
|
||||
try {
|
||||
external ssh $@ssh-opts $@args
|
||||
} catch e {
|
||||
set ssh-ret = $e[reason][exit-status]
|
||||
if (not-eq $ssh-term-override "") {
|
||||
var ssh-original-term = $E:TERM
|
||||
set-env TERM $ssh-term-override
|
||||
try {
|
||||
external ssh $@ssh-opts $@args
|
||||
} catch e {
|
||||
set ssh-ret = $e[reason][exit-status]
|
||||
}
|
||||
set-env TERM $ssh-original-term
|
||||
} else {
|
||||
try {
|
||||
external ssh $@ssh-opts $@args
|
||||
} catch e {
|
||||
set ssh-ret = $e[reason][exit-status]
|
||||
}
|
||||
}
|
||||
|
||||
# Restore original environment variables
|
||||
|
|
|
|||
|
|
@ -86,132 +86,119 @@ function __ghostty_setup --on-event fish_prompt -d "Setup ghostty integration"
|
|||
end
|
||||
end
|
||||
|
||||
# SSH Integration for Fish Shell
|
||||
# SSH Integration
|
||||
if string match -q '*ssh-env*' -- "$GHOSTTY_SHELL_FEATURES"; or string match -q '*ssh-terminfo*' -- "$GHOSTTY_SHELL_FEATURES"
|
||||
set -g GHOSTTY_SSH_CACHE_TIMEOUT (test -n "$GHOSTTY_SSH_CACHE_TIMEOUT"; and echo $GHOSTTY_SSH_CACHE_TIMEOUT; or echo 5)
|
||||
set -g GHOSTTY_SSH_CHECK_TIMEOUT (test -n "$GHOSTTY_SSH_CHECK_TIMEOUT"; and echo $GHOSTTY_SSH_CHECK_TIMEOUT; or echo 3)
|
||||
|
||||
# SSH wrapper that preserves Ghostty features across remote connections
|
||||
function ssh --wraps=ssh --description "SSH wrapper with Ghostty integration"
|
||||
set -l ssh_env
|
||||
set -l ssh_opts
|
||||
set -l ssh_exported_vars
|
||||
|
||||
# Configure environment variables for remote session
|
||||
if string match -q '*ssh-env*' -- "$GHOSTTY_SHELL_FEATURES"
|
||||
set -l ssh_env_vars \
|
||||
"COLORTERM=truecolor" \
|
||||
"TERM_PROGRAM=ghostty"
|
||||
|
||||
set -a ssh_opts -o "SetEnv COLORTERM=truecolor"
|
||||
|
||||
if set -q TERM_PROGRAM
|
||||
set -a ssh_exported_vars "TERM_PROGRAM=$TERM_PROGRAM"
|
||||
else
|
||||
set -a ssh_exported_vars "TERM_PROGRAM"
|
||||
end
|
||||
set -gx TERM_PROGRAM ghostty
|
||||
set -a ssh_opts -o "SendEnv TERM_PROGRAM"
|
||||
|
||||
if test -n "$TERM_PROGRAM_VERSION"
|
||||
set -a ssh_env_vars "TERM_PROGRAM_VERSION=$TERM_PROGRAM_VERSION"
|
||||
end
|
||||
|
||||
# Store original values for restoration
|
||||
set -l ssh_exported_vars
|
||||
for ssh_v in $ssh_env_vars
|
||||
set -l ssh_var_name (string split -m1 '=' -- $ssh_v)[1]
|
||||
|
||||
if set -q $ssh_var_name
|
||||
set -a ssh_exported_vars "$ssh_var_name="(eval echo \$$ssh_var_name)
|
||||
if set -q TERM_PROGRAM_VERSION
|
||||
set -a ssh_exported_vars "TERM_PROGRAM_VERSION=$TERM_PROGRAM_VERSION"
|
||||
else
|
||||
set -a ssh_exported_vars $ssh_var_name
|
||||
set -a ssh_exported_vars "TERM_PROGRAM_VERSION"
|
||||
end
|
||||
|
||||
# Export the variable
|
||||
set -gx (string split -m1 '=' -- $ssh_v)
|
||||
|
||||
# Use both SendEnv and SetEnv for maximum compatibility
|
||||
set -a ssh_opts -o "SendEnv $ssh_var_name"
|
||||
set -a ssh_opts -o "SetEnv $ssh_v"
|
||||
set -a ssh_opts -o "SendEnv TERM_PROGRAM_VERSION"
|
||||
end
|
||||
|
||||
set -a ssh_env $ssh_env_vars
|
||||
set -a ssh_env "COLORTERM=truecolor"
|
||||
set -a ssh_env "TERM_PROGRAM=ghostty"
|
||||
if test -n "$TERM_PROGRAM_VERSION"
|
||||
set -a ssh_env "TERM_PROGRAM_VERSION=$TERM_PROGRAM_VERSION"
|
||||
end
|
||||
end
|
||||
|
||||
# Install terminfo on remote host if needed
|
||||
if string match -q '*ssh-terminfo*' -- "$GHOSTTY_SHELL_FEATURES"
|
||||
set -l ssh_config (command ssh -G $argv 2>/dev/null)
|
||||
set -l ssh_user (echo $ssh_config | while read -l ssh_key ssh_value
|
||||
test "$ssh_key" = "user"; and echo $ssh_value; and break
|
||||
end)
|
||||
set -l ssh_hostname (echo $ssh_config | while read -l ssh_key ssh_value
|
||||
test "$ssh_key" = "hostname"; and echo $ssh_value; and break
|
||||
end)
|
||||
set -l ssh_user
|
||||
set -l ssh_hostname
|
||||
|
||||
for line in $ssh_config
|
||||
set -l parts (string split ' ' -- $line)
|
||||
if test (count $parts) -ge 2
|
||||
switch $parts[1]
|
||||
case user
|
||||
set ssh_user $parts[2]
|
||||
case hostname
|
||||
set ssh_hostname $parts[2]
|
||||
end
|
||||
if test -n "$ssh_user"; and test -n "$ssh_hostname"
|
||||
break
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
set -l ssh_target "$ssh_user@$ssh_hostname"
|
||||
|
||||
if test -n "$ssh_hostname"
|
||||
# Detect timeout command (BSD compatibility)
|
||||
set -l ssh_timeout_cmd
|
||||
if command -v timeout >/dev/null 2>&1
|
||||
set ssh_timeout_cmd timeout
|
||||
else if command -v gtimeout >/dev/null 2>&1
|
||||
set ssh_timeout_cmd gtimeout
|
||||
end
|
||||
|
||||
# Check if terminfo is already cached
|
||||
set -l ssh_cache_check_success false
|
||||
if command -v ghostty >/dev/null 2>&1
|
||||
if test -n "$ssh_timeout_cmd"
|
||||
if $ssh_timeout_cmd "$GHOSTTY_SSH_CHECK_TIMEOUT"s ghostty +ssh-cache --host="$ssh_target" >/dev/null 2>&1
|
||||
set ssh_cache_check_success true
|
||||
end
|
||||
else
|
||||
if ghostty +ssh-cache --host="$ssh_target" >/dev/null 2>&1
|
||||
set ssh_cache_check_success true
|
||||
end
|
||||
if ghostty +ssh-cache --host="$ssh_target" >/dev/null 2>&1
|
||||
set ssh_cache_check_success true
|
||||
end
|
||||
end
|
||||
|
||||
if test "$ssh_cache_check_success" = "true"
|
||||
set -a ssh_env TERM=xterm-ghostty
|
||||
else if command -v infocmp >/dev/null 2>&1
|
||||
# Generate terminfo data (BSD base64 compatibility)
|
||||
set -l ssh_terminfo
|
||||
if base64 --help 2>&1 | grep -q GNU
|
||||
set ssh_terminfo (infocmp -0 -Q2 -q xterm-ghostty 2>/dev/null | base64 -w0 2>/dev/null)
|
||||
if not command -v base64 >/dev/null 2>&1
|
||||
echo "Warning: base64 command not available for terminfo installation." >&2
|
||||
set -a ssh_env TERM=xterm-256color
|
||||
else
|
||||
set ssh_terminfo (infocmp -0 -Q2 -q xterm-ghostty 2>/dev/null | base64 2>/dev/null | tr -d '\n')
|
||||
end
|
||||
|
||||
if test -n "$ssh_terminfo"
|
||||
echo "Setting up Ghostty terminfo on remote host..." >&2
|
||||
set -l ssh_cpath_dir (mktemp -d "/tmp/ghostty-ssh-$ssh_user.XXXXXX" 2>/dev/null; or echo "/tmp/ghostty-ssh-$ssh_user."(random))
|
||||
set -l ssh_cpath "$ssh_cpath_dir/socket"
|
||||
|
||||
set -l ssh_terminfo
|
||||
set -l ssh_base64_decode_cmd
|
||||
|
||||
# BSD vs GNU base64 compatibility
|
||||
if base64 --help 2>&1 | grep -q GNU
|
||||
set ssh_base64_decode_cmd "base64 -d"
|
||||
set ssh_terminfo (infocmp -0 -Q2 -q xterm-ghostty 2>/dev/null | base64 -w0 2>/dev/null)
|
||||
else
|
||||
set ssh_base64_decode_cmd "base64 -D"
|
||||
set ssh_terminfo (infocmp -0 -Q2 -q xterm-ghostty 2>/dev/null | base64 2>/dev/null | tr -d '\n')
|
||||
end
|
||||
|
||||
if echo "$ssh_terminfo" | eval $ssh_base64_decode_cmd | command ssh $ssh_opts -o ControlMaster=yes -o ControlPath="$ssh_cpath" -o ControlPersist=60s $argv '
|
||||
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
|
||||
echo "Terminfo setup complete." >&2
|
||||
set -a ssh_env TERM=xterm-ghostty
|
||||
set -a ssh_opts -o "ControlPath=$ssh_cpath"
|
||||
if test -n "$ssh_terminfo"
|
||||
echo "Setting up Ghostty terminfo on $ssh_hostname..." >&2
|
||||
set -l ssh_cpath_dir (mktemp -d "/tmp/ghostty-ssh-$ssh_user.XXXXXX" 2>/dev/null; or echo "/tmp/ghostty-ssh-$ssh_user."(random))
|
||||
set -l ssh_cpath "$ssh_cpath_dir/socket"
|
||||
|
||||
# Cache successful installation
|
||||
if test -n "$ssh_target"; and command -v ghostty >/dev/null 2>&1
|
||||
fish -c "
|
||||
if test -n '$ssh_timeout_cmd'
|
||||
$ssh_timeout_cmd '$GHOSTTY_SSH_CACHE_TIMEOUT's ghostty +ssh-cache --add='$ssh_target' >/dev/null 2>&1; or true
|
||||
else
|
||||
ghostty +ssh-cache --add='$ssh_target' >/dev/null 2>&1; or true
|
||||
end
|
||||
" &
|
||||
if echo "$ssh_terminfo" | eval $ssh_base64_decode_cmd | command ssh $ssh_opts -o ControlMaster=yes -o ControlPath="$ssh_cpath" -o ControlPersist=60s $argv '
|
||||
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
|
||||
echo "Terminfo setup complete on $ssh_hostname." >&2
|
||||
set -a ssh_env TERM=xterm-ghostty
|
||||
set -a ssh_opts -o "ControlPath=$ssh_cpath"
|
||||
|
||||
# Cache successful installation
|
||||
if test -n "$ssh_target"; and command -v ghostty >/dev/null 2>&1
|
||||
fish -c "ghostty +ssh-cache --add='$ssh_target' >/dev/null 2>&1; or true" &
|
||||
end
|
||||
else
|
||||
echo "Warning: Failed to install terminfo." >&2
|
||||
set -a ssh_env TERM=xterm-256color
|
||||
end
|
||||
else
|
||||
echo "Warning: Failed to install terminfo." >&2
|
||||
echo "Warning: Could not generate terminfo data." >&2
|
||||
set -a ssh_env TERM=xterm-256color
|
||||
end
|
||||
else
|
||||
echo "Warning: Could not generate terminfo data." >&2
|
||||
set -a ssh_env TERM=xterm-256color
|
||||
end
|
||||
else
|
||||
echo "Warning: ghostty command not available for cache management." >&2
|
||||
|
|
@ -224,22 +211,31 @@ function __ghostty_setup --on-event fish_prompt -d "Setup ghostty integration"
|
|||
end
|
||||
end
|
||||
|
||||
# Ensure TERM is set when using ssh-env feature
|
||||
if string match -q '*ssh-env*' -- "$GHOSTTY_SHELL_FEATURES"
|
||||
set -l ssh_term_set false
|
||||
for ssh_v in $ssh_env
|
||||
if string match -q 'TERM=*' -- $ssh_v
|
||||
set ssh_term_set true
|
||||
break
|
||||
end
|
||||
end
|
||||
if test "$ssh_term_set" = "false"; and test "$TERM" = "xterm-ghostty"
|
||||
set -a ssh_env TERM=xterm-256color
|
||||
# Execute SSH with environment handling
|
||||
set -l ssh_term_override
|
||||
for ssh_v in $ssh_env
|
||||
if string match -q 'TERM=*' -- $ssh_v
|
||||
set ssh_term_override (string replace 'TERM=' '' -- $ssh_v)
|
||||
break
|
||||
end
|
||||
end
|
||||
|
||||
command ssh $ssh_opts $argv
|
||||
set -l ssh_ret $status
|
||||
if string match -q '*ssh-env*' -- "$GHOSTTY_SHELL_FEATURES"; and test -z "$ssh_term_override"
|
||||
set -a ssh_env TERM=xterm-256color
|
||||
set ssh_term_override xterm-256color
|
||||
end
|
||||
|
||||
set -l ssh_ret
|
||||
if test -n "$ssh_term_override"
|
||||
set -l ssh_original_term "$TERM"
|
||||
set -gx TERM "$ssh_term_override"
|
||||
command ssh $ssh_opts $argv
|
||||
set ssh_ret $status
|
||||
set -gx TERM "$ssh_original_term"
|
||||
else
|
||||
command ssh $ssh_opts $argv
|
||||
set ssh_ret $status
|
||||
end
|
||||
|
||||
# Restore original environment variables
|
||||
if string match -q '*ssh-env*' -- "$GHOSTTY_SHELL_FEATURES"
|
||||
|
|
|
|||
|
|
@ -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}"
|
||||
|
|
|
|||
Loading…
Reference in New Issue