简体   繁体   中英

Get current cursor position while drawing ZSH prompt

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.

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` '

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.

cheat buffer example

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 (ie without any changes to the preceding parameters done after the last redisplay); read-only.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM