refactor: replace ghostty wrapper with proper CLI actions for terminfo cache management

- Add +list-ssh-cache and +clear-ssh-cache CLI actions
- Remove ghostty() wrapper functions from all shell integrations
- Improve variable naming in shell scripts for readability

Addresses @00-kat's feedback about CLI discoverability and naming
consistency. The new CLI actions follow established Ghostty patterns
and are discoverable via `ghostty --help`, while maintaining clean
separation of concerns between shell logic and cache management.
This commit is contained in:
Jason Rayne
2025-06-25 12:47:38 -07:00
parent 6789b7fb6e
commit 0565ed3954
8 changed files with 299 additions and 173 deletions

View File

@@ -100,19 +100,11 @@ if [[ "$GHOSTTY_SHELL_FEATURES" =~ ssh-(env|terminfo) ]]; then
if [[ "$GHOSTTY_SHELL_FEATURES" =~ ssh-terminfo ]]; then
readonly _CACHE="${GHOSTTY_RESOURCES_DIR}/shell-integration/shared/ghostty-ssh-cache"
# If 'ssh-terminfo' flag is enabled, wrap ghostty to provide cache management commands
ghostty() {
case "$1" in
ssh-cache-list) "$_CACHE" list ;;
ssh-cache-clear) "$_CACHE" clear ;;
*) builtin command ghostty "$@" ;;
esac
}
fi
# SSH wrapper
ssh() {
local e=() o=() c=() # Removed 't' from here
local env=() opts=() ctrl=()
# Set up env vars first so terminfo installation inherits them
if [[ "$GHOSTTY_SHELL_FEATURES" =~ ssh-env ]]; then
@@ -123,35 +115,35 @@ if [[ "$GHOSTTY_SHELL_FEATURES" =~ ssh-(env|terminfo) ]]; then
)
for v in "${vars[@]}"; do
builtin export "${v?}"
o+=(-o "SendEnv ${v%=*}" -o "SetEnv $v")
opts+=(-o "SendEnv ${v%=*}" -o "SetEnv $v")
done
fi
# Install terminfo if needed, reuse control connection for main session
if [[ "$GHOSTTY_SHELL_FEATURES" =~ ssh-terminfo ]]; then
# Get target (only when needed for terminfo)
builtin local t
t=$(builtin command ssh -G "$@" 2>/dev/null | awk '/^(user|hostname) /{print $2}' | paste -sd'@')
builtin local target
target=$(builtin command ssh -G "$@" 2>/dev/null | awk '/^(user|hostname) /{print $2}' | paste -sd'@')
if [[ -n "$t" ]] && "$_CACHE" chk "$t"; then
e+=(TERM=xterm-ghostty)
if [[ -n "$target" ]] && "$_CACHE" chk "$target"; then
env+=(TERM=xterm-ghostty)
elif builtin command -v infocmp >/dev/null 2>&1; then
builtin local ti
ti=$(infocmp -x xterm-ghostty 2>/dev/null) || builtin echo "Warning: xterm-ghostty terminfo not found locally." >&2
if [[ -n "$ti" ]]; then
builtin local tinfo
tinfo=$(infocmp -x xterm-ghostty 2>/dev/null) || builtin echo "Warning: xterm-ghostty terminfo not found locally." >&2
if [[ -n "$tinfo" ]]; then
builtin echo "Setting up Ghostty terminfo on remote host..." >&2
builtin local cp
cp="/tmp/ghostty-ssh-$USER-$RANDOM-$(date +%s)"
case $(builtin echo "$ti" | builtin command ssh "${o[@]}" -o ControlMaster=yes -o ControlPath="$cp" -o ControlPersist=60s "$@" '
builtin local cpath
cpath="/tmp/ghostty-ssh-$USER-$RANDOM-$(date +%s)"
case $(builtin echo "$tinfo" | builtin command ssh "${opts[@]}" -o ControlMaster=yes -o ControlPath="$cpath" -o ControlPersist=60s "$@" '
infocmp xterm-ghostty >/dev/null 2>&1 && echo OK && exit
command -v tic >/dev/null 2>&1 || { echo NO_TIC; exit 1; }
mkdir -p ~/.terminfo 2>/dev/null && tic -x - 2>/dev/null && echo OK || echo FAIL
') in
OK)
builtin echo "Terminfo setup complete." >&2
[[ -n "$t" ]] && "$_CACHE" add "$t"
e+=(TERM=xterm-ghostty)
c+=(-o "ControlPath=$cp")
[[ -n "$target" ]] && "$_CACHE" add "$target"
env+=(TERM=xterm-ghostty)
ctrl+=(-o "ControlPath=$cpath")
;;
*) builtin echo "Warning: Failed to install terminfo." >&2 ;;
esac
@@ -163,14 +155,14 @@ if [[ "$GHOSTTY_SHELL_FEATURES" =~ ssh-(env|terminfo) ]]; then
# Fallback TERM only if terminfo didn't set it
if [[ "$GHOSTTY_SHELL_FEATURES" =~ ssh-env ]]; then
[[ $TERM == xterm-ghostty && ! " ${e[*]} " =~ " TERM=" ]] && e+=(TERM=xterm-256color)
[[ $TERM == xterm-ghostty && ! " ${env[*]} " =~ " TERM=" ]] && env+=(TERM=xterm-256color)
fi
# Execute
if [[ ${#e[@]} -gt 0 ]]; then
env "${e[@]}" ssh "${o[@]}" "${c[@]}" "$@"
if [[ ${#env[@]} -gt 0 ]]; then
env "${env[@]}" ssh "${opts[@]}" "${ctrl[@]}" "$@"
else
builtin command ssh "${o[@]}" "${c[@]}" "$@"
builtin command ssh "${opts[@]}" "${ctrl[@]}" "$@"
fi
}
fi

View File

@@ -100,85 +100,68 @@
# SSH Integration
use str
use path
use re
if (re:match 'ssh-(env|terminfo)' $E:GHOSTTY_SHELL_FEATURES) {
if (re:match 'ssh-terminfo' $E:GHOSTTY_SHELL_FEATURES) {
var _cache_script = (path:join $E:GHOSTTY_RESOURCES_DIR shell-integration shared ghostty-ssh-cache)
# Wrap ghostty command to provide cache management commands
fn ghostty {|@args|
if (eq $args[0] ssh-cache-list) {
(external $_cache_script) list
} elif (eq $args[0] ssh-cache-clear) {
(external $_cache_script) clear
} else {
(external ghostty) $@args
}
}
if (str:contains $E:GHOSTTY_SHELL_FEATURES ssh-env) or (str:contains $E:GHOSTTY_SHELL_FEATURES ssh-terminfo) {
edit:add-var ghostty~ $ghostty~
if (str:contains $E:GHOSTTY_SHELL_FEATURES ssh-terminfo) {
var _CACHE = $E:GHOSTTY_RESOURCES_DIR/shell-integration/shared/ghostty-ssh-cache
}
# SSH wrapper
fn ssh {|@args|
var e = []
var o = []
var c = []
var env = []
var opts = []
var ctrl = []
# Set up env vars first so terminfo installation inherits them
if (re:match 'ssh-env' $E:GHOSTTY_SHELL_FEATURES) {
set-env COLORTERM (or $E:COLORTERM truecolor)
set-env TERM_PROGRAM (or $E:TERM_PROGRAM ghostty)
if (has-env GHOSTTY_VERSION) {
set-env TERM_PROGRAM_VERSION $E:GHOSTTY_VERSION
}
var vars = [COLORTERM=truecolor TERM_PROGRAM=ghostty]
if (has-env GHOSTTY_VERSION) {
if (str:contains $E:GHOSTTY_SHELL_FEATURES ssh-env) {
var vars = [
COLORTERM=truecolor
TERM_PROGRAM=ghostty
]
if (not-eq $E:GHOSTTY_VERSION '') {
set vars = [$@vars TERM_PROGRAM_VERSION=$E:GHOSTTY_VERSION]
}
for v $vars {
var varname = (str:split &max=2 '=' $v | take 1)
set o = [$@o -o "SendEnv "$varname -o "SetEnv "$v]
set-env (str:split = $v | take 1) (str:split = $v | drop 1 | str:join =)
var varname = (str:split = $v | take 1)
set opts = [$@opts -o 'SendEnv '$varname -o 'SetEnv '$v]
}
}
# Install terminfo if needed, reuse control connection for main session
if (re:match 'ssh-terminfo' $E:GHOSTTY_SHELL_FEATURES) {
# Get target (only when needed for terminfo)
var t = ""
if (str:contains $E:GHOSTTY_SHELL_FEATURES ssh-terminfo) {
# Get target
var target = ''
try {
set t = (e:ssh -G $@args 2>/dev/null | awk '/^(user|hostname) /{print $2}' | paste -sd'@' | str:trim-space)
} catch e {
# Ignore errors
}
set target = (e:ssh -G $@args 2>/dev/null | e:awk '/^(user|hostname) /{print $2}' | e:paste -sd'@')
} catch { }
if (and (not-eq $t "") (try { (external $_cache_script) chk $t } catch e { put $false })) {
set e = [$@e TERM=xterm-ghostty]
if (and (not-eq $target '') ($_CACHE chk $target)) {
set env = [$@env TERM=xterm-ghostty]
} elif (has-external infocmp) {
var ti = ""
var tinfo = ''
try {
set ti = (infocmp -x xterm-ghostty 2>/dev/null | slurp)
} catch e {
set tinfo = (e:infocmp -x xterm-ghostty 2>/dev/null)
} catch {
echo "Warning: xterm-ghostty terminfo not found locally." >&2
}
if (not-eq $ti "") {
if (not-eq $tinfo '') {
echo "Setting up Ghostty terminfo on remote host..." >&2
var cp = "/tmp/ghostty-ssh-"$E:USER"-"(randint 10000)"-"(date +%s | str:trim-space)
var result = (echo $ti | e:ssh $@o -o ControlMaster=yes -o ControlPath=$cp -o ControlPersist=60s $@args '
var cpath = '/tmp/ghostty-ssh-'$E:USER'-'(randint 0 32767)'-'(date +%s)
var result = (echo $tinfo | e:ssh $@opts -o ControlMaster=yes -o ControlPath=$cpath -o ControlPersist=60s $@args '
infocmp xterm-ghostty >/dev/null 2>&1 && echo OK && exit
command -v tic >/dev/null 2>&1 || { echo NO_TIC; exit 1; }
mkdir -p ~/.terminfo 2>/dev/null && tic -x - 2>/dev/null && echo OK || echo FAIL
' | str:trim-space)
')
if (eq $result OK) {
echo "Terminfo setup complete." >&2
if (not-eq $t "") {
(external $_cache_script) add $t
}
set e = [$@e TERM=xterm-ghostty]
set c = [$@c -o ControlPath=$cp]
if (not-eq $target '') { $_CACHE add $target }
set env = [$@env TERM=xterm-ghostty]
set ctrl = [$@ctrl -o ControlPath=$cpath]
} else {
echo "Warning: Failed to install terminfo." >&2
}
@@ -189,22 +172,19 @@
}
# Fallback TERM only if terminfo didn't set it
if (re:match 'ssh-env' $E:GHOSTTY_SHELL_FEATURES) {
if (and (eq $E:TERM xterm-ghostty) (not (re:match 'TERM=' (str:join ' ' $e)))) {
set e = [$@e TERM=xterm-256color]
if (str:contains $E:GHOSTTY_SHELL_FEATURES ssh-env) {
if (and (eq $E:TERM xterm-ghostty) (not (str:contains (str:join ' ' $env) 'TERM='))) {
set env = [$@env TERM=xterm-256color]
}
}
# Execute
if (> (count $e) 0) {
e:env $@e e:ssh $@o $@c $@args
if (> (count $env) 0) {
e:env $@env e:ssh $@opts $@ctrl $@args
} else {
e:ssh $@o $@c $@args
e:ssh $@opts $@ctrl $@args
}
}
# Export ssh function for global use
set edit:add-var[ssh] = $ssh~
}
defer {

View File

@@ -87,89 +87,86 @@ function __ghostty_setup --on-event fish_prompt -d "Setup ghostty integration"
end
# SSH Integration
if string match -qr 'ssh-(env|terminfo)' "$GHOSTTY_SHELL_FEATURES"
if string match -qr ssh-terminfo "$GHOSTTY_SHELL_FEATURES"
set -g _cache_script "$GHOSTTY_RESOURCES_DIR/shell-integration/shared/ghostty-ssh-cache"
if string match -qr 'ssh-(env|terminfo)' $GHOSTTY_SHELL_FEATURES
# Wrap ghostty command to provide cache management commands
function ghostty -d "Wrap ghostty to provide cache management commands"
switch "$argv[1]"
case ssh-cache-list
command "$_cache_script" list
case ssh-cache-clear
command "$_cache_script" clear
case "*"
command ghostty $argv
end
end
if string match -q '*ssh-terminfo*' $GHOSTTY_SHELL_FEATURES
set -g _CACHE "$GHOSTTY_RESOURCES_DIR/shell-integration/shared/ghostty-ssh-cache"
end
# SSH wrapper
function ssh
set -l e
set -l o
set -l c
set -l env
set -l opts
set -l ctrl
# Set up env vars first so terminfo installation inherits them
if string match -qr ssh-env "$GHOSTTY_SHELL_FEATURES"
set -gx COLORTERM (test -n "$COLORTERM" && echo "$COLORTERM" || echo "truecolor")
set -gx TERM_PROGRAM (test -n "$TERM_PROGRAM" && echo "$TERM_PROGRAM" || echo "ghostty")
test -n "$GHOSTTY_VERSION" && set -gx TERM_PROGRAM_VERSION "$GHOSTTY_VERSION"
if string match -q '*ssh-env*' $GHOSTTY_SHELL_FEATURES
set -l vars \
COLORTERM=truecolor \
TERM_PROGRAM=ghostty
set -l vars COLORTERM=truecolor TERM_PROGRAM=ghostty
test -n "$GHOSTTY_VERSION" && set vars $vars "TERM_PROGRAM_VERSION=$GHOSTTY_VERSION"
if test -n "$GHOSTTY_VERSION"
set -a vars "TERM_PROGRAM_VERSION=$GHOSTTY_VERSION"
end
for v in $vars
set -l varname (string split -m1 '=' "$v")[1]
set o $o -o "SendEnv $varname" -o "SetEnv $v"
set -l parts (string split = $v)
set -gx $parts[1] $parts[2]
set -a opts -o "SendEnv $parts[1]" -o "SetEnv $v"
end
end
# Install terminfo if needed, reuse control connection for main session
if string match -qr ssh-terminfo "$GHOSTTY_SHELL_FEATURES"
# Get target (only when needed for terminfo)
set -l t (builtin command ssh -G $argv 2>/dev/null | awk '/^(user|hostname) /{print $2}' | paste -sd'@')
if string match -q '*ssh-terminfo*' $GHOSTTY_SHELL_FEATURES
# Get target
set -l target (command ssh -G $argv 2>/dev/null | awk '/^(user|hostname) /{print $2}' | paste -sd'@')
if test -n "$t" && command "$_cache_script" chk "$t"
set e $e TERM=xterm-ghostty
if test -n "$target" -a ("$_CACHE" chk "$target")
set -a env TERM=xterm-ghostty
else if command -v infocmp >/dev/null 2>&1
set -l ti
set ti (infocmp -x xterm-ghostty 2>/dev/null) || builtin echo "Warning: xterm-ghostty terminfo not found locally." >&2
if test -n "$ti"
builtin echo "Setting up Ghostty terminfo on remote host..." >&2
set -l cp "/tmp/ghostty-ssh-$USER-"(random)"-"(date +%s)
set -l result (builtin echo "$ti" | builtin command ssh $o -o ControlMaster=yes -o ControlPath="$cp" -o ControlPersist=60s $argv '
set -l tinfo (infocmp -x xterm-ghostty 2>/dev/null)
set -l status_code $status
if test $status_code -ne 0
echo "Warning: xterm-ghostty terminfo not found locally." >&2
end
if test -n "$tinfo"
echo "Setting up Ghostty terminfo on remote host..." >&2
set -l cpath "/tmp/ghostty-ssh-$USER-"(random)"-"(date +%s)
set -l result (echo "$tinfo" | command ssh $opts -o ControlMaster=yes -o ControlPath="$cpath" -o ControlPersist=60s $argv '
infocmp xterm-ghostty >/dev/null 2>&1 && echo OK && exit
command -v tic >/dev/null 2>&1 || { echo NO_TIC; exit 1; }
mkdir -p ~/.terminfo 2>/dev/null && tic -x - 2>/dev/null && echo OK || echo FAIL
')
switch $result
case OK
builtin echo "Terminfo setup complete." >&2
test -n "$t" && command "$_cache_script" add "$t"
set e $e TERM=xterm-ghostty
set c $c -o "ControlPath=$cp"
echo "Terminfo setup complete." >&2
test -n "$target" && "$_CACHE" add "$target"
set -a env TERM=xterm-ghostty
set -a ctrl -o "ControlPath=$cpath"
case '*'
builtin echo "Warning: Failed to install terminfo." >&2
echo "Warning: Failed to install terminfo." >&2
end
end
else
builtin echo "Warning: infocmp not found locally. Terminfo installation unavailable." >&2
echo "Warning: infocmp not found locally. Terminfo installation unavailable." >&2
end
end
# Fallback TERM only if terminfo didn't set it
if string match -qr ssh-env "$GHOSTTY_SHELL_FEATURES"
if test "$TERM" = xterm-ghostty && not string match -q '*TERM=*' "$e"
set e $e TERM=xterm-256color
if string match -q '*ssh-env*' $GHOSTTY_SHELL_FEATURES
if test "$TERM" = xterm-ghostty -a ! (string join ' ' $env | string match -q '*TERM=*')
set -a env TERM=xterm-256color
end
end
# Execute
if test (count $e) -gt 0
env $e ssh $o $c $argv
if test (count $env) -gt 0
env $env command ssh $opts $ctrl $argv
else
builtin command ssh $o $c $argv
command ssh $opts $ctrl $argv
end
end
end

View File

@@ -246,80 +246,76 @@ _ghostty_deferred_init() {
# SSH Integration
if [[ "$GHOSTTY_SHELL_FEATURES" =~ ssh-(env|terminfo) ]]; then
if [[ "$GHOSTTY_SHELL_FEATURES" =~ ssh-terminfo ]]; then
readonly _cache_script="${GHOSTTY_RESOURCES_DIR}/shell-integration/shared/ghostty-ssh-cache"
# Wrap ghostty command to provide cache management commands
ghostty() {
case "$1" in
ssh-cache-list) "$_cache_script" list ;;
ssh-cache-clear) "$_cache_script" clear ;;
*) builtin command ghostty "$@" ;;
esac
}
readonly _CACHE="${GHOSTTY_RESOURCES_DIR}/shell-integration/shared/ghostty-ssh-cache"
fi
# SSH wrapper
ssh() {
local -a e o c
local -a env opts ctrl
env=()
opts=()
ctrl=()
# Set up env vars first so terminfo installation inherits them
if [[ "$GHOSTTY_SHELL_FEATURES" =~ ssh-env ]]; then
local vars=(
local -a vars
vars=(
COLORTERM=truecolor
TERM_PROGRAM=ghostty
${GHOSTTY_VERSION:+TERM_PROGRAM_VERSION=$GHOSTTY_VERSION}
)
for v in "${vars[@]}"; do
builtin export "${v?}"
o+=(-o "SendEnv ${v%=*}" -o "SetEnv $v")
export "${v?}"
opts+=(-o "SendEnv ${v%=*}" -o "SetEnv $v")
done
fi
# Install terminfo if needed, reuse control connection for main session
if [[ "$GHOSTTY_SHELL_FEATURES" =~ ssh-terminfo ]]; then
# Get target (only when needed for terminfo)
builtin local t
t=$(builtin command ssh -G "$@" 2>/dev/null | awk '/^(user|hostname) /{print $2}' | paste -sd'@')
local target
target=$(command ssh -G "$@" 2>/dev/null | awk '/^(user|hostname) /{print $2}' | paste -sd'@')
if [[ -n $t ]] && "$_cache_script" chk "$t"; then
e+=(TERM=xterm-ghostty)
elif builtin command -v infocmp >/dev/null 2>&1; then
local ti
ti=$(infocmp -x xterm-ghostty 2>/dev/null) || builtin echo "Warning: xterm-ghostty terminfo not found locally." >&2
if [[ -n $ti ]]; then
builtin echo "Setting up Ghostty terminfo on remote host..." >&2
local cp
cp="/tmp/ghostty-ssh-$USER-$RANDOM-$(date +%s)"
case $(builtin echo "$ti" | builtin command ssh "${o[@]}" -o ControlMaster=yes -o ControlPath="$cp" -o ControlPersist=60s "$@" '
if [[ -n "$target" ]] && "$_CACHE" chk "$target"; then
env+=(TERM=xterm-ghostty)
elif command -v infocmp >/dev/null 2>&1; then
local tinfo
tinfo=$(infocmp -x xterm-ghostty 2>/dev/null) || echo "Warning: xterm-ghostty terminfo not found locally." >&2
if [[ -n "$tinfo" ]]; then
echo "Setting up Ghostty terminfo on remote host..." >&2
local cpath
cpath="/tmp/ghostty-ssh-$USER-$RANDOM-$(date +%s)"
case $(echo "$tinfo" | command ssh "${opts[@]}" -o ControlMaster=yes -o ControlPath="$cpath" -o ControlPersist=60s "$@" '
infocmp xterm-ghostty >/dev/null 2>&1 && echo OK && exit
command -v tic >/dev/null 2>&1 || { echo NO_TIC; exit 1; }
mkdir -p ~/.terminfo 2>/dev/null && tic -x - 2>/dev/null && echo OK || echo FAIL
') in
OK)
builtin echo "Terminfo setup complete." >&2
[[ -n $t ]] && "$_cache_script" add "$t"
e+=(TERM=xterm-ghostty)
c+=(-o "ControlPath=$cp")
echo "Terminfo setup complete." >&2
[[ -n "$target" ]] && "$_CACHE" add "$target"
env+=(TERM=xterm-ghostty)
ctrl+=(-o "ControlPath=$cpath")
;;
*) builtin echo "Warning: Failed to install terminfo." >&2 ;;
*) echo "Warning: Failed to install terminfo." >&2 ;;
esac
fi
else
builtin echo "Warning: infocmp not found locally. Terminfo installation unavailable." >&2
echo "Warning: infocmp not found locally. Terminfo installation unavailable." >&2
fi
fi
# Fallback TERM only if terminfo didn't set it
if [[ "$GHOSTTY_SHELL_FEATURES" =~ ssh-env ]]; then
[[ $TERM == xterm-ghostty && ! " ${(j: :)e} " =~ " TERM=" ]] && e+=(TERM=xterm-256color)
[[ $TERM == xterm-ghostty && ! " ${env[*]} " =~ " TERM=" ]] && env+=(TERM=xterm-256color)
fi
# Execute
if (( ${#e} > 0 )); then
env "${e[@]}" ssh "${o[@]}" "${c[@]}" "$@"
if [[ ${#env[@]} -gt 0 ]]; then
env "${env[@]}" command ssh "${opts[@]}" "${ctrl[@]}" "$@"
else
builtin command ssh "${o[@]}" "${c[@]}" "$@"
command ssh "${opts[@]}" "${ctrl[@]}" "$@"
fi
}
fi