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

Completing newest file



I've just realised how to do something I've wanted zsh to do for a
long time, and I couldn't resist sharing it...

If you follow the instructions in the version of `multicomp' below,
then typing ^X. (pick your own binding, of course) will allow you to
complete something or other to just the newest of all matching
completions (glob patterns are also expanded, but only one or the
other, i.e. if you have wild cards and want completion as well you
need to stick a * at the end).  If you have files containing ":+",
choose some other non-wildcard-containing string.

(I disovered exchange-point-and-mark is broken while I was doing
this.  Somebody will no doubt be eager to fix this :-/)

The main problem is that if nothing matches you get a bogus :+ still
on the command line.  That can be fixed by forcing multicomp to return
the original string without the :+.  Exercise for the reader.

You'll need zsh 2.6 for all the stuff (such as localoptions) to work.

# multicomp() {
# Completes all manner of files given prefixes for each path segment.
# e.g. s/z/s -> src/zsh-2.4/src
#
# Usage: e.g.
# compctl -D -f + -U -K multicomp
#
# Note that exactly matched directories are not expanded, e.g.
# s/zsh-2.4/s<TAB> will not expand to src/zsh-2.4old/src.
# Will expand glob patterns already in the word, but use complete-word,
# not TAB (expand-or-complete), or you will get ordinary glob expansion.
# Requires the -U option to compctl.
# Menucompletion is highly recommended for ambiguous matches.
# Liable to screw up escaped metacharacters royally.
# $fignore is not used: feel free to add your own bit.
#
# There's a hack builtin: if the the pre-cursor text ends with :+,
# that is removed.  Then only the newest file is returned at the end.
# This allows the following:
#
# bindkey "\C-X/" complete-word
# bindkey -s "\C-X." ":+\C-X/"
#
# after which (if you have multicomp installed in completion as above)
# typing \C-X. at the end of a glob pattern or a file prefix will
# replace the pattern with the newest matching file or newest possible
# completion respectively.

local pref head sofar origtop newtop wild newf
integer newest

setopt localoptions rcexpandparam nullglob

if [[ $1 = *:+ ]]; then
  # Hack to allow completion to the most recent file.
  newest=1
  pref=${1%:+}$2
else
  pref=${1}$2
fi

sofar=('')
reply=('')

if [[ "$pref[1]" = '~' ]]; then
  # If the string started with ~, save the head and what it will become.
  origtop="${pref%%/*}"
  [[ "$origtop" = */ ]] && origtop[-1]=
  # Next line assumes cshjunkietilde was not set.  See note on toggles above.
  newtop=${~origtop}
  # Save the expansion as the bit matched already
  sofar=($newtop)
  pref="$pref[$#origtop+1,-1]"
elif [[ -z $pref ]]; then
  pref="*"
fi

while [[ -n "$pref" ]]; do
  [[ "$pref" = /* ]] && sofar=(${sofar}/) && pref="$pref[2,-1]"
  head="${pref%%/*}"
  [[ "$head" = */ ]] && head[-1]=
  pref="$pref[$#head+1,-1]"
  if [[ "$pref" = /* && -z $sofar[2] && -d "${sofar}$head" ]]; then
    # Exactly matched directory: don't try to glob
    reply=("${sofar}$head")
  else
    # if patch segment contains wildcards, don't add another.
    if [[ $pref = /* ]]; then
      wild='*(-/)'
    elif [[ "$head" = *[\*\?]* ]]; then
      wild=
    else
      wild='*(ND^M)'
    fi
    # $sofar must be expanded with rcexpandparam here, in such a way
    # that metacharacters are expanded in the eval step.
    reply=(${^sofar}"${head}${wild}")
    eval "reply=($reply)"

  fi

  [[ -z $reply[1] ]] && reply=() && break
  [[ -n $pref ]] && sofar=($reply)
done

if let '$#reply > 1 && newest'; then
  # Get the newest file.
  newf=$reply[1]
  shift reply
  for wild in $reply; do
    [[ $wild -nt $newf ]] && newf=$wild
  done
  reply=($newf)
fi

# Restore ~'s in front if there were any.
# There had better not be anything funny in $newtop.
[[ -n "$origtop" ]] && eval "reply=(\$reply:gs?$newtop?\\$origtop?)"

# }

-- 
Peter Stephenson <P.Stephenson@xxxxxxxxxxxxx>  Tel: +44 1792 205678 extn. 4461
WWW:  http://python.swan.ac.uk/~pypeters/      Fax: +44 1792 295324
Department of Physics, University of Wales, Swansea,
Singleton Park, Swansea, SA2 8PP, U.K.



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