Use zsh's builtin functions to do I/O with TTY
Far more robust than the system tools
This commit is contained in:
parent
f6706a55ec
commit
30e635a934
@ -2,14 +2,61 @@
|
|||||||
# Copyright (C) 2022 Kovid Goyal <kovid at kovidgoyal.net>
|
# Copyright (C) 2022 Kovid Goyal <kovid at kovidgoyal.net>
|
||||||
# Distributed under terms of the GPLv3 license.
|
# Distributed under terms of the GPLv3 license.
|
||||||
|
|
||||||
# read the transmitted data from STDIN
|
|
||||||
cleanup_on_bootstrap_exit() {
|
cleanup_on_bootstrap_exit() {
|
||||||
[ -n "$saved_tty_settings" ] && command stty "$saved_tty_settings" 2> /dev/null < /dev/tty
|
[ -n "$saved_tty_settings" ] && command stty "$saved_tty_settings" 2> /dev/null < /dev/tty
|
||||||
saved_tty_settings=""
|
saved_tty_settings=""
|
||||||
}
|
}
|
||||||
|
|
||||||
|
# try to use zsh's builtin functions for reading/writing to TTY fd as they are superior to the POSIX variants
|
||||||
|
tty_fd=-1
|
||||||
|
if builtin zmodload zsh/system 2> /dev/null; then
|
||||||
|
builtin sysopen -o cloexec -rwu tty_fd -- $TTY 2> /dev/null
|
||||||
|
[ $tty_fd = -1 ] && builtin sysopen -o cloexec -rwu tty_fd -- /dev/tty 2> /dev/null
|
||||||
|
fi
|
||||||
|
if [ $tty_fd -gt -1 ]; then
|
||||||
|
dcs_to_kitty() {
|
||||||
|
builtin local b64data
|
||||||
|
b64data=$(builtin printf "%s" "$2" | builtin command base64)
|
||||||
|
builtin print -nu "$tty_fd" '\eP@kitty-'"${1}|${b64data//[[:space:]]}"'\e\\'
|
||||||
|
}
|
||||||
|
read_one_byte_from_tty() {
|
||||||
|
builtin sysread -s "1" -i "$tty_fd" n 2> /dev/null
|
||||||
|
return $?
|
||||||
|
}
|
||||||
|
read_n_bytes_from_tty() {
|
||||||
|
builtin let num_left=$1
|
||||||
|
while [ $num_left -gt 0 ]; do
|
||||||
|
builtin sysread -c num_read -s "$num_left" -i "$tty_fd" -o "1" 2> /dev/null || die "Failed to read $num_left bytes from TTY using sysread"
|
||||||
|
builtin let num_left=$num_left-$num_read
|
||||||
|
done
|
||||||
|
}
|
||||||
|
else
|
||||||
|
dcs_to_kitty() { printf "\033P@kitty-$1|%s\033\\" "$(printf "%s" "$2" | command base64 | command tr -d \\n)" > /dev/tty; }
|
||||||
|
|
||||||
|
read_one_byte_from_tty() {
|
||||||
|
# We need a way to read a single byte at a time and to read a specified number of bytes in one invocation.
|
||||||
|
# The options are head -c, read -N and dd
|
||||||
|
#
|
||||||
|
# read -N is not in POSIX and dash/posh dont implement it. Also bash seems to read beyond
|
||||||
|
# the specified number of bytes into an internal buffer.
|
||||||
|
#
|
||||||
|
# head -c reads beyond the specified number of bytes into an internal buffer on macOS
|
||||||
|
#
|
||||||
|
# POSIX dd works for one byte at a time but for reading X bytes it needs the GNU iflag=count_bytes
|
||||||
|
# extension, and is anyway unsafe as it can lead to corrupt output when the read syscall is interrupted.
|
||||||
|
n=$(command dd bs=1 count=1 2> /dev/null < /dev/tty)
|
||||||
|
return $?
|
||||||
|
}
|
||||||
|
|
||||||
|
read_n_bytes_from_tty() {
|
||||||
|
# using dd with bs=1 is very slow, so use head. On non GNU coreutils head
|
||||||
|
# does not limit itself to reading -c bytes only from the pipe so we can potentially lose
|
||||||
|
# some trailing data, for instance if the user starts typing. Cant be helped.
|
||||||
|
command head -c "$1" < /dev/tty
|
||||||
|
}
|
||||||
|
fi
|
||||||
|
|
||||||
die() { printf "\033[31m%s\033[m\n\r" "$*" > /dev/stderr; cleanup_on_bootstrap_exit; exit 1; }
|
die() { printf "\033[31m%s\033[m\n\r" "$*" > /dev/stderr; cleanup_on_bootstrap_exit; exit 1; }
|
||||||
dcs_to_kitty() { printf "\033P@kitty-$1|%s\033\\" "$(printf "%s" "$2" | base64 | tr -d \\n)" > /dev/tty; }
|
|
||||||
debug() { dcs_to_kitty "print" "debug $1"; }
|
debug() { dcs_to_kitty "print" "debug $1"; }
|
||||||
echo_via_kitty() { dcs_to_kitty "echo" "$1"; }
|
echo_via_kitty() { dcs_to_kitty "echo" "$1"; }
|
||||||
saved_tty_settings=$(command stty -g 2> /dev/null < /dev/tty)
|
saved_tty_settings=$(command stty -g 2> /dev/null < /dev/tty)
|
||||||
@ -63,10 +110,7 @@ untar_and_read_env() {
|
|||||||
|
|
||||||
tdir=$(mktemp -d "$HOME/.kitty-ssh-kitten-untar-XXXXXXXXXXXX");
|
tdir=$(mktemp -d "$HOME/.kitty-ssh-kitten-untar-XXXXXXXXXXXX");
|
||||||
[ $? = 0 ] || die "Creating temp directory failed";
|
[ $? = 0 ] || die "Creating temp directory failed";
|
||||||
# using dd with bs=1 is very slow, so use head. On non GNU coreutils head
|
read_n_bytes_from_tty "$1" | command base64 -d | command tar xjf - --no-same-owner -C "$tdir";
|
||||||
# does not limit itself to reading -c bytes only from the pipe so we can potentially lose
|
|
||||||
# some trailing data, for instance if the user starts typing. Cant be helped.
|
|
||||||
command head -c "$1" < /dev/tty | 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"
|
||||||
@ -78,19 +122,9 @@ untar_and_read_env() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
read_record() {
|
read_record() {
|
||||||
# We need a way to read a single byte at a time and to read a specified number of bytes in one invocation.
|
|
||||||
# The options are head -c, read -N and dd
|
|
||||||
#
|
|
||||||
# read -N is not in POSIX and dash/posh dont implement it. Also bash seems to read beyond
|
|
||||||
# the specified number of bytes into an internal buffer.
|
|
||||||
#
|
|
||||||
# head -c reads beyond the specified number of bytes into an internal buffer on macOS
|
|
||||||
#
|
|
||||||
# POSIX dd works for one byte at a time but for reading X bytes it needs the GNU iflag=count_bytes
|
|
||||||
# extension, and is anyway unsafe as it can lead to corrupt output when the read syscall is interrupted.
|
|
||||||
record=""
|
record=""
|
||||||
while :; do
|
while :; do
|
||||||
n=$(command dd bs=1 count=1 2> /dev/null < /dev/tty)
|
read_one_byte_from_tty || die "Reading a byte from the TTY failed"
|
||||||
[ "$n" = "$record_separator" ] && break
|
[ "$n" = "$record_separator" ] && break
|
||||||
record="$record$n"
|
record="$record$n"
|
||||||
done
|
done
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user