On Wed, 30 Sep 2009 09:52:10 -0700 (PDT)
Guido van Steen <gvsteen@xxxxxxxxx> wrote:
> I use the "history-beginning-search-backward" widget quite
> frequently. It searches for commands in the command history that START
> WITH "LBUFFER".
>
> I like this behaviour. It is simple and it keeps my attention fixed on
> one line. What I don't like about the widget is that ONLY searches for
> commands that start with "LBUFFER". Instead I would prefer a similar
> widget that searches for commands in the command history, in such a way
> that "LBUFFER" is a SUBSTRING of these commands.
(I moved this to zsh-users.)
This seemed to work. I stole a lot of it from
history-beginning-search-menu. It implements forward and backward
searches, so you can do something like
zle -N history-substring-search-forward history-substring-search-backward
zle -N history-substring-search-backward
bindkey '\ep' history-substring-search-backward
bindkey '\en' history-substring-search-forward
At this point, it is traditional for people to say it's absolutely
crucial that the cursor be posititioned etc. etc...
pws
# history-substring-search-backward
# can also be used for the widget history-substring-search-forward.
emulate -L zsh
setopt extendedglob
zmodload -i zsh/parameter
local search=$LBUFFER MATCH MBEGIN MEND
typeset -g ZLE_HISTORY_SUBSTRING_MATCH
if [[ $LASTWIDGET = history-substring-search-* ]]; then
# here's one I prepared earlier
search=$ZLE_HISTORY_SUBSTRING_MATCH
else
# We need to quote metacharacters in the search string
# since they are otherwise active in the reverse subscript.
# We need to avoid quoting other characters since they aren't
# and just stay quoted, rather annoyingly.
search=${LBUFFER//(#m)[\][()\\*?#<>~^]/\\$MATCH}
ZLE_HISTORY_SUBSTRING_MATCH=$search
fi
local -aU matches
matches=(${(kon)history[(R)*${search}*]})
# Filter out any match that's the same as the original.
# Note this isn't a pattern this time.
matches=(${matches:#${LBUFFER}})
(( ${#matches} )) || return 1
if [[ $WIDGET = *forward* ]]; then
eval "matches=(\${matches:#<-$HISTNO>})"
(( ${#matches} )) || return 1
HISTNO=${matches[1]}
else
eval "matches=(\${matches:#<$HISTNO->})"
(( ${#matches} )) || return 1
HISTNO=${matches[-1]}
fi