7

I want to create a widget bound to a hotkey that prints the current command description in rich text below the prompt, then erases it after a keypress. Like so (simplified):

widget() {
  zle -R "ls - list files"
  read -k 1
}
zle -N widget
bindkey '\eg' widget

But zle -R can print only plain text, it doesn't even support line breaks. I want to print text with color and line breaks like ^[[31mls^[[00m - list files.

What approaches can I use to do that?

Just printing it to a regular stdout then initializing a new prompt would be a bad user interface for my use case. That would be an undesirable solutions.

I want it to appear below the prompt and work similarly to zsh-autocomplete, ctrl+R, or fzf. The output doesn't have any complex interactions, it only appears on hotkey and disappears on keypress after that.

The zsh-autocomplete repo does similar, but I don’t know how it is done.

James Risner
  • 5,451
  • 11
  • 25
  • 47
Poma
  • 8,174
  • 18
  • 82
  • 144
  • `zle -R $'\e[31mls\e[00m - list files'` doesn't work? – Fravadona Mar 09 '23 at 14:50
  • No, it can only print plain text. Control codes will show up in terminal. – Poma Mar 10 '23 at 03:28
  • You said that even linebreaks don't work; did you try with a literal one? `zle -R $'ls - \n list files'` – Fravadona Mar 10 '23 at 06:29
  • Yes I did. If you want to suggest that my statements are false, it's a good idea to test your claims first. – Poma Mar 10 '23 at 09:39
  • you provided an example but I don’t know how to use it; btw, a literal newline isn’t `'\n'` but `$'\n'`; because you didn't comment on that construct I wasn't sure that you tested it, sorry for that – Fravadona Mar 10 '23 at 10:51
  • 1
    `zle -R` [can't output any kind of control characters](https://www.zsh.org/mla/users/2011/msg00100.html), at least that was the case at the time of this thread (which is pretty old to be fair) – Poma Mar 10 '23 at 13:14
  • I'm not a master on zsh, but I know a few things. I spend a few hours on this one and I couldn't find something. Maybe an expert could help. – tur1ng Mar 19 '23 at 15:34

1 Answers1

3

When you use zle -R, you end up calling this function inside zsh. The first argument after -R is stored in statusline. That is checked here and stripped of any characters that would modify the screen unexpectedly here. So the mailing list question from 2011 is still present today.

Upon review of the hooks and the code in zsh-autocomplete, I now understand this works by using built in support for color highlighting in zsh while actively using autocomplete.

Since you just wish to have a key binding to display the status line and await for a keystroke, you will need to write (in C) a module to display the current BUFFER and await a keystroke. This will require you to track the cursor position and maintaining the same state that zsh is expecting.

The example module is a start. You will need to compile it with zsh, as the build script builds all modules with tools needed to create the .mdh/.pro files from the .mdd of your module.

Here is an updated widget that demonstrates the various options:

widget() {
  autoload -Uz colors && colors
  PREDISPLAY="PRE:"
  POSTDISPLAY="${fg[red]}POST$reset_color"
  zle -R "$BUFFER" "${fg[red]}line below$reset_color"
  print "${fg[red]}print$reset_color"
  read -k 1
}
zle -N widget

Notice, you can't control the display of the status line, it has all special characters removed. The print properly allows special characters, but only on the input line (not on the status line). PRE/POST also only work on the input line, and also are stripped of special characters.

What approaches can I use to do that?

  • Write your own module. This is the best way.
  • you may be able to use print to color it as you wish, but you would need to still make sure the screen positions are maintained as zsh expects.
James Risner
  • 5,451
  • 11
  • 25
  • 47
  • This answer states that zsh-autocomplete manages to do it, but doesn't really explain *how* apart from "it adds some hooks that do the thing". Can you explain what functions does it use to print the text? I already tried to dive into zsh-autocomplete repo but it's too complex for me to find the relevant parts. – Poma Mar 20 '23 at 04:59
  • I think it could be done at least with some clever printing into the current buffer and erasing it after keypress. – Poma Mar 21 '23 at 10:31