Skip to content

Commit

Permalink
confirm: fix line erasure if cursor response took too long
Browse files Browse the repository at this point in the history
  • Loading branch information
balupton committed Sep 4, 2023
1 parent 2dcb950 commit d7a3b11
Show file tree
Hide file tree
Showing 2 changed files with 19 additions and 14 deletions.
27 changes: 16 additions & 11 deletions commands/confirm
Original file line number Diff line number Diff line change
Expand Up @@ -165,6 +165,7 @@ function confirm_() (
fi

# used to process the input
local CURSOR_COLUMN='' # used by do_read and do_question
function do_read {
local answer read_status

Expand Down Expand Up @@ -241,23 +242,26 @@ function confirm_() (

# try reading again, and erase any leaked characters
if test "$using_tty_stderr_fallback" = 'no'; then
printf '\e[%sG\e[K' "$hx" >"$tty_target"
# set the cursor back to CURSOR_COLUMN and erase everything after it
if test -n "$CURSOR_COLUMN"; then
printf '\e[%sG\e[K' "$CURSOR_COLUMN" >"$tty_target"
fi
fi
do_read
}

function do_question {
local _ hx

# if not a tty, just output the question
if test "$using_tty_stderr_fallback" = 'yes'; then
echo-lines -- "${option_question[@]}" >"$tty_target"
else
# output the prompt, saving the cursor position
hx=''
CURSOR_COLUMN=''
print_string "$prompt " >"$tty_target"
# read cursor x y, discard y, set hx to y
IFS='[;' read -t "$(get_read_decimal_timeout 0.01)" -srd R -p $'\e[6n' _ _ hx <"$tty_target" || :
# send an ansi query to fetch the cursor row and column, returns [^[[24;80R] where 24 is row, 80 is column
# use _ to discard, the first read var is garbage, the second read var is the column, the final read var is the column
# don't use a timeout, as we already in a TTY so can guarantee an answer, and the read will complete immediately upon a response thanks to [-d R] which completes reading when the R is read, which is the final character of the response query
local _
IFS='[;' read -srd R -p $'\e[6n' _ _ CURSOR_COLUMN <"$tty_target" || :

# output the body if it exists
if test -n "$body"; then
Expand All @@ -270,9 +274,9 @@ function confirm_() (
fi
fi

# move to the hx column
if test -n "$hx"; then
printf '\e[%sG' "$hx" >"$tty_target"
# move to the CURSOR_COLUMN column
if test -n "$CURSOR_COLUMN"; then
printf '\e[%sG' "$CURSOR_COLUMN" >"$tty_target"
fi
fi

Expand Down Expand Up @@ -350,7 +354,8 @@ function confirm_() (
return "$RESULT"

# @todo
# an alternative implementation could be a new line like this at the end, with ENTER and ESCAPE and SPACE as the correct outputs
# if the above read cursor position issue is a problem (e.g. press a keypress before the cursor position answer is fetched, so keypress goes into the cursor position read), then one could use `print_line question | echo-trim-special | wc -c` however that is unreliable as doesn't take into account terminal size and wrapping, etc.
# the better solution would be to just append a newline like this below, with ENTER and ESCAPE and SPACE as the correct outputs:
# echo-style --blink='Press: ' --blink+green+bold='y ' --blink='for ' --blink+green='YES' --blink=', ' --blink+red+bold='n ' --blink='for ' --blink+red='NO' --blink=', ' --blink+bold='ENTER ' --blink='for ' --blink+red='NO'

# using \e[s (save) and \e[u (restore) for ctrl+c handling did not work
Expand Down
6 changes: 3 additions & 3 deletions commands/get-terminal-theme
Original file line number Diff line number Diff line change
Expand Up @@ -122,13 +122,13 @@ function get_terminal_theme() (
# stdin+stderr must be readable+writable for the read to work, but we can't check silently, as failures are noisey, and silencing the failures causes them to close: https://gist.github.com/balupton/6eee015345c663d7d7baf83d8e20ce1f so just note in this comment
# as terminal theme is really only important for TTY use cases, use is-tty, this also solves vscode unable to ssh session into a machine
if is-tty; then
# </dev/tty >/dev/tty is used to ensure data = book in this example:
# </dev/tty is used to ensure data = book in this example (don't need >/dev/tty as -s flag prevents output):
# echo 'book' | {
# IFS=: read -s -t 1 -d $'\a' -p $'\e]11;?\a' _ color </dev/tty >/dev/tty;
# IFS=: read -s -t 1 -d $'\a' -p $'\e]11;?\a' _ color </dev/tty;
# read -t 1 data
# echo data = $data
# }
IFS=: read -s -t "$(get_read_decimal_timeout 0.01)" -d $'\a' -p $'\e]11;?\a' _ color </dev/tty >/dev/tty || :
IFS=: read -s -t "$(get_read_decimal_timeout 0.01)" -d $'\a' -p $'\e]11;?\a' _ color </dev/tty || :
if test -n "$color"; then
# Fetch the first two characters of [1a]74/[2b]98/[3c]b6 which is our color, and convert from hexadecimal to decimal
# For what the latter two characters are, no one seems to know: https://unix.stackexchange.com/q/754952/50703
Expand Down

0 comments on commit d7a3b11

Please sign in to comment.