mirror of
https://github.com/ghostty-org/ghostty.git
synced 2025-07-15 00:06:09 +03: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:
@ -97,131 +97,116 @@ fi
|
|||||||
|
|
||||||
# SSH Integration
|
# SSH Integration
|
||||||
if [[ "$GHOSTTY_SHELL_FEATURES" =~ ssh-(env|terminfo) ]]; then
|
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() {
|
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
|
# Configure environment variables for remote session
|
||||||
if [[ "$GHOSTTY_SHELL_FEATURES" =~ ssh-env ]]; then
|
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"
|
"COLORTERM=truecolor"
|
||||||
"TERM_PROGRAM=ghostty"
|
"TERM_PROGRAM=ghostty"
|
||||||
)
|
)
|
||||||
if [[ -n "$TERM_PROGRAM_VERSION" ]]; then
|
if [[ -n "$TERM_PROGRAM_VERSION" ]]; then
|
||||||
ssh_env_vars+=("TERM_PROGRAM_VERSION=$TERM_PROGRAM_VERSION")
|
ssh_env+=("TERM_PROGRAM_VERSION=$TERM_PROGRAM_VERSION")
|
||||||
fi
|
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
|
fi
|
||||||
|
|
||||||
# Install terminfo on remote host if needed
|
# Install terminfo on remote host if needed
|
||||||
if [[ "$GHOSTTY_SHELL_FEATURES" =~ ssh-terminfo ]]; then
|
if [[ "$GHOSTTY_SHELL_FEATURES" =~ ssh-terminfo ]]; then
|
||||||
builtin local ssh_config ssh_user ssh_hostname
|
builtin local ssh_config ssh_user ssh_hostname
|
||||||
ssh_config=$(builtin command ssh -G "$@" 2>/dev/null)
|
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
|
while IFS=' ' read -r ssh_key ssh_value; do
|
||||||
done)
|
case "$ssh_key" in
|
||||||
ssh_hostname=$(echo "$ssh_config" | while IFS=' ' read -r ssh_key ssh_value; do
|
user) ssh_user="$ssh_value" ;;
|
||||||
[[ "$ssh_key" == "hostname" ]] && echo "$ssh_value" && break
|
hostname) ssh_hostname="$ssh_value" ;;
|
||||||
done)
|
esac
|
||||||
|
[[ -n "$ssh_user" && -n "$ssh_hostname" ]] && break
|
||||||
|
done <<< "$ssh_config"
|
||||||
|
|
||||||
ssh_target="${ssh_user}@${ssh_hostname}"
|
ssh_target="${ssh_user}@${ssh_hostname}"
|
||||||
|
|
||||||
if [[ -n "$ssh_hostname" ]]; then
|
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
|
# Check if terminfo is already cached
|
||||||
local ssh_cache_check_success=false
|
builtin local ssh_cache_check_success=false
|
||||||
if command -v ghostty >/dev/null 2>&1; then
|
if builtin command -v ghostty >/dev/null 2>&1; then
|
||||||
if [[ -n "$ssh_timeout_cmd" ]]; then
|
ghostty +ssh-cache --host="$ssh_target" >/dev/null 2>&1 && ssh_cache_check_success=true
|
||||||
$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
|
|
||||||
fi
|
fi
|
||||||
|
|
||||||
if [[ "$ssh_cache_check_success" == "true" ]]; then
|
if [[ "$ssh_cache_check_success" == "true" ]]; then
|
||||||
ssh_env+=(TERM=xterm-ghostty)
|
ssh_env+=(TERM=xterm-ghostty)
|
||||||
elif builtin command -v infocmp >/dev/null 2>&1; then
|
elif builtin command -v infocmp >/dev/null 2>&1; then
|
||||||
builtin local ssh_terminfo
|
if ! builtin command -v base64 >/dev/null 2>&1; then
|
||||||
|
builtin echo "Warning: base64 command not available for terminfo installation." >&2
|
||||||
# Generate terminfo data (BSD base64 compatibility)
|
ssh_env+=(TERM=xterm-256color)
|
||||||
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)
|
|
||||||
else
|
else
|
||||||
ssh_terminfo=$(infocmp -0 -Q2 -q xterm-ghostty 2>/dev/null | base64 2>/dev/null | tr -d '\n')
|
builtin local ssh_terminfo ssh_base64_decode_cmd
|
||||||
fi
|
|
||||||
|
|
||||||
if [[ -n "$ssh_terminfo" ]]; then
|
# BSD vs GNU base64 compatibility
|
||||||
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
|
|
||||||
if base64 --help 2>&1 | grep -q GNU; then
|
if base64 --help 2>&1 | grep -q GNU; then
|
||||||
ssh_base64_decode_cmd="base64 -d"
|
ssh_base64_decode_cmd="base64 -d"
|
||||||
|
ssh_terminfo=$(infocmp -0 -Q2 -q xterm-ghostty 2>/dev/null | base64 -w0 2>/dev/null)
|
||||||
else
|
else
|
||||||
ssh_base64_decode_cmd="base64 -D"
|
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
|
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 "$@" '
|
if [[ -n "$ssh_terminfo" ]]; then
|
||||||
infocmp xterm-ghostty >/dev/null 2>&1 && exit 0
|
builtin echo "Setting up Ghostty terminfo on $ssh_hostname..." >&2
|
||||||
command -v tic >/dev/null 2>&1 || exit 1
|
builtin local ssh_cpath_dir ssh_cpath
|
||||||
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")
|
|
||||||
|
|
||||||
# Cache successful installation
|
ssh_cpath_dir=$(mktemp -d "/tmp/ghostty-ssh-$ssh_user.XXXXXX" 2>/dev/null) || ssh_cpath_dir="/tmp/ghostty-ssh-$ssh_user.$$"
|
||||||
if [[ -n "$ssh_target" ]] && command -v ghostty >/dev/null 2>&1; then
|
ssh_cpath="$ssh_cpath_dir/socket"
|
||||||
(
|
|
||||||
set +m
|
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
|
||||||
if [[ -n "$ssh_timeout_cmd" ]]; then
|
command -v tic >/dev/null 2>&1 || exit 1
|
||||||
$ssh_timeout_cmd "${GHOSTTY_SSH_CACHE_TIMEOUT}s" ghostty +ssh-cache --add="$ssh_target" >/dev/null 2>&1 || true
|
mkdir -p ~/.terminfo 2>/dev/null && tic -x - 2>/dev/null && exit 0
|
||||||
else
|
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
|
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
|
fi
|
||||||
else
|
else
|
||||||
builtin echo "Warning: Failed to install terminfo." >&2
|
builtin echo "Warning: Could not generate terminfo data." >&2
|
||||||
ssh_env+=(TERM=xterm-256color)
|
ssh_env+=(TERM=xterm-256color)
|
||||||
fi
|
fi
|
||||||
else
|
|
||||||
builtin echo "Warning: Could not generate terminfo data." >&2
|
|
||||||
ssh_env+=(TERM=xterm-256color)
|
|
||||||
fi
|
fi
|
||||||
else
|
else
|
||||||
builtin echo "Warning: ghostty command not available for cache management." >&2
|
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
|
||||||
fi
|
fi
|
||||||
|
|
||||||
# Ensure TERM is set when using ssh-env feature
|
# Execute SSH with environment handling
|
||||||
if [[ "$GHOSTTY_SHELL_FEATURES" =~ ssh-env ]]; then
|
builtin local ssh_term_override=""
|
||||||
local ssh_term_set=false
|
for ssh_v in "${ssh_env[@]}"; do
|
||||||
for ssh_v in "${ssh_env[@]}"; do
|
if [[ "$ssh_v" =~ ^TERM=(.*)$ ]]; then
|
||||||
if [[ "$ssh_v" =~ ^TERM= ]]; then
|
ssh_term_override="${BASH_REMATCH[1]}"
|
||||||
ssh_term_set=true
|
break
|
||||||
break
|
|
||||||
fi
|
|
||||||
done
|
|
||||||
if [[ "$ssh_term_set" == "false" && "$TERM" == "xterm-ghostty" ]]; then
|
|
||||||
ssh_env+=(TERM=xterm-256color)
|
|
||||||
fi
|
fi
|
||||||
|
done
|
||||||
|
|
||||||
|
if [[ "$GHOSTTY_SHELL_FEATURES" =~ ssh-env && -z "$ssh_term_override" ]]; then
|
||||||
|
ssh_env+=(TERM=xterm-256color)
|
||||||
|
ssh_term_override="xterm-256color"
|
||||||
fi
|
fi
|
||||||
|
|
||||||
builtin command ssh "${ssh_opts[@]}" "$@"
|
if [[ -n "$ssh_term_override" ]]; then
|
||||||
local ssh_ret=$?
|
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
|
# Restore original environment variables
|
||||||
if [[ "$GHOSTTY_SHELL_FEATURES" =~ ssh-env ]]; then
|
if [[ "$GHOSTTY_SHELL_FEATURES" =~ ssh-env ]]; then
|
||||||
|
@ -100,50 +100,41 @@
|
|||||||
|
|
||||||
# SSH Integration
|
# SSH Integration
|
||||||
use str
|
use str
|
||||||
use re
|
|
||||||
|
|
||||||
if (or (str:contains $E:GHOSTTY_SHELL_FEATURES ssh-env) (str:contains $E:GHOSTTY_SHELL_FEATURES ssh-terminfo)) {
|
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|
|
fn ssh {|@args|
|
||||||
var ssh-env = []
|
var ssh-env = []
|
||||||
var ssh-opts = []
|
var ssh-opts = []
|
||||||
|
var ssh-exported-vars = []
|
||||||
|
|
||||||
# Configure environment variables for remote session
|
# Configure environment variables for remote session
|
||||||
if (str:contains $E:GHOSTTY_SHELL_FEATURES ssh-env) {
|
if (str:contains $E:GHOSTTY_SHELL_FEATURES ssh-env) {
|
||||||
var ssh-env-vars = [
|
set ssh-opts = [$@ssh-opts -o "SetEnv COLORTERM=truecolor"]
|
||||||
COLORTERM=truecolor
|
|
||||||
TERM_PROGRAM=ghostty
|
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) {
|
if (has-env TERM_PROGRAM_VERSION) {
|
||||||
set ssh-env-vars = [$@ssh-env-vars TERM_PROGRAM_VERSION=$E:TERM_PROGRAM_VERSION]
|
if (has-env TERM_PROGRAM_VERSION) {
|
||||||
}
|
set ssh-exported-vars = [$@ssh-exported-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]
|
|
||||||
} else {
|
} else {
|
||||||
set ssh-exported-vars = [$@ssh-exported-vars $ssh-var-name]
|
set ssh-exported-vars = [$@ssh-exported-vars "TERM_PROGRAM_VERSION"]
|
||||||
}
|
}
|
||||||
|
set ssh-opts = [$@ssh-opts -o "SendEnv 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-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
|
# Install terminfo on remote host if needed
|
||||||
@ -160,52 +151,28 @@
|
|||||||
|
|
||||||
for line (str:split "\n" $ssh-config) {
|
for line (str:split "\n" $ssh-config) {
|
||||||
var parts = (str:split " " $line)
|
var parts = (str:split " " $line)
|
||||||
if (and (> (count $parts) 1) (eq $parts[0] user)) {
|
if (> (count $parts) 1) {
|
||||||
set ssh-user = $parts[1]
|
if (eq $parts[0] user) {
|
||||||
}
|
set ssh-user = $parts[1]
|
||||||
if (and (> (count $parts) 1) (eq $parts[0] hostname)) {
|
} elif (eq $parts[0] hostname) {
|
||||||
set ssh-hostname = $parts[1]
|
set ssh-hostname = $parts[1]
|
||||||
|
}
|
||||||
|
if (and (not-eq $ssh-user "") (not-eq $ssh-hostname "")) {
|
||||||
|
break
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
var ssh-target = $ssh-user"@"$ssh-hostname
|
var ssh-target = $ssh-user"@"$ssh-hostname
|
||||||
|
|
||||||
if (not-eq $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
|
# Check if terminfo is already cached
|
||||||
var ssh-cache-check-success = $false
|
var ssh-cache-check-success = $false
|
||||||
try {
|
try {
|
||||||
external ghostty --help >/dev/null 2>&1
|
external ghostty +ssh-cache --host=$ssh-target >/dev/null 2>&1
|
||||||
if (not-eq $ssh-timeout-cmd "") {
|
set ssh-cache-check-success = $true
|
||||||
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
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} catch {
|
} catch {
|
||||||
# ghostty not available
|
# cache check failed
|
||||||
}
|
}
|
||||||
|
|
||||||
if $ssh-cache-check-success {
|
if $ssh-cache-check-success {
|
||||||
@ -213,74 +180,68 @@
|
|||||||
} else {
|
} else {
|
||||||
try {
|
try {
|
||||||
external infocmp --help >/dev/null 2>&1
|
external infocmp --help >/dev/null 2>&1
|
||||||
|
|
||||||
# Generate terminfo data (BSD base64 compatibility)
|
|
||||||
var ssh-terminfo = ""
|
|
||||||
try {
|
try {
|
||||||
var base64-help = (external base64 --help 2>&1 | slurp)
|
external base64 --help >/dev/null 2>&1
|
||||||
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"
|
|
||||||
|
|
||||||
|
# Generate terminfo data (BSD base64 compatibility)
|
||||||
|
var ssh-terminfo = ""
|
||||||
var ssh-base64-decode-cmd = ""
|
var ssh-base64-decode-cmd = ""
|
||||||
try {
|
try {
|
||||||
var base64-help = (external base64 --help 2>&1 | slurp)
|
var base64-help = (external base64 --help 2>&1 | slurp)
|
||||||
if (str:contains $base64-help GNU) {
|
if (str:contains $base64-help GNU) {
|
||||||
set ssh-base64-decode-cmd = "base64 -d"
|
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 {
|
} else {
|
||||||
set ssh-base64-decode-cmd = "base64 -D"
|
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 {
|
} catch {
|
||||||
set ssh-base64-decode-cmd = "base64 -d"
|
set ssh-terminfo = ""
|
||||||
}
|
}
|
||||||
|
|
||||||
var terminfo-install-success = $false
|
if (not-eq $ssh-terminfo "") {
|
||||||
try {
|
echo "Setting up Ghostty terminfo on "$ssh-hostname"..." >&2
|
||||||
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 '
|
var ssh-cpath-dir = ""
|
||||||
infocmp xterm-ghostty >/dev/null 2>&1 && exit 0
|
try {
|
||||||
command -v tic >/dev/null 2>&1 || exit 1
|
set ssh-cpath-dir = (external mktemp -d "/tmp/ghostty-ssh-"$ssh-user".XXXXXX" 2>/dev/null | slurp)
|
||||||
mkdir -p ~/.terminfo 2>/dev/null && tic -x - 2>/dev/null && exit 0
|
} catch {
|
||||||
exit 1
|
set ssh-cpath-dir = "/tmp/ghostty-ssh-"$ssh-user"."(randint 10000 99999)
|
||||||
' >/dev/null 2>&1
|
}
|
||||||
set terminfo-install-success = $true
|
var ssh-cpath = $ssh-cpath-dir"/socket"
|
||||||
} catch {
|
|
||||||
set terminfo-install-success = $false
|
|
||||||
}
|
|
||||||
|
|
||||||
if $terminfo-install-success {
|
var terminfo-install-success = $false
|
||||||
echo "Terminfo setup complete." >&2
|
try {
|
||||||
set ssh-env = [$@ssh-env TERM=xterm-ghostty]
|
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 '
|
||||||
set ssh-opts = [$@ssh-opts -o ControlPath=$ssh-cpath]
|
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 $terminfo-install-success {
|
||||||
if (and (not-eq $ssh-target "") (has-external ghostty)) {
|
echo "Terminfo setup complete on "$ssh-hostname"." >&2
|
||||||
if (not-eq $ssh-timeout-cmd "") {
|
set ssh-env = [$@ssh-env TERM=xterm-ghostty]
|
||||||
external $ssh-timeout-cmd $GHOSTTY_SSH_CACHE_TIMEOUT"s" ghostty +ssh-cache --add=$ssh-target >/dev/null 2>&1 &
|
set ssh-opts = [$@ssh-opts -o ControlPath=$ssh-cpath]
|
||||||
} else {
|
|
||||||
|
# Cache successful installation
|
||||||
|
if (and (not-eq $ssh-target "") (has-external ghostty)) {
|
||||||
external ghostty +ssh-cache --add=$ssh-target >/dev/null 2>&1 &
|
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 {
|
} else {
|
||||||
echo "Warning: Failed to install terminfo." >&2
|
echo "Warning: Could not generate terminfo data." >&2
|
||||||
set ssh-env = [$@ssh-env TERM=xterm-256color]
|
set ssh-env = [$@ssh-env TERM=xterm-256color]
|
||||||
}
|
}
|
||||||
} else {
|
} catch {
|
||||||
echo "Warning: Could not generate terminfo data." >&2
|
echo "Warning: base64 command not available for terminfo installation." >&2
|
||||||
set ssh-env = [$@ssh-env TERM=xterm-256color]
|
set ssh-env = [$@ssh-env TERM=xterm-256color]
|
||||||
}
|
}
|
||||||
} catch {
|
} catch {
|
||||||
@ -295,25 +256,36 @@
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
# Ensure TERM is set when using ssh-env feature
|
# Execute SSH with environment handling
|
||||||
if (str:contains $E:GHOSTTY_SHELL_FEATURES ssh-env) {
|
var ssh-term-override = ""
|
||||||
var ssh-term-set = $false
|
for ssh-v $ssh-env {
|
||||||
for ssh-v $ssh-env {
|
if (str:has-prefix $ssh-v TERM=) {
|
||||||
if (str:has-prefix $ssh-v TERM=) {
|
set ssh-term-override = (str:trim-prefix $ssh-v TERM=)
|
||||||
set ssh-term-set = $true
|
break
|
||||||
break
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (and (not $ssh-term-set) (eq $E:TERM xterm-ghostty)) {
|
|
||||||
set ssh-env = [$@ssh-env TERM=xterm-256color]
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
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
|
var ssh-ret = 0
|
||||||
try {
|
if (not-eq $ssh-term-override "") {
|
||||||
external ssh $@ssh-opts $@args
|
var ssh-original-term = $E:TERM
|
||||||
} catch e {
|
set-env TERM $ssh-term-override
|
||||||
set ssh-ret = $e[reason][exit-status]
|
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
|
# Restore original environment variables
|
||||||
|
@ -86,132 +86,119 @@ function __ghostty_setup --on-event fish_prompt -d "Setup ghostty integration"
|
|||||||
end
|
end
|
||||||
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"
|
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"
|
function ssh --wraps=ssh --description "SSH wrapper with Ghostty integration"
|
||||||
set -l ssh_env
|
set -l ssh_env
|
||||||
set -l ssh_opts
|
set -l ssh_opts
|
||||||
|
set -l ssh_exported_vars
|
||||||
|
|
||||||
# Configure environment variables for remote session
|
# Configure environment variables for remote session
|
||||||
if string match -q '*ssh-env*' -- "$GHOSTTY_SHELL_FEATURES"
|
if string match -q '*ssh-env*' -- "$GHOSTTY_SHELL_FEATURES"
|
||||||
set -l ssh_env_vars \
|
set -a ssh_opts -o "SetEnv COLORTERM=truecolor"
|
||||||
"COLORTERM=truecolor" \
|
|
||||||
"TERM_PROGRAM=ghostty"
|
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"
|
if test -n "$TERM_PROGRAM_VERSION"
|
||||||
set -a ssh_env_vars "TERM_PROGRAM_VERSION=$TERM_PROGRAM_VERSION"
|
if set -q TERM_PROGRAM_VERSION
|
||||||
end
|
set -a ssh_exported_vars "TERM_PROGRAM_VERSION=$TERM_PROGRAM_VERSION"
|
||||||
|
|
||||||
# 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)
|
|
||||||
else
|
else
|
||||||
set -a ssh_exported_vars $ssh_var_name
|
set -a ssh_exported_vars "TERM_PROGRAM_VERSION"
|
||||||
end
|
end
|
||||||
|
set -a ssh_opts -o "SendEnv TERM_PROGRAM_VERSION"
|
||||||
# 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"
|
|
||||||
end
|
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
|
end
|
||||||
|
|
||||||
# Install terminfo on remote host if needed
|
# Install terminfo on remote host if needed
|
||||||
if string match -q '*ssh-terminfo*' -- "$GHOSTTY_SHELL_FEATURES"
|
if string match -q '*ssh-terminfo*' -- "$GHOSTTY_SHELL_FEATURES"
|
||||||
set -l ssh_config (command ssh -G $argv 2>/dev/null)
|
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
|
set -l ssh_user
|
||||||
test "$ssh_key" = "user"; and echo $ssh_value; and break
|
set -l ssh_hostname
|
||||||
end)
|
|
||||||
set -l ssh_hostname (echo $ssh_config | while read -l ssh_key ssh_value
|
for line in $ssh_config
|
||||||
test "$ssh_key" = "hostname"; and echo $ssh_value; and break
|
set -l parts (string split ' ' -- $line)
|
||||||
end)
|
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"
|
set -l ssh_target "$ssh_user@$ssh_hostname"
|
||||||
|
|
||||||
if test -n "$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
|
# Check if terminfo is already cached
|
||||||
set -l ssh_cache_check_success false
|
set -l ssh_cache_check_success false
|
||||||
if command -v ghostty >/dev/null 2>&1
|
if command -v ghostty >/dev/null 2>&1
|
||||||
if test -n "$ssh_timeout_cmd"
|
if ghostty +ssh-cache --host="$ssh_target" >/dev/null 2>&1
|
||||||
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
|
||||||
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
|
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
if test "$ssh_cache_check_success" = "true"
|
if test "$ssh_cache_check_success" = "true"
|
||||||
set -a ssh_env TERM=xterm-ghostty
|
set -a ssh_env TERM=xterm-ghostty
|
||||||
else if command -v infocmp >/dev/null 2>&1
|
else if command -v infocmp >/dev/null 2>&1
|
||||||
# Generate terminfo data (BSD base64 compatibility)
|
if not command -v base64 >/dev/null 2>&1
|
||||||
set -l ssh_terminfo
|
echo "Warning: base64 command not available for terminfo installation." >&2
|
||||||
if base64 --help 2>&1 | grep -q GNU
|
set -a ssh_env TERM=xterm-256color
|
||||||
set ssh_terminfo (infocmp -0 -Q2 -q xterm-ghostty 2>/dev/null | base64 -w0 2>/dev/null)
|
|
||||||
else
|
else
|
||||||
set ssh_terminfo (infocmp -0 -Q2 -q xterm-ghostty 2>/dev/null | base64 2>/dev/null | tr -d '\n')
|
set -l ssh_terminfo
|
||||||
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_base64_decode_cmd
|
set -l ssh_base64_decode_cmd
|
||||||
|
|
||||||
|
# BSD vs GNU base64 compatibility
|
||||||
if base64 --help 2>&1 | grep -q GNU
|
if base64 --help 2>&1 | grep -q GNU
|
||||||
set ssh_base64_decode_cmd "base64 -d"
|
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
|
else
|
||||||
set ssh_base64_decode_cmd "base64 -D"
|
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
|
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 '
|
if test -n "$ssh_terminfo"
|
||||||
infocmp xterm-ghostty >/dev/null 2>&1 && exit 0
|
echo "Setting up Ghostty terminfo on $ssh_hostname..." >&2
|
||||||
command -v tic >/dev/null 2>&1 || exit 1
|
set -l ssh_cpath_dir (mktemp -d "/tmp/ghostty-ssh-$ssh_user.XXXXXX" 2>/dev/null; or echo "/tmp/ghostty-ssh-$ssh_user."(random))
|
||||||
mkdir -p ~/.terminfo 2>/dev/null && tic -x - 2>/dev/null && exit 0
|
set -l ssh_cpath "$ssh_cpath_dir/socket"
|
||||||
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"
|
|
||||||
|
|
||||||
# Cache successful installation
|
if echo "$ssh_terminfo" | eval $ssh_base64_decode_cmd | command ssh $ssh_opts -o ControlMaster=yes -o ControlPath="$ssh_cpath" -o ControlPersist=60s $argv '
|
||||||
if test -n "$ssh_target"; and command -v ghostty >/dev/null 2>&1
|
infocmp xterm-ghostty >/dev/null 2>&1 && exit 0
|
||||||
fish -c "
|
command -v tic >/dev/null 2>&1 || exit 1
|
||||||
if test -n '$ssh_timeout_cmd'
|
mkdir -p ~/.terminfo 2>/dev/null && tic -x - 2>/dev/null && exit 0
|
||||||
$ssh_timeout_cmd '$GHOSTTY_SSH_CACHE_TIMEOUT's ghostty +ssh-cache --add='$ssh_target' >/dev/null 2>&1; or true
|
exit 1
|
||||||
else
|
' 2>/dev/null
|
||||||
ghostty +ssh-cache --add='$ssh_target' >/dev/null 2>&1; or true
|
echo "Terminfo setup complete on $ssh_hostname." >&2
|
||||||
end
|
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
|
end
|
||||||
else
|
else
|
||||||
echo "Warning: Failed to install terminfo." >&2
|
echo "Warning: Could not generate terminfo data." >&2
|
||||||
set -a ssh_env TERM=xterm-256color
|
set -a ssh_env TERM=xterm-256color
|
||||||
end
|
end
|
||||||
else
|
|
||||||
echo "Warning: Could not generate terminfo data." >&2
|
|
||||||
set -a ssh_env TERM=xterm-256color
|
|
||||||
end
|
end
|
||||||
else
|
else
|
||||||
echo "Warning: ghostty command not available for cache management." >&2
|
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
|
||||||
end
|
end
|
||||||
|
|
||||||
# Ensure TERM is set when using ssh-env feature
|
# Execute SSH with environment handling
|
||||||
if string match -q '*ssh-env*' -- "$GHOSTTY_SHELL_FEATURES"
|
set -l ssh_term_override
|
||||||
set -l ssh_term_set false
|
for ssh_v in $ssh_env
|
||||||
for ssh_v in $ssh_env
|
if string match -q 'TERM=*' -- $ssh_v
|
||||||
if string match -q 'TERM=*' -- $ssh_v
|
set ssh_term_override (string replace 'TERM=' '' -- $ssh_v)
|
||||||
set ssh_term_set true
|
break
|
||||||
break
|
|
||||||
end
|
|
||||||
end
|
|
||||||
if test "$ssh_term_set" = "false"; and test "$TERM" = "xterm-ghostty"
|
|
||||||
set -a ssh_env TERM=xterm-256color
|
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
command ssh $ssh_opts $argv
|
if string match -q '*ssh-env*' -- "$GHOSTTY_SHELL_FEATURES"; and test -z "$ssh_term_override"
|
||||||
set -l ssh_ret $status
|
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
|
# Restore original environment variables
|
||||||
if string match -q '*ssh-env*' -- "$GHOSTTY_SHELL_FEATURES"
|
if string match -q '*ssh-env*' -- "$GHOSTTY_SHELL_FEATURES"
|
||||||
|
@ -244,132 +244,116 @@ _ghostty_deferred_init() {
|
|||||||
}
|
}
|
||||||
fi
|
fi
|
||||||
|
|
||||||
# SSH Integration
|
# SSH Integration
|
||||||
if [[ "$GHOSTTY_SHELL_FEATURES" =~ (ssh-env|ssh-terminfo) ]]; then
|
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() {
|
ssh() {
|
||||||
emulate -L zsh
|
emulate -L zsh
|
||||||
setopt local_options no_glob_subst
|
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
|
# Configure environment variables for remote session
|
||||||
if [[ "$GHOSTTY_SHELL_FEATURES" =~ ssh-env ]]; then
|
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"
|
"COLORTERM=truecolor"
|
||||||
"TERM_PROGRAM=ghostty"
|
"TERM_PROGRAM=ghostty"
|
||||||
)
|
)
|
||||||
[[ -n "$TERM_PROGRAM_VERSION" ]] && ssh_env_vars+=("TERM_PROGRAM_VERSION=$TERM_PROGRAM_VERSION")
|
[[ -n "$TERM_PROGRAM_VERSION" ]] && ssh_env+=("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[@]}")
|
|
||||||
fi
|
fi
|
||||||
|
|
||||||
# Install terminfo on remote host if needed
|
# Install terminfo on remote host if needed
|
||||||
if [[ "$GHOSTTY_SHELL_FEATURES" =~ ssh-terminfo ]]; then
|
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_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
|
while IFS=' ' read -r ssh_key ssh_value; do
|
||||||
done)
|
case "$ssh_key" in
|
||||||
ssh_hostname=$(printf '%s\n' "${(@f)ssh_config}" | while IFS=' ' read -r ssh_key ssh_value; do
|
user) ssh_user="$ssh_value" ;;
|
||||||
[[ "$ssh_key" == "hostname" ]] && printf '%s\n' "$ssh_value" && break
|
hostname) ssh_hostname="$ssh_value" ;;
|
||||||
done)
|
esac
|
||||||
|
[[ -n "$ssh_user" && -n "$ssh_hostname" ]] && break
|
||||||
|
done <<< "$ssh_config"
|
||||||
|
|
||||||
ssh_target="${ssh_user}@${ssh_hostname}"
|
ssh_target="${ssh_user}@${ssh_hostname}"
|
||||||
|
|
||||||
if [[ -n "$ssh_hostname" ]]; then
|
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
|
# Check if terminfo is already cached
|
||||||
local ssh_cache_check_success=false
|
local ssh_cache_check_success=false
|
||||||
if (( $+commands[ghostty] )); then
|
if (( $+commands[ghostty] )); then
|
||||||
if [[ -n "$ssh_timeout_cmd" ]]; then
|
ghostty +ssh-cache --host="$ssh_target" >/dev/null 2>&1 && ssh_cache_check_success=true
|
||||||
$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
|
|
||||||
fi
|
fi
|
||||||
|
|
||||||
if [[ "$ssh_cache_check_success" == "true" ]]; then
|
if [[ "$ssh_cache_check_success" == "true" ]]; then
|
||||||
ssh_env+=(TERM=xterm-ghostty)
|
ssh_env+=(TERM=xterm-ghostty)
|
||||||
elif (( $+commands[infocmp] )); then
|
elif (( $+commands[infocmp] )); then
|
||||||
local ssh_terminfo
|
if ! (( $+commands[base64] )); then
|
||||||
|
print "Warning: base64 command not available for terminfo installation." >&2
|
||||||
# Generate terminfo data (BSD base64 compatibility)
|
ssh_env+=(TERM=xterm-256color)
|
||||||
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)
|
|
||||||
else
|
else
|
||||||
ssh_terminfo=$(infocmp -0 -Q2 -q xterm-ghostty 2>/dev/null | base64 2>/dev/null | tr -d '\n')
|
local ssh_terminfo ssh_base64_decode_cmd
|
||||||
fi
|
|
||||||
|
|
||||||
if [[ -n "$ssh_terminfo" ]]; then
|
# BSD vs GNU base64 compatibility
|
||||||
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
|
|
||||||
if base64 --help 2>&1 | grep -q GNU; then
|
if base64 --help 2>&1 | grep -q GNU; then
|
||||||
ssh_base64_decode_cmd="base64 -d"
|
ssh_base64_decode_cmd="base64 -d"
|
||||||
|
ssh_terminfo=$(infocmp -0 -Q2 -q xterm-ghostty 2>/dev/null | base64 -w0 2>/dev/null)
|
||||||
else
|
else
|
||||||
ssh_base64_decode_cmd="base64 -D"
|
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
|
fi
|
||||||
|
|
||||||
if print "$ssh_terminfo" | $ssh_base64_decode_cmd | command ssh "${ssh_opts[@]}" -o ControlMaster=yes -o ControlPath="$ssh_cpath" -o ControlPersist=60s "$@" '
|
if [[ -n "$ssh_terminfo" ]]; then
|
||||||
infocmp xterm-ghostty >/dev/null 2>&1 && exit 0
|
print "Setting up Ghostty terminfo on $ssh_hostname..." >&2
|
||||||
command -v tic >/dev/null 2>&1 || exit 1
|
local ssh_cpath_dir ssh_cpath
|
||||||
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")
|
|
||||||
|
|
||||||
# Cache successful installation
|
ssh_cpath_dir=$(mktemp -d "/tmp/ghostty-ssh-$ssh_user.XXXXXX" 2>/dev/null) || ssh_cpath_dir="/tmp/ghostty-ssh-$ssh_user.$$"
|
||||||
if [[ -n "$ssh_target" ]] && (( $+commands[ghostty] )); then
|
ssh_cpath="$ssh_cpath_dir/socket"
|
||||||
{
|
|
||||||
if [[ -n "$ssh_timeout_cmd" ]]; then
|
if print "$ssh_terminfo" | $ssh_base64_decode_cmd | command ssh "${ssh_opts[@]}" -o ControlMaster=yes -o ControlPath="$ssh_cpath" -o ControlPersist=60s "$@" '
|
||||||
$ssh_timeout_cmd "${GHOSTTY_SSH_CACHE_TIMEOUT}s" ghostty +ssh-cache --add="$ssh_target" >/dev/null 2>&1 || true
|
infocmp xterm-ghostty >/dev/null 2>&1 && exit 0
|
||||||
else
|
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
|
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
|
fi
|
||||||
else
|
else
|
||||||
print "Warning: Failed to install terminfo." >&2
|
print "Warning: Could not generate terminfo data." >&2
|
||||||
ssh_env+=(TERM=xterm-256color)
|
ssh_env+=(TERM=xterm-256color)
|
||||||
fi
|
fi
|
||||||
else
|
|
||||||
print "Warning: Could not generate terminfo data." >&2
|
|
||||||
ssh_env+=(TERM=xterm-256color)
|
|
||||||
fi
|
fi
|
||||||
else
|
else
|
||||||
print "Warning: ghostty command not available for cache management." >&2
|
print "Warning: ghostty command not available for cache management." >&2
|
||||||
@ -380,21 +364,35 @@ _ghostty_deferred_init() {
|
|||||||
fi
|
fi
|
||||||
fi
|
fi
|
||||||
|
|
||||||
# Ensure TERM is set when using ssh-env feature
|
# Execute SSH with environment handling
|
||||||
if [[ "$GHOSTTY_SHELL_FEATURES" =~ ssh-env ]]; then
|
local ssh_term_override=""
|
||||||
local ssh_term_set=false ssh_v
|
local ssh_v
|
||||||
for ssh_v in "${ssh_env[@]}"; do
|
for ssh_v in "${ssh_env[@]}"; do
|
||||||
[[ "$ssh_v" =~ ^TERM= ]] && ssh_term_set=true && break
|
if [[ "$ssh_v" =~ ^TERM=(.*)$ ]]; then
|
||||||
done
|
ssh_term_override="${match[1]}"
|
||||||
[[ "$ssh_term_set" == "false" && "$TERM" == "xterm-ghostty" ]] && ssh_env+=(TERM=xterm-256color)
|
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
|
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
|
# Restore original environment variables
|
||||||
if [[ "$GHOSTTY_SHELL_FEATURES" =~ ssh-env ]]; then
|
if [[ "$GHOSTTY_SHELL_FEATURES" =~ ssh-env ]]; then
|
||||||
local ssh_v
|
|
||||||
for ssh_v in "${ssh_exported_vars[@]}"; do
|
for ssh_v in "${ssh_exported_vars[@]}"; do
|
||||||
if [[ "$ssh_v" == *=* ]]; then
|
if [[ "$ssh_v" == *=* ]]; then
|
||||||
export "${ssh_v}"
|
export "${ssh_v}"
|
||||||
|
Reference in New Issue
Block a user