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

Re: Feature Request: HIST_STORE_BANG option

On Aug 4,  2:55pm, Matt Gerassimoff wrote:
} Subject: Feature Request:  HIST_STORE_BANG option
} Alot of times I would like to get back the substitution I used
} several commands ago but can't because the actual command (after
} the substitution) is stored.  Could a option be implemented,
} HIST_STORE_BANG, that would store the command before the substitution
} took place?

This would be difficult because of the way history expansion takes place.
History is expanding during lexical analysis of the input; that is, at
the same time that the characters are being read.  Zsh "pretends" that
what you typed was the text -after- history substitution.  Consequently,
zsh never "sees" the entire unexpanded input.

Even if it could be implemented, the potential for confusion would be
very high.  Consider:

zsh% echo This line is one.
This line is one.
zsh% !!:s/one/another/
echo This line is another.
This line is another.
zsh% !!
zsh: command not found: !!:s/one/another/

What should history references to unexpanded history references mean?
Expand a second time?  What does the !! in the second expansion mean?

What you're really asking for is the ability to scroll back through the
line editor input as if it were distinct from the shell's command input.
(Zsh used to do something almost-but-not-quite like that, back when it
had options to distinguish "literal" from "lexical" history.)  The best
way to implement that would not be a history option, but a modification
to ZLE itself, to store and fetch lines from the previous editor input
rather than from the history.

Here's a simple implementation of this using the zle widget facilities
of zsh 3.1.4.  It lacks searching and other history facilities, but you
can scroll up and down just fine.  Note that if you abort an edit with
^C or ^G, the scrollback position is left unchanged (is that a feature?).

--- 8< --- snip --- 8< ---


zle_store () {
    zle_lines=($zle_lines $BUFFER) 
    zle accept-line

zle_fetch_previous () {
    ((zle_hist -= ${1:-1}))
    if ((zle_hist > 0 && zle_hist <= $#zle_lines))
        if ((zle_hist == 0))
        echo -en '\a'

zle_fetch_next () {
    zle_fetch_previous -${1:-1}

zle -N zle_store zle_store
zle -N zle_fetch_next zle_fetch_next
zle -N zle_fetch_previous zle_fetch_previous

# If we bind this to ^M, then ^J can be used to avoid entering a line
# into the zle_lines history, and to accept-line in an emergency in
# case the zle_store function gets messed up somehow.
bindkey \^M zle_store

# Choose reasonable bindings for the following; ^P and ^N override the
# usual history up/down bindings (so I commented out these lines).
#bindkey \^P zle_fetch_previous
#bindkey \^N zle_fetch_next

--- 8< --- snip --- 8< ---

Bart Schaefer                                 Brass Lantern Enterprises
http://www.well.com/user/barts              http://www.brasslantern.com

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