Zsh Mailing List Archive
Messages sorted by: Reverse Date, Date, Thread, Author

Proposal (with code) to fix breaking of history widgets on reset-prompt



Hi,

If your [up] key is bound to up-line-or-beginning-search, like most people
have it, try the following experiment. Type sleep 6& and hit [enter]. Then
quickly press [up] and wait for the job to finish. Once it finishes, press
[up] again. Oh no! History doesn’t work. You are supposed to see the
command you’d typed before sleep 6& but you are likely still seeing sleep 6&
.

Here’s what’s going on. When jobs finish, zle .reset-prompt is called to
re-expand and display prompt. This sets LASTWIDGET to .reset-prompt. When
you press [up] after that, up-line-or-beginning-search will behave as if
you’ve typed sleep 6& in your prompt and then pressed [up]. That is, it’ll
search for the previous command in your history that starts with sleep 6&.

up-line-or-beginning-search breaks whenever reset-prompt is called. This
happens when jobs finish and also when ZSH themes with async support want
to refresh prompt after collecting some data in the background. For
example, Powerlevel10k <https://github.com/romkatv/powerlevel10k> theme
shows a greyed-out prompt when entering a large git repo and then updates
it once it figures out git status in the background. If the user has
pressed [up] while the prompt was grey, they’ll be surprised to find that
[up] doesn’t work as expected once prompt updates.

One potential fix for this issue is to change reset-prompt widget so that
it keeps LASTWIDGET unchanged. I’ve implemented this change in
https://github.com/romkatv/zsh/tree/gentle-reset-prompt. Diff against
upstream:
https://github.com/zsh-users/zsh/compare/master...romkatv:gentle-reset-prompt
.

The same branch also adds -W option to zle widget command. This option
instructs zle to keep LASTWIDGET unchanged. I added it because it’s a
natural extension of what I’ve done with .reset-prompt and because it has
solved a long-standing issue I had in my zsh config.

The long-stating problem is that I want my [up] key to behave as
up-line-or-beginning-search with local history turned on, so that it
doesn’t see history from other sessions, and my [ctrl+up] key as
up-line-or-beginning-search with local history turned off. This is very
difficult to achieve. The only solution I’ve found is to fork
up-line-or-beginning-search and edit its source code. You can see it in my
dotfiles
<https://github.com/romkatv/dotfiles-public/blob/88218b6fa6801ad4448b04a6893966b9221c1491/bin/local-history.zsh>.
With the new -W flag that I added to zle widget this problem has a clear
solution. Like this:

# This zle widget is the same as the standard
up-line-or-beginning-search# but restricted to local history.
function up-line-or-beginning-search-local() {
  zle .set-local-history -W 1
  up-line-or-beginning-search
  zle .set-local-history -W 0
}
zle -N up-line-or-beginning-search-local

What do you think?

Roman.


Messages sorted by: Reverse Date, Date, Thread, Author