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

Re: Zle history feature like that of many IRC clients?

On Dec 19, 10:39pm, milk wrote:
: Specifically, if I were to type something, then
: press the down arrow and get a blank input line

So what you're asking for is to bind down-arrow to a sort of "put this
in the history but don't send it" action?

Presumably, though, if you've already pressed up-arrow at least once so
you are in the middle of the history, then you just want down-arrow to
move through the history like it normally does.

Let's build it up from some pieces.  First, a "fake-accept-line" to
not really execute the command, but put it on the history.  There are
several different ways to do this with preexec hooks etc., but let's
just do it the old-fashioned way:

    fake-accept-line() {
      if [[ -n "$BUFFER" ]];
	print -S "$BUFFER"
	zle .send-break
      return 0
    zle -N fake-accept-line

If your version of zsh doesn't have "print -S", use "-s" instead.  It's
not perfect but it'll do.  Using "zle .send-break" at the end sets the
correct return value and makes the history from "print -S" immediately
available for recall, but interrupts whatever else you have going on so
it does mean that fake-accept-line has to be the last thing you want to
do before getting a new prompt.

The leading dot in ".send-break" tells zle to call the widget by its
unalterable name, so you won't be messed up by some other configuration
rebinding the widget.  Make note of this for below.  Also note that you
can't create an unalterable name for a user-defined widget, those are
only for builtins.

Next you want a function that does down-line-or-history [probably; you
might want down-history instead, but I can't tell from your description]
unless there is nowhere to go, in which case it does fake-accept-line.

    down-or-fake-accept-line() {
      (( HISTNO == HISTCMD )) && zle fake-accept-line
      zle .down-line-or-history "$@"                     
    zle -N down-or-fake-accept-line

There I've done a shortcut:  I know fake-accept-line is going to break
out of the surrounding function if it does anything at all, so there's
no need for an else-case, I can fall through to down-line-or-history.

Finally you just need to bind it to a key.  To avoid all the messiness
of figuring out what sequence of characters your down-arrow key may
send, it's often easier to simply grab the widget that is already bound
to that key and alias it to your new widget.

    zle -N down-line-or-history down-or-fake-accept-line

This has now swapped out down-line-or history for this widget anywhere
that down-line-or-history was used (such as, all the default keymaps),
but not inside down-or-fake-accept-line itself, where we have avoided
infinite recursion by using the unalterable name.

If you prefer not to do it this way, add a bindkey command such as

    bindkey '^[[B' down-or-fake-accept-line

which depending on your terminal might mean down-arrow.

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