This commit is contained in:
Kovid Goyal 2022-03-07 11:18:15 +05:30
commit d4d4e00f9d
No known key found for this signature in database
GPG Key ID: 06BC317B515ACE7C
7 changed files with 104 additions and 111 deletions

View File

@ -83,7 +83,7 @@ def make_tarfile(ssh_opts: SSHOptions, base_env: Dict[str, str]) -> bytes:
def filter_from_globs(*pats: str) -> Callable[[tarfile.TarInfo], Optional[tarfile.TarInfo]]: def filter_from_globs(*pats: str) -> Callable[[tarfile.TarInfo], Optional[tarfile.TarInfo]]:
def filter(tarinfo: tarfile.TarInfo) -> Optional[tarfile.TarInfo]: def filter(tarinfo: tarfile.TarInfo) -> Optional[tarfile.TarInfo]:
for junk_dir in ('.DS_Store', '__pycache__'): for junk_dir in ('.DS_Store', '__pycache__'):
for pat in (f'*/{junk_dir}', '*/{junk_dir}/*'): for pat in (f'*/{junk_dir}', f'*/{junk_dir}/*'):
if fnmatch.fnmatch(tarinfo.name, pat): if fnmatch.fnmatch(tarinfo.name, pat):
return None return None
for pat in pats: for pat in pats:

View File

@ -213,16 +213,8 @@ function _set_status_prompt; function fish_prompt; echo -n "$pipestatus $status
pty.write_to_child('i') pty.write_to_child('i')
pty.wait_till(lambda: pty.screen.cursor.shape == CURSOR_BEAM) pty.wait_till(lambda: pty.screen.cursor.shape == CURSOR_BEAM)
pty.send_cmd_to_child('_set_key default') pty.send_cmd_to_child('_set_key default')
# pipestatus
pty.send_cmd_to_child('clear;false|true|false')
pty.send_cmd_to_child('echo $pipestatus $status')
pty.wait_till(lambda: pty.screen_contents().count(right_prompt) == 2)
self.ae(pty.last_cmd_output(), '1 0 1 1')
pty.send_cmd_to_child('_set_status_prompt')
pty.send_cmd_to_child('false|true|false')
pty.wait_till(lambda: pty.screen_contents().count(right_prompt) == 4) pty.wait_till(lambda: pty.screen_contents().count(right_prompt) == 4)
self.assertTrue(str(pty.screen.line(pty.screen.cursor.y)).startswith(f'1 0 1 1 {fish_prompt}')) pty.wait_till(lambda: pty.screen.cursor.shape == CURSOR_BEAM)
pty.send_cmd_to_child('exit') pty.send_cmd_to_child('exit')

View File

@ -155,8 +155,19 @@ _ksi_main() {
fi fi
if [[ "${_ksi_prompt[title]}" == "y" ]]; then if [[ "${_ksi_prompt[title]}" == "y" ]]; then
if [[ -n "$SSH_TTY$SSH2_TTY" ]]; then if [[ -z "$KITTY_PID" ]]; then
_ksi_prompt[hostname_prefix]="\h: "; if [[ -n "$SSH_TTY" || -n "$SSH2_TTY$KITTY_WINDOW_ID" ]]; then
# connected to most SSH servers
# or use ssh kitten to connected to some SSH servers that do not set SSH_TTY
_ksi_prompt[hostname_prefix]="\h: ";
else
if [[ -n "$(builtin command -v who)" && "$(builtin command who -m 2> /dev/null)" =~ "\([a-fA-F.:0-9]+\)$" ]]; then
# the shell integration script is installed manually on the remote system
# the environment variables are cleared after sudo
# OpenSSH's sshd creates entries in utmp for every login so use those
_ksi_prompt[hostname_prefix]="\h: ";
fi
fi
fi fi
# see https://www.gnu.org/software/bash/manual/html_node/Controlling-the-Prompt.html#Controlling-the-Prompt # see https://www.gnu.org/software/bash/manual/html_node/Controlling-the-Prompt.html#Controlling-the-Prompt
# we use suffix here because some distros add title setting to their bashrc files by default # we use suffix here because some distros add title setting to their bashrc files by default

View File

@ -19,7 +19,7 @@ end
status is-interactive || exit 0 status is-interactive || exit 0
not functions -q __ksi_schedule || exit 0 not functions -q __ksi_schedule || exit 0
# Check fish version 3.3.0+ efficiently and fallback to check the last working version 3.2.0, exit on outdated versions. # Check fish version 3.3.0+ efficiently and fallback to check the minimum working version 3.2.0, exit on outdated versions.
# "Warning: Update fish to version 3.3.0+ to enable kitty shell integration.\n" # "Warning: Update fish to version 3.3.0+ to enable kitty shell integration.\n"
set -q fish_killring || set -q status_generation || string match -qnv "3.1.*" "$version" set -q fish_killring || set -q status_generation || string match -qnv "3.1.*" "$version"
or echo -en "\eP@kitty-print|V2FybmluZzogVXBkYXRlIGZpc2ggdG8gdmVyc2lvbiAzLjMuMCsgdG8gZW5hYmxlIGtpdHR5IHNoZWxsIGludGVncmF0aW9uLgo=\e\\" && exit 0 || exit 0 or echo -en "\eP@kitty-print|V2FybmluZzogVXBkYXRlIGZpc2ggdG8gdmVyc2lvbiAzLjMuMCsgdG8gZW5hYmxlIGtpdHR5IHNoZWxsIGludGVncmF0aW9uLgo=\e\\" && exit 0 || exit 0
@ -80,21 +80,6 @@ function __ksi_schedule --on-event fish_prompt -d "Setup kitty integration after
end end
__ksi_mark_prompt_start __ksi_mark_prompt_start
functions -c fish_prompt __ksi_original_fish_prompt
function fish_prompt
# fish trims one trailing newline from the output of fish_prompt, so
# we need to do the same. See https://github.com/kovidgoyal/kitty/issues/4032
# op is a list because fish splits on newlines in command substitution
set --local op (__ksi_original_fish_prompt)
# print all but last element of the list, each followed by a new line
set -q op[2]
and printf '%s\n' $op[1..-2]
# print the last component without a newline
printf '%s' $op[-1]
set --global __ksi_prompt_state prompt-end
echo -en "\e]133;B\a"
end
function __ksi_mark_output_start --on-event fish_preexec function __ksi_mark_output_start --on-event fish_preexec
set --global __ksi_prompt_state pre-exec set --global __ksi_prompt_state pre-exec
echo -en "\e]133;C\a" echo -en "\e]133;C\a"

View File

@ -107,21 +107,20 @@ def move(src, base_dest):
def compile_terminfo(base): def compile_terminfo(base):
if not shutil.which('tic'): tic = shutil.which('tic')
if not tic:
return return
tname = '.terminfo' tname = '.terminfo'
if os.path.exists('/usr/share/misc/terminfo.cdb'): if os.path.exists('/usr/share/misc/terminfo.cdb'):
tname += '.cdb' tname += '.cdb'
os.environ['TERMINFO'] = os.path.join(HOME, tname) os.environ['TERMINFO'] = os.path.join(HOME, tname)
tic = shutil.which('tic') cp = subprocess.run(
if tic: [tic, '-x', '-o', os.path.join(base, tname), os.path.join(base, '.terminfo', 'kitty.terminfo')],
cp = subprocess.run( stdout=subprocess.PIPE, stderr=subprocess.STDOUT
[tic, '-x', '-o', os.path.join(base, tname), os.path.join(base, '.terminfo', 'kitty.terminfo')], )
stdout=subprocess.PIPE, stderr=subprocess.STDOUT if cp.returncode != 0:
) sys.stderr.buffer.write(cp.stdout)
if cp.returncode != 0: raise SystemExit('Failed to compile the terminfo database')
sys.stderr.buffer.write(cp.stdout)
raise SystemExit('Failed to compile the terminfo database')
def get_data(): def get_data():
@ -164,15 +163,6 @@ def get_data():
move(tdir + '/root', '/') move(tdir + '/root', '/')
def exec_bash_with_integration():
os.environ['ENV'] = os.path.join(shell_integration_dir, 'bash', 'kitty.bash')
os.environ['KITTY_BASH_INJECT'] = '1'
if not os.environ.get('HISTFILE'):
os.environ['HISTFILE'] = os.path.join(HOME, '.bash_history')
os.environ['KITTY_BASH_UNEXPORT_HISTFILE'] = '1'
os.execlp(login_shell, os.path.basename('login_shell'), '--posix')
def exec_zsh_with_integration(): def exec_zsh_with_integration():
zdotdir = os.environ.get('ZDOTDIR') or '' zdotdir = os.environ.get('ZDOTDIR') or ''
if not zdotdir: if not zdotdir:
@ -180,8 +170,8 @@ def exec_zsh_with_integration():
os.environ.pop('KITTY_ORIG_ZDOTDIR', None) # ensure this is not propagated os.environ.pop('KITTY_ORIG_ZDOTDIR', None) # ensure this is not propagated
else: else:
os.environ['KITTY_ORIG_ZDOTDIR'] = zdotdir os.environ['KITTY_ORIG_ZDOTDIR'] = zdotdir
# dont prevent zsh-new-user from running # dont prevent zsh-newuser-install from running
for q in '.zshrc .zshenv .zprofile .zlogin'.split(): for q in ('.zshrc', '.zshenv', '.zprofile', '.zlogin'):
if os.path.exists(os.path.join(HOME, q)): if os.path.exists(os.path.join(HOME, q)):
os.environ['ZDOTDIR'] = shell_integration_dir + '/zsh' os.environ['ZDOTDIR'] = shell_integration_dir + '/zsh'
os.execlp(login_shell, os.path.basename(login_shell), '-l') os.execlp(login_shell, os.path.basename(login_shell), '-l')
@ -197,14 +187,23 @@ def exec_fish_with_integration():
os.execlp(login_shell, os.path.basename(login_shell), '-l') os.execlp(login_shell, os.path.basename(login_shell), '-l')
def exec_bash_with_integration():
os.environ['ENV'] = os.path.join(shell_integration_dir, 'bash', 'kitty.bash')
os.environ['KITTY_BASH_INJECT'] = '1'
if not os.environ.get('HISTFILE'):
os.environ['HISTFILE'] = os.path.join(HOME, '.bash_history')
os.environ['KITTY_BASH_UNEXPORT_HISTFILE'] = '1'
os.execlp(login_shell, os.path.basename('login_shell'), '--posix')
def exec_with_shell_integration(): def exec_with_shell_integration():
shell_name = os.path.basename(login_shell).lower() shell_name = os.path.basename(login_shell).lower()
if shell_name == 'bash':
exec_bash_with_integration()
if shell_name == 'zsh': if shell_name == 'zsh':
exec_zsh_with_integration() exec_zsh_with_integration()
if shell_name == 'fish': if shell_name == 'fish':
exec_fish_with_integration() exec_fish_with_integration()
if shell_name == 'bash':
exec_bash_with_integration()
def main(): def main():

View File

@ -81,7 +81,7 @@ if [ -z "$HOSTNAME" ]; then
if [ -z "$hostname" ]; then if [ -z "$hostname" ]; then
hostname=$(command hostnamectl hostname 2> /dev/null) hostname=$(command hostnamectl hostname 2> /dev/null)
if [ -z "$hostname" ]; then if [ -z "$hostname" ]; then
hostname="_"; hostname="_"
fi fi
fi fi
else else
@ -95,17 +95,17 @@ if [ -z "$USER" ]; then USER=$(command whoami 2> /dev/null); fi
# ask for the SSH data # ask for the SSH data
leading_data="" leading_data=""
init_tty && trap 'cleanup_on_bootstrap_exit' EXIT init_tty && trap "cleanup_on_bootstrap_exit" EXIT
[ "$tty_ok" = "y" ] && dcs_to_kitty "ssh" "id="REQUEST_ID":hostname="$hostname":pwfile="PASSWORD_FILENAME":user="$USER":pw="DATA_PASSWORD"" [ "$tty_ok" = "y" ] && dcs_to_kitty "ssh" "id="REQUEST_ID":hostname="$hostname":pwfile="PASSWORD_FILENAME":user="$USER":pw="DATA_PASSWORD""
record_separator=$(printf "\036") record_separator=$(printf "\036")
mv_files_and_dirs() { mv_files_and_dirs() {
cwd="$PWD"; cwd="$PWD"
cd "$1"; cd "$1"
command find . -type d -exec mkdir -p "$2/{}" ";" command find . -type d -exec mkdir -p "$2/{}" ";"
command find . -type l -exec sh -c "tgt=\$(command readlink -n \"{}\"); command ln -sf \"\$tgt\" \"$2/{}\"; command rm -f \"{}\"" ";" command find . -type l -exec sh -c "tgt=\$(command readlink -n \"{}\"); command ln -sf \"\$tgt\" \"$2/{}\"; command rm -f \"{}\"" ";"
command find . -type f -exec mv "{}" "$2/{}" ";" command find . -type f -exec mv "{}" "$2/{}" ";"
cd "$cwd"; cd "$cwd"
} }
compile_terminfo() { compile_terminfo() {
@ -130,18 +130,18 @@ untar_and_read_env() {
# extract the tar file atomically, in the sense that any file from the # extract the tar file atomically, in the sense that any file from the
# tarfile is only put into place after it has been fully written to disk # tarfile is only put into place after it has been fully written to disk
tdir=$(command mktemp -d "$HOME/.kitty-ssh-kitten-untar-XXXXXXXXXXXX"); tdir=$(command mktemp -d "$HOME/.kitty-ssh-kitten-untar-XXXXXXXXXXXX")
[ $? = 0 ] || die "Creating temp directory failed"; [ $? = 0 ] || die "Creating temp directory failed"
read_n_bytes_from_tty "$1" | command base64 -d | command tar xjf - --no-same-owner -C "$tdir"; read_n_bytes_from_tty "$1" | command base64 -d | command tar xjf - --no-same-owner -C "$tdir"
data_file="$tdir/data.sh"; data_file="$tdir/data.sh"
[ -f "$data_file" ] && . "$data_file"; [ -f "$data_file" ] && . "$data_file"
data_dir="$HOME/$KITTY_SSH_KITTEN_DATA_DIR" data_dir="$HOME/$KITTY_SSH_KITTEN_DATA_DIR"
compile_terminfo "$tdir/home" compile_terminfo "$tdir/home"
mv_files_and_dirs "$tdir/home" "$HOME" mv_files_and_dirs "$tdir/home" "$HOME"
[ -e "$tdir/root" ] && mv_files_and_dirs "$tdir/root" "" [ -e "$tdir/root" ] && mv_files_and_dirs "$tdir/root" ""
command rm -rf "$tdir"; command rm -rf "$tdir"
[ -z "KITTY_SSH_KITTEN_DATA_DIR" ] && die "Failed to read SSH data from tty"; [ -z "KITTY_SSH_KITTEN_DATA_DIR" ] && die "Failed to read SSH data from tty"
unset KITTY_SSH_KITTEN_DATA_DIR; unset KITTY_SSH_KITTEN_DATA_DIR
} }
read_record() { read_record() {
@ -175,17 +175,15 @@ if [ "$tty_ok" = "y" ]; then
printf "\r\033[K" > /dev/tty printf "\r\033[K" > /dev/tty
fi fi
shell_integration_dir="$data_dir/shell-integration" shell_integration_dir="$data_dir/shell-integration"
[ -f "$HOME/.terminfo/kitty.terminfo" ] || die "Incomplete extraction of ssh data"; [ -f "$HOME/.terminfo/kitty.terminfo" ] || die "Incomplete extraction of ssh data"
fi fi
login_shell_is_ok() { login_shell_is_ok() {
if [ -z "$login_shell" -o ! -x "$login_shell" ]; then return 1; fi if [ -z "$login_shell" -o ! -x "$login_shell" ]; then return 1; fi
case "$login_shell" in case "$login_shell" in
*sh) return 0; *sh) return 0;
esac esac
return 1; return 1
} }
detect_python() { detect_python() {
@ -193,7 +191,7 @@ detect_python() {
if [ -z "$python" ]; then python=$(command -v python2); fi if [ -z "$python" ]; then python=$(command -v python2); fi
if [ -z "$python" ]; then python=$(command -v python); fi if [ -z "$python" ]; then python=$(command -v python); fi
if [ -z "$python" -o ! -x "$python" ]; then return 1; fi if [ -z "$python" -o ! -x "$python" ]; then return 1; fi
return 0; return 0
} }
parse_passwd_record() { parse_passwd_record() {
@ -203,43 +201,43 @@ parse_passwd_record() {
using_getent() { using_getent() {
cmd=$(command -v getent) cmd=$(command -v getent)
if [ -n "$cmd" ]; then if [ -n "$cmd" ]; then
output=$($cmd passwd $USER 2>/dev/null) output=$(command $cmd passwd $USER 2>/dev/null)
if [ $? = 0 ]; then if [ $? = 0 ]; then
login_shell=$(echo $output | parse_passwd_record); login_shell=$(echo $output | parse_passwd_record)
if login_shell_is_ok; then return 0; fi if login_shell_is_ok; then return 0; fi
fi fi
fi fi
return 1; return 1
} }
using_id() { using_id() {
cmd=$(command -v id) cmd=$(command -v id)
if [ -n "$cmd" ]; then if [ -n "$cmd" ]; then
output=$($cmd -P $USER 2>/dev/null) output=$(command $cmd -P $USER 2>/dev/null)
if [ $? = 0 ]; then if [ $? = 0 ]; then
login_shell=$(echo $output | parse_passwd_record); login_shell=$(echo $output | parse_passwd_record)
if login_shell_is_ok; then return 0; fi if login_shell_is_ok; then return 0; fi
fi fi
fi fi
return 1; return 1
}
using_passwd() {
if [ -f "/etc/passwd" -a -r "/etc/passwd" ]; then
output=$(command grep "^$USER:" /etc/passwd 2>/dev/null)
if [ $? = 0 ]; then
login_shell=$(echo $output | parse_passwd_record);
if login_shell_is_ok; then return 0; fi
fi
fi
return 1;
} }
using_python() { using_python() {
if detect_python; then if detect_python; then
output=$(command $python -c "import pwd, os; print(pwd.getpwuid(os.geteuid()).pw_shell)") output=$(command $python -c "import pwd, os; print(pwd.getpwuid(os.geteuid()).pw_shell)")
if [ $? = 0 ]; then if [ $? = 0 ]; then
login_shell=$output; login_shell=$output
if login_shell_is_ok; then return 0; fi
fi
fi
return 1
}
using_passwd() {
if [ -f "/etc/passwd" -a -r "/etc/passwd" ]; then
output=$(command grep "^$USER:" /etc/passwd 2>/dev/null)
if [ $? = 0 ]; then
login_shell=$(echo $output | parse_passwd_record)
if login_shell_is_ok; then return 0; fi if login_shell_is_ok; then return 0; fi
fi fi
fi fi
@ -250,14 +248,14 @@ execute_with_python() {
if detect_python; then if detect_python; then
exec $python -c "import os; os.execlp('$login_shell', '-' '$shell_name')" exec $python -c "import os; os.execlp('$login_shell', '-' '$shell_name')"
fi fi
return 1; return 1
} }
if [ -n "$KITTY_LOGIN_SHELL" ]; then if [ -n "$KITTY_LOGIN_SHELL" ]; then
login_shell="$KITTY_LOGIN_SHELL" login_shell="$KITTY_LOGIN_SHELL"
unset KITTY_LOGIN_SHELL unset KITTY_LOGIN_SHELL
else else
using_getent || using_id || using_python || using_passwd || die "Could not detect login shell"; using_getent || using_id || using_python || using_passwd || die "Could not detect login shell"
fi fi
shell_name=$(command basename $login_shell) shell_name=$(command basename $login_shell)
@ -272,17 +270,6 @@ if [ "$tty_ok" = "n" ]; then
fi fi
fi fi
exec_bash_with_integration() {
export ENV="$shell_integration_dir/bash/kitty.bash"
export KITTY_BASH_INJECT="1"
if [ -z "$HISTFILE" ]; then
export HISTFILE="$HOME/.bash_history"
export KITTY_BASH_UNEXPORT_HISTFILE="1"
fi
exec "$login_shell" "--posix"
}
exec_zsh_with_integration() { exec_zsh_with_integration() {
zdotdir="$ZDOTDIR" zdotdir="$ZDOTDIR"
if [ -z "$zdotdir" ]; then if [ -z "$zdotdir" ]; then
@ -290,7 +277,7 @@ exec_zsh_with_integration() {
else else
export KITTY_ORIG_ZDOTDIR="$zdotdir" export KITTY_ORIG_ZDOTDIR="$zdotdir"
fi fi
# dont prevent zsh-new-user from running # dont prevent zsh-newuser-install from running
if [ -f "$zdotdir/.zshrc" -o -f "$zdotdir/.zshenv" -o -f "$zdotdir/.zprofile" -o -f "$zdotdir/.zlogin" ]; then if [ -f "$zdotdir/.zshrc" -o -f "$zdotdir/.zshenv" -o -f "$zdotdir/.zprofile" -o -f "$zdotdir/.zlogin" ]; then
export ZDOTDIR="$shell_integration_dir/zsh" export ZDOTDIR="$shell_integration_dir/zsh"
exec "$login_shell" "-l" exec "$login_shell" "-l"
@ -308,17 +295,27 @@ exec_fish_with_integration() {
exec "$login_shell" "-l" exec "$login_shell" "-l"
} }
exec_bash_with_integration() {
export ENV="$shell_integration_dir/bash/kitty.bash"
export KITTY_BASH_INJECT="1"
if [ -z "$HISTFILE" ]; then
export HISTFILE="$HOME/.bash_history"
export KITTY_BASH_UNEXPORT_HISTFILE="1"
fi
exec "$login_shell" "--posix"
}
exec_with_shell_integration() { exec_with_shell_integration() {
case "$shell_name" in case "$shell_name" in
"zsh") "zsh")
exec_zsh_with_integration exec_zsh_with_integration
;; ;;
"bash")
exec_bash_with_integration
;;
"fish") "fish")
exec_fish_with_integration exec_fish_with_integration
;; ;;
"bash")
exec_bash_with_integration
;;
esac esac
} }
@ -333,7 +330,7 @@ case "$KITTY_SHELL_INTEGRATION" in
(*) (*)
# not blank # not blank
q=$(printf "%s" "$KITTY_SHELL_INTEGRATION" | command grep '\bno-rc\b') q=$(printf "%s" "$KITTY_SHELL_INTEGRATION" | command grep '\bno-rc\b')
if [ -z "$q" ]; then if [ -z "$q" ]; then
exec_with_shell_integration exec_with_shell_integration
# exec failed, unset # exec failed, unset
unset KITTY_SHELL_INTEGRATION unset KITTY_SHELL_INTEGRATION

View File

@ -55,9 +55,9 @@ builtin typeset -gi _ksi_state
# _ksi_deferred_init. # _ksi_deferred_init.
typeset -gi _ksi_fd typeset -gi _ksi_fd
{ {
zmodload zsh/system && (( $+builtins[sysopen] )) && { builtin zmodload zsh/system && (( $+builtins[sysopen] )) && {
{ [[ -w $TTY ]] && sysopen -o cloexec -wu _ksi_fd -- $TTY } || { [[ -w $TTY ]] && builtin sysopen -o cloexec -wu _ksi_fd -- $TTY } ||
{ [[ -w /dev/tty ]] && sysopen -o cloexec -wu _ksi_fd -- /dev/tty } { [[ -w /dev/tty ]] && builtin sysopen -o cloexec -wu _ksi_fd -- /dev/tty }
} }
} 2>/dev/null || (( _ksi_fd = 1 )) } 2>/dev/null || (( _ksi_fd = 1 ))
@ -87,7 +87,7 @@ _ksi_deferred_init() {
# Recognized options: no-cursor, no-title, no-prompt-mark, no-complete. # Recognized options: no-cursor, no-title, no-prompt-mark, no-complete.
builtin local -a opt builtin local -a opt
opt=(${(s: :)KITTY_SHELL_INTEGRATION}) opt=(${(s: :)KITTY_SHELL_INTEGRATION})
unset KITTY_SHELL_INTEGRATION builtin unset KITTY_SHELL_INTEGRATION
# The directory where kitty-integration is located: /.../shell-integration/zsh. # The directory where kitty-integration is located: /.../shell-integration/zsh.
builtin local self_dir="${functions_source[_ksi_deferred_init]:A:h}" builtin local self_dir="${functions_source[_ksi_deferred_init]:A:h}"
@ -233,8 +233,17 @@ _ksi_deferred_init() {
# (LF becomes \n, etc.). This isn't necessary in precmd because (%) does it # (LF becomes \n, etc.). This isn't necessary in precmd because (%) does it
# for us. # for us.
builtin local is_ssh_session="n" builtin local is_ssh_session="n"
if [[ -n "$SSH_TTY$SSH2_TTY" ]]; then if [[ -n "$KITTY_PID" ]]; then
is_ssh_session="y"; # kitty running locally
elif [[ -n "$SSH_TTY" || -n "$SSH2_TTY$KITTY_WINDOW_ID" ]]; then
# connected to most SSH servers
# or use ssh kitten to connected to some SSH servers that do not set SSH_TTY
is_ssh_session="y"
elif [[ -n "$(builtin command -v who)" ]]; then
# the shell integration script is installed manually on the remote system
# the environment variables are cleared after sudo
# OpenSSH's sshd creates entries in utmp for every login so use those
[[ "$(builtin command who -m 2> /dev/null)" =~ "\([a-fA-F.:0-9]+\)$" ]] && is_ssh_session="y"
fi fi
if [[ "$is_ssh_session" == "y" ]]; then if [[ "$is_ssh_session" == "y" ]]; then