You are not logged in.
Pages: 1
I am trying to store the cursor position in Bash using an additional method to the normal escape sequences \e7 and \e8.
The reasoning is that I need to first store my cursor position in order to jump back to its location later, but when I later do jump, I need to store the position I am jumping from, so that I can return there again afterwards. I need to store two cursor locations, in other words.
Now, I found a way to do that second storing with a function:
savepos()
{
# Save TTY settings
exec < /dev/tty
savedtty=$(stty -g)
# Mute TTY
stty raw -echo min 0
# Catch current cursor position
echo -en "\e[6n" > /dev/tty
IFS=';' read -r -d R -a rawpos
# Restore TTY settings
stty "$savedtty"
# Extract row and column of the cursor position
eval "posrow=$((${rawpos[0]:2} - 2))"
eval "poscol=$((${rawpos[1]} - 1))"
}
I understand more or less what I do here, but obviously not completely so, because can't understand why this function only works if I call it straight.
I.e. if I call it through something like echo $(savepos), it executes, but it won't store the cursor position:
$ savepos;printf "Position: $posrow $poscol\n"
Position: 0 0
$ savepos;printf "Position: $posrow $poscol\n"
Position: 2 0
$ printf "$(savepos)Position: $posrow $poscol\n"
Position: 2 0
Any insights will be much appreciated
Offline
Store where?
$(savepos) executes savepos in a subshell - assignments there are not relevant to the parenting shell
echo $foo
echo $(foo=bar)
echo $foo
echo $(foo=bar; echo $foo)
echo $foo
Offline
Aw.. of course - that wouldn't work then
I didn't really think of
printf "$(command)"
as running command in a subshell - to me it was just an alternative to using backticks - but evidently backticks too run in a subshell :-p
What I'm trying to do is just sillybilly functionality-wise, but I got a bit pig-headed when it proved more difficult than I initially thought:
I'm trying to change the looks of the command I typed at the prompt after I have entered the command. So, say, while I type the command it is normal text, but after I press enter, before the command executes, I want it bold. As part of a fancy-prompt.thing
What I (try to) do is I have a fairly normal PS1 and do the change from PS0:
PS1="\e[0;37m\! \e[0;32m\w\e[1;33m:\e[0m\e7 "
PS0="$(savepos)\e8\e[1m\e[$posrow;0H\e[0m"
Basically my prompt shows me my history number, current path and a colon, after which I store the cursor position.
Then my PS0 stores the current cursor position (which may be anywhere with multiline commands), jumps to my PS1 stored cursor position, inserts a bold escape sequence, jumps back to the last stored position (right at the end of the entered command), inserts the escape sequence for normal text - and then the command executes.
But I'm setting the position variable in a subshell, so it won't stick.
And I guess I'm rather stuck with this one, as a subshell can't easily set a variable in the calling shell (in a normal script I could write to a file in the subshell and read it back in the calling shell or that sort of mumbo jumbo, but this is a prompt definition)?
Last edited by Ferdinand (2022-03-16 17:57:30)
Offline
https://gist.github.com/fnky/458719343a … r-controls
\e7 / \e8 or \e[s / \e[u
Offline
Thanks, that's a nice try, but \e7 and \e8 are the same as \e[s and \e[u
Using
PS1="\e[0;37m\! \e[0;32m\w\e[1;33m:\e[0m\e7 "
PS0="X\e[s\e8Y\e[u\e[1mZ"
I get
1 ~: printf "\n\n"
XZ
2 ~:
where the Z is bold, meaning it writes an "X", stores the position, restores the same position, writes an Y, restores the same position again, overwrites Y with a bold escape sequence and then a Z.
Using
PS1="\e[0;37m\! \e[0;32m\w\e[1;33m:\e[0m\e7 "
PS0="\e8\e[1mX"
I get
1 ~:Xprintf "\n\n"
2 ~:
where the X is bold, meaning it restores the position from PS1, writes bold escape sequence and then a X.
Crucially, this means writing the escape sequence in front of the old text does not make it bold, the only bold thing in that last example is the X, and that got written after the escape sequence.
This I should have checked in the first place, of course. It seems Ferdinand is rather more like a dog than a bull; following my nose without thinking
Last edited by Ferdinand (2022-03-17 08:42:07)
Offline
\e7 and \e8 are the same as \e[s and \e[u
No. See the note in the link I posted.
this means writing the escape sequence in front of the old text does not make it bold
Of course not
This I should have checked in the first place, of course.
Yes.
You'll have to move to the line and replace the text. This is certainly possible w/ zle (zsh) where you can access the $BUFFER - you should™ be able to access the last command as "!$", but whether it's ultimately possible to get this down in a function triggered by $PS0 like zsh's preexec() function idk. - I guess you'll figure
Offline
Note: Some sequences, like saving and restoring cursors, are private sequences and are not standardized. While some terminal emulators (i.e. xterm and derived) support both SCO and DEC sequences, they are likely to have different functionality. It is therefore recommended to use DEC sequences.
That's the one you mean?
ESC 7 and ESC 8 are DEC, while ESC[s and ESC[u are SCO, and they could have worked differently, but evidently, in my xfce4-terminal, they act the same.
At least that's how it looks to me, based on the example below, where I use
PS1="\e[0;37m\! \e[0;32m\w\e[1;33m:\e[0m\e7 "
PS0="X\e[s\e8Y\e[u\e[1mZ"
Of course not
Hehe, well it seems obvious now, but to my thinking the text in the terminal is stored in the terminal buffer, and is presented to the user one screenful at the time. The text may contain formatting codes that works on the text following the code, so if I modify that text by inserting a formatting code, then the text following that code should be modified according to the formatting (like text in a word processor), but I guess that's not quite how it works :-p
You'll have to move to the line and replace the text.
And, sadly, that doesn't seem possible in Bash. I can't use !! or !$ in PS0 as it doesn't expand them; theyll just be text.
I can, hower, use $BASH_COMMAND, but that variable is not assigned the command entered at PS1 by the time PS0 is displayed, so it's always one command behind. And also, the command it shows is the assignment to PS0, so it'll look like this:
PS0="$BASH_COMMAND\n"
$ echo test
PS0="the last command from .bashrc
"
test
$ echo test2
PS0="echo test
"
test2
$
So that's it then :-/
Thank's for helping out!
Offline
Pages: 1