zsh-workers
 help / color / mirror / code / Atom feed
From: Peter Stephenson <pws@ibmth.df.unipi.it>
To: zsh-workers@sunsite.auc.dk (Zsh hackers list)
Subject: PATCH: pws-25: more completion goodies
Date: Sun, 04 Jul 1999 18:34:19 +0200	[thread overview]
Message-ID: <9907041634.AA26457@ibmth.df.unipi.it> (raw)

As promised, here are a few completion function additions.

_default:  if magicequalsubst is set, no files matched, and the word
contains an =, try to match files after the =.  This is where the
_path_files return status is important.

_cd: if cdablevars is set and the PREFIX is not an absolute pathname and
is not a directory, try expanding it with a tilde in front --- in other
words, just what cdablevars is supposed to do (the name is a misnomer, it
should be cdablenameddirs, or something).

_read_comp: This I like.  It's a new directly bindable widget which (thanks
to Sven's key reading and redisplay changes) reads a string from the
`minibuffer' which is taken to be a set of arguments for compgen (complete
with minus signs, spaces, and any quotations).  Hence you can generate any
of the builtin completions on the fly.  Alternatively, you can enter a
string beginning with _ and it will be taken to be a completion function to
be called directly.  The longest unambiguous part of this string will be
completed automatically, sort of like emacs.  For ease of typing, the same
completion is regenerated on subsequent calls; to enter a new on-the-fly
completion, you need to give it a numeric argument.

It was a nice surprise to discover read -k and zle -R worked inside
completion widgets; the first time I hacked it as a zle widget which
defined and called a completion widget.  It wouldn't be a bad idea to allow
things like zle beep inside completion widgets too, but maybe that will
become irrelevant if we eventually merge the widget types somehow.  Maybe.

--- Completion/Base/_default.c2	Tue Apr 13 09:37:36 1999
+++ Completion/Base/_default	Sun Jul  4 16:11:11 1999
@@ -11,4 +11,11 @@
 
 compcall || return 0
 
-_files
+_files && return
+
+# magicequalsubst allows arguments like <any-old-stuff>=~/foo to do
+# file name expansion after the =.  In that case, it's natural to
+# allow completion to handle file names after any equals sign.
+if [[ -o magicequalsubst ]] && compset -P 1 '*='; then
+  _files
+fi
--- Completion/Builtins/_cd.c2	Fri Jul  2 18:57:55 1999
+++ Completion/Builtins/_cd	Sun Jul  4 16:11:02 1999
@@ -11,11 +11,8 @@
 #    it's not a lot of use.  If you don't type the + or - it will
 #    complete directories as normal.
 
-local pushdminus
-[[ -o pushdminus ]] && pushdminus=1
-
-emulate -LR zsh
-setopt extendedglob
+emulate -L zsh
+setopt extendedglob nonomatch
 
 if [[ CURRENT -eq 3 ]]; then
   # cd old new: look for old in $PWD and see what can replace it
@@ -40,8 +37,8 @@
   lines="$(dirs -v)"
   # turn the lines into an array, removing the current directory
   list=(${${(f)lines}##0*})
-  if [[ ( $IPREFIX = - && -z $pushdminus ) ||
-        ( $IPREFIX = + && -n $pushdminus ) ]]; then
+  if [[ ( $IPREFIX = - && ! -o pushdminus ) ||
+        ( $IPREFIX = + && -o pushdminus ) ]]; then
     # reverse the numbering: it counts the last one as -0, which
     # is a little strange.
     integer tot i
@@ -59,7 +56,19 @@
 
   return ret
 elif [[ $PREFIX != (\~|/|./|../)* && $#cdpath -ne 0 ]]; then
-  _path_files -W "(. $cdpath)" -/
+  local tdir
+  # With cdablevars, we can convert foo/bar/... to ~foo/bar/... if
+  # there is no directory foo.  In that case we could also complete
+  # variable names, but it hardly seems worth it.
+  # Note we need a tilde because cdablevars also allows user home
+  # directories, hence we also need nonomatch to suppress error messages.
+  if [[ -o cdablevars && ! -d ${tdir::=${PREFIX%%/*}} &&
+    -d ${~tdir2::="~$tdir"} ]]; then
+      PREFIX="~$PREFIX"
+      _path_files -/
+  else
+    _path_files -W "(. $cdpath)" -/
+  fi
 else
   _path_files -/
 fi
--- Completion/Commands/_read_comp.c2	Sun Jul  4 16:10:30 1999
+++ Completion/Commands/_read_comp	Sun Jul  4 18:28:14 1999
@@ -0,0 +1,128 @@
+#compdef -k complete-word \C-x\C-r
+
+# This allows an on-the-fly choice of completions.  On typing the key
+# sequence given above, you will be prompted for a string of arguments.  If
+# this string begins with `_', it will be taken as the name of a function to
+# evaluate to generate the completions; unambiguous strings in the function
+# name are automatically completed.
+#
+# Else it is taken to be a set of arguments for compgen to generate a list
+# of choices.  The possibilities are the same as the flags for generating
+# completions given in the zshcompctl manual page.  Note the arguments are
+# verbatim:  include minus signs, spaces, quotes, etc.
+#
+# On subsequent calls, the same completion will be re-performed.  To
+# force a new type of completion to be read, supply a numeric argument.
+#
+# For example,
+#  % bindkey | grep rever<C-xC-r>
+#  Completion: -b<RET>
+#  % bindkey | grep reverse-menu-complete _
+#
+# Global variables used:
+#  _read_comp         Last completion string read from user
+
+emulate -L zsh
+
+# Took me ages to work this out.  If we're not on the first global
+# matcher specification, we mustn't do any I/O.
+if [[ compstate[matcher] -gt 1 && -n $_read_comp ]]; then
+  return 1
+fi
+
+if [[ compstate[matcher] -gt 1 ||
+  ( ${+NUMERIC} = 0 && -n $_read_comp ) ]]; then
+  if [[ $_read_comp = _* ]]; then
+    eval $_read_comp
+  else
+    eval "compgen $_read_comp"
+  fi
+  return
+fi
+
+local key search str str2 newch funcs funcs2 exact msg
+integer pos
+
+msg="Completion: "
+
+zle -R $msg
+
+if ! read -k key; then
+  zle -R ''
+  return 1
+fi
+
+while [[ '#key' -ne 10 && '#key' -ne 13 ]]; do
+  if [[ '#key' -eq 3 || '#key' -eq 7 ]]; then
+    zle -R ''
+    return 1
+  fi
+  if [[ '#key' -eq 8 || '#key' -eq 127 ]]; then
+    str="$str[1,-2]"
+    exact=
+  elif [[ -n $exact ]]; then
+    if [[ -n $ZBEEP ]]; then
+      print -nb $ZBEEP
+    elif [[ -o beep ]]; then
+      print "\a"
+    fi
+  else
+    str="$str$key"
+    if [[ $str = _* ]]; then
+      # Rudimentary completion for function names.
+      funcs=(${$(whence -m "$str*")%: function})
+      if (( $#funcs == 1 )); then
+	# Exact match; prompt the user for a newline to confirm
+	str=$funcs[1]
+	exact=" (Confirm)"
+      elif (( $#funcs == 0 )); then
+	# We can't call zle beep, because this isn't a zle widget.
+	if [[ -n $ZBEEP ]]; then
+	  print -nb $ZBEEP
+	elif [[ -o beep ]]; then
+	  print "\a"
+	fi
+	str="$str[1,-2]"
+      else
+	# Add characters to the string until a name doesn't
+	# match any more, then backtrack one character to get
+	# the longest unambiguous match.
+	str2=$str
+	pos=$#str2
+	while true; do
+	  (( pos++ ))
+	  newch=${funcs[1][pos]}
+	  [[ -z $newch ]] && break
+	  str2=$str2$newch
+	  funcs2=(${funcs##$str2*})
+	  (( $#funcs2 )) && break
+	  str=$str2
+	done
+      fi
+    fi
+  fi
+  zle -R "$msg$str$exact"
+  if ! read -k key; then
+    zle -R ''
+    return 1
+  fi
+done
+
+if [[ -z $str ]]; then
+  # string must be non-zero
+  return 1
+elif [[ $str = _* ]] && ! whence $str >& /dev/null; then
+  # a function must be known to the shell
+  return 1
+else
+  # remember the string for re-use
+  _read_comp=$str
+fi
+
+zle -R ''
+
+if [[ $str = _* ]]; then
+  eval $str
+else
+  eval "compgen $str"
+fi

-- 
Peter Stephenson <pws@ibmth.df.unipi.it>       Tel: +39 050 844536
WWW:  http://www.ifh.de/~pws/
Dipartimento di Fisica, Via Buonarroti 2, 56127 Pisa, Italy


             reply	other threads:[~1999-07-04 17:03 UTC|newest]

Thread overview: 3+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
1999-07-04 16:34 Peter Stephenson [this message]
1999-07-05 13:40 Sven Wischnowsky
1999-07-05 14:23 ` Peter Stephenson

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=9907041634.AA26457@ibmth.df.unipi.it \
    --to=pws@ibmth.df.unipi.it \
    --cc=zsh-workers@sunsite.auc.dk \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
Code repositories for project(s) associated with this public inbox

	https://git.vuxu.org/mirror/zsh/

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).