In a contrived example, if I have the following:
sup="$(printf "\e[s" > /dev/tty; printf "one" > /dev/tty; printf "\e[u\e[Jtwo" > /dev/tty)"
The output will successfully erase one
leaving only:
two
However, if I use echo "one"
to print a newline with it:
sup="$(printf "\e[s" > /dev/tty; echo "one" > /dev/tty; printf "\e[u\e[Jtwo" > /dev/tty)"
Then the output is:
one
two
Why would the newline break the cursor handling? And how could I work around it?
A more comprehensive example would be:
sup="$(printf "\e[s" > /dev/tty; for (( i=0; i<5; i )); do echo -e "a random number is:\n$RANDOM" > /dev/tty; sleep 1; printf "\e[u\e[J" > /dev/tty; done; echo 'result')"
echo "sup=$sup" # sup=result
CodePudding user response:
I suspect that you're writing to the last line of the window. Writing a newline will cause the window contents to scroll. When you restore the cursor position with ESC [ u
, it returns to the physical position in the window that was saved with ESC [ s
, not the position in the scroll buffer. But the word one
will have scrolled up one line, so two
will be written to the line after it rather than overwriting it.
CodePudding user response:
As @Barmer's answer alluded to, the reason why restore cursor does not work, is that saving the cursor only saves the left/right margins, not the row:
Saves the cursor position/state in SCO console mode.[22] In vertical split screen mode, instead used to set (as CSI n ; n s) or reset left and right margins.[23] https://en.wikipedia.org/wiki/ANSI_escape_code#CUP
I was able to come up with a portable solution that does not need me to count line numbers.
tty.bash
#!/usr/bin/env bash
# sourced from:
# https://stackoverflow.com/a/69138082/130638
# inspired by:
# https://unix.stackexchange.com/a/88304/50703
# https://stackoverflow.com/a/2575525/130638
# https://askubuntu.com/a/366158/22776
# https://stackoverflow.com/a/5810220/130638
get_tty_snapshot () {
local pos oldstty y x y_offset="${1:-0}" x_offset="${2:-0}"
exec < /dev/tty
oldstty=$(stty -g)
stty raw -echo min 0
echo -en "\e[6n" > /dev/tty
IFS=';' read -r -d R -a pos
stty "$oldstty"
y="$((${pos[0]:2} - 2 y_offset))"
x="$((pos[1] - 1 x_offset))"
echo -en "\e[${y};${x}H\e[J"
}
use_tty_snapshot () {
echo -en "$1" > /dev/tty
}
embed.bash
#!/usr/bin/env bash
source "./tty.bash"
tty_snapshot="$(get_tty_snapshot)"
for (( i=0; i<5; i )); do
echo -e "one random number $RANDOM\nanother random number: $RANDOM" > /dev/tty
sleep 1
use_tty_snapshot "$tty_snapshot"
done
echo 'result'
example.bash
#!/usr/bin/env bash
echo "ask result"
result="$(./test-cursor-embed)"
echo "got result=[$result]"