Reputation: 3244
I'm trying to read into a variable the current cursor position (the current line number and column) into a variable, from within a function drawing the ZSH shell prompt. My goal is to display stuff below the prompt, only if there are enough empty lines to not cause extra scrolling.
In an interactive shell, I can use the following commands:
echo -ne "\033[6n"
read -t 1 -s -d 'R' line
line="${line##*\[}"
line="${line%;*}"
echo "XX $line XX"
# Prints: XX 2 XX"
However, if I start a clean zsh -f
, and put this into a function which is executed when rendering the prompt, it stops working:
setopt prompt_subst
prompt_fn(){
echo -ne "\033[6n"
read -t 1 -s -d 'R' line
line="${line##*\[}"
line="${line%;*}"
echo "XX $line XX"
}
PROMPT='`prompt_fn` '
The ANSI escape sequence returned by the terminal gets appended to the current command (as if I had typed it on my keyboard), but is not gobbled by the read -t 1 -s -d 'R' line
command above. I suspect that ZSH disables access to STDIN while drawing the prompt, but I do not know how to regain access to it temporarily (normal keyboard keystrokes typed before drawing the prompt, or during the tenth of second that it takes to draw it should not be intercepted), or how to use ZLE to access that information.
Edit: if the user already typed the beginning of a command before the prompt was shown, that input should not be discarded. The solution I found so far (see my own answer below) unfortunately reads and drops these characters. This is frustrating, as when I open a new terminal window and start typing right away, the characters typed before the prompt appears are discarded.
Upvotes: 4
Views: 1923
Reputation: 106
Maybe you want to look into the minibuffer
based off of these docs:
http://zsh.sourceforge.net/Guide/zshguide04.html
The `minibuffer' is yet another Emacs concept; it is a prompt that appears just under the command line for you to enter some edit required by the editor itself.
I used it in a zsh plugin to print out help for the command under the cursor. I only display text, but you should be able to do other things with it.
You can also find some information on zsh widgets here
This might be relevant:
BUFFERLINES (integer)
The number of screen lines needed for the edit buffer currently displayed on screen (i.e. without any changes to the preceding parameters done after the last redisplay); read-only.
Upvotes: 1
Reputation: 3244
Reading directly from /dev/tty
seems to mostly work, but it still gobbles any input typed between the beginning of prompt_fn
and the read
command. If the prompt_fn
is doing a bit of work before getting to that point, it may cause some user input to be dropped. Hopefully someone will come along with a better solution.
setopt prompt_subst
prompt_fn(){
echo -ne "\033[6n" > /dev/tty
read -t 1 -s -d 'R' line < /dev/tty
line="${line##*\[}"
line="${line%;*}"
echo "XX $line XX"
}
PROMPT='`prompt_fn` '
Upvotes: 4