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

Menu-driven version of history-beginning-search-backward



I was too lazy to search the mailing list archive for anything like
this, but in any case it would be good to have something like it in
the distribution.

It would be easy to expand it to allow patterns on the command line,
but it's going a little beyond the original intention.


#Start
# Menu-driven alternative to history-beginning-search-backward.
# As it uses a menu there is no sense of "forward" or "backward", however;
# the entire history is searched.
#
# Configuration:
#   autoload -U history-beginning-search-menu
#   zle -N history-beginning-search-menu
#   bindkey '\eP' history-beginning-search-menu
#
# Example:
#   % /bin/su<ESC-P>
#   Enter digit:
#   1 /bin/su -c 'make install'            4 /bin/su - perforce
#   2 /bin/su                              5 /bin/su -c
#   3 /bin/su -c 'chown pws:pws **/*(u0)'
#
# Typing "1" expands the line to
#   % /bin/su -c 'make install'
#
# With a prefix argument, the search is not anchored to the beginning,
# so for example "/su" could expand to "p4 files //depot/support/..."
#
# If this is bound to a widget containing "-end", e.g.
#   zle -N history-beginning-search-menu-end history-beginning-search-menu
# then the cursor is put at the end of the line, else it is left
# after the matched characters.

emulate -L zsh
setopt extendedglob

zmodload -i zsh/parameter

local -aU matches
local -a display

if (( ${+NUMERIC} )); then
  matches=(${history[(R)*${(q)LBUFFER}*]})
else
  matches=(${history[(R)${(q)LBUFFER}*]})
fi

# Filter out any match that's the same as the original.
# Note this isn't a pattern this time.
matches=(${matches:#${LBUFFER}})

integer n=${#matches}
integer width=${#n}

(( n == 0 )) && return 1

# Hey, this works...
integer i
display=(${matches/(#m)*/${(l.$width..0.):-$((++i))} $MATCH})
zle -R "Enter digit${${width##1}:+s}:" $display

local chars
read -k$width chars

if [[ $chars != [[:digit:]]## || $chars -eq 0 || $chars -gt $n ]]; then
  return 1
fi

if [[ $WIDGET = *-end* ]]; then
  LBUFFER=${matches[$chars]} RBUFFER=
else
  integer newcursor
  if (( ${+NUMERIC} )); then
    # Advance cursor so that it's still after the string typed
    local -a match mbegin mend
    if [[ $matches[$chars] = (#b)(*${LBUFFER})* ]]; then
      newcursor=${#match[1]}
    fi
  fi

  BUFFER=${matches[$chars]}
  (( newcursor )) && CURSOR=$newcursor
fi
#End


-- 
Peter Stephenson <pws@xxxxxxx>                  Software Engineer
CSR PLC, Churchill House, Cambridge Business Park, Cowley Road
Cambridge, CB4 0WZ, UK                          Tel: +44 (0)1223 692070


To access the latest news from CSR copy this link into a web browser:  http://www.csr.com/email_sig.php



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