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

PATCH: completion of glob qualifiers



This is mostly useful as a memory jogger rather than actually to save
you typing a single character.  However, I've added a pretty useless
function to save you typing a delimiter character.  (The alternative
was simply to print a message saying "delimiter", which was
really low tech.)

It works OK so far but it does raise various issues about related things
that might be got to work better.  You might run across those.

The change to _alternative fixes a pretty obvious bug.  Presumably
no one has been using it with arguments that just print a message.

Index: Completion/Base/Utility/_alternative
===================================================================
RCS file: /cvsroot/zsh/zsh/Completion/Base/Utility/_alternative,v
retrieving revision 1.3
diff -u -r1.3 _alternative
--- Completion/Base/Utility/_alternative	13 Mar 2003 10:00:21 -0000	1.3
+++ Completion/Base/Utility/_alternative	23 Feb 2008 00:04:31 -0000
@@ -75,7 +75,7 @@
 done
 
 for descr in "$mesgs[@]"; do
-  _message -e "${descr%%:*}" "${desc#*:}"
+  _message -e "${descr%%:*}" "${descr#*:}"
 done
 
 return 1
Index: Completion/Unix/Type/_path_files
===================================================================
RCS file: /cvsroot/zsh/zsh/Completion/Unix/Type/_path_files,v
retrieving revision 1.26
diff -u -r1.26 _path_files
--- Completion/Unix/Type/_path_files	25 Oct 2007 09:00:04 -0000	1.26
+++ Completion/Unix/Type/_path_files	23 Feb 2008 00:04:32 -0000
@@ -6,8 +6,9 @@
 local linepath realpath donepath prepath testpath exppath skips skipped
 local tmp1 tmp2 tmp3 tmp4 i orig eorig pre suf tpre tsuf opre osuf cpre
 local pats haspats ignore pfx pfxsfx sopt gopt opt sdirs ignpar cfopt listsfx
-local nm=$compstate[nmatches] menu matcher mopts sort match mid accex fake
+local nm=$compstate[nmatches] menu matcher mopts sort mid accex fake
 local listfiles listopts tmpdisp
+local -a match mbegin mend
 
 typeset -U prepaths exppaths
 
@@ -349,7 +350,19 @@
 
     tmp2=( "$tmp1[@]" )
 
-    if [[ "$tpre$tsuf" = */* ]]; then
+    # Look for glob qualifiers.
+    # Extra nastiness to be careful about a quoted parenthesis.
+    # The initial tests look for parentheses with zero or an
+    # even number of backslashes in front.
+    # The later test looks for an outstanding quote.
+    if [[ ( -o bareglobqual && \
+	      "$tpre/$tsuf" = (#b)((*[^\\]|)(\\\\)#\()([^\)]#) || \
+            -o extendedglob && \
+		"$tpre/$tsuf" = (#b)((*[^\\]|)(\\\\)#"(#q")([^\)]#) \
+	  ) && -z $compstate[quote] ]]; then
+       compset -p ${#match[1]}
+       _globquals
+    elif [[ "$tpre$tsuf" = */* ]]; then
       compfiles -P$cfopt tmp1 accex "$skipped" "$_matcher $matcher[2]" "$sdirs" fake
     elif [[ "$sopt" = *[/f]* ]]; then
       compfiles -p$cfopt tmp1 accex "$skipped" "$_matcher $matcher[2]" "$sdirs" fake "$pats[@]"
Index: Completion/Zsh/Type/_delimiters
===================================================================
RCS file: Completion/Zsh/Type/_delimiters
diff -N Completion/Zsh/Type/_delimiters
--- /dev/null	1 Jan 1970 00:00:00 -0000
+++ Completion/Zsh/Type/_delimiters	23 Feb 2008 00:04:32 -0000
@@ -0,0 +1,16 @@
+#autoload
+
+# Simple function to offer delimiters for modifiers and qualifers.
+# Single argument is tag to use.
+
+local expl
+local -a list
+
+zstyle -a ":completion:${curcontext}:$1" delimiters list ||
+  list=(: + / - %)
+
+if (( ${#list} )); then
+  _wanted delimiters expl delimiter compadd -S '' -a list
+else
+  _message delimiter
+fi
Index: Completion/Zsh/Type/_globqual_delims
===================================================================
RCS file: Completion/Zsh/Type/_globqual_delims
diff -N Completion/Zsh/Type/_globqual_delims
--- /dev/null	1 Jan 1970 00:00:00 -0000
+++ Completion/Zsh/Type/_globqual_delims	23 Feb 2008 00:04:32 -0000
@@ -0,0 +1,24 @@
+#autoload
+
+# Helper for _globquals.  Sets delim to delimiter to match.
+
+# don't restore special parameters
+compstate[restore]=no
+
+delim=$PREFIX[1]
+compset -p 1
+
+# One of matching brackets?
+# These don't actually work: the parser gets very confused.
+local matchl="<({[" matchr=">)}]"
+integer ind=${matchl[(I)$delim]}
+
+(( ind )) && delim=$matchr[ind]
+
+if compset -P "[^$delim]#$delim"; then
+  # Completely matched.
+  return 0
+else
+  # Still in delimiter
+  return 1
+fi
Index: Completion/Zsh/Type/_globquals
===================================================================
RCS file: Completion/Zsh/Type/_globquals
diff -N Completion/Zsh/Type/_globquals
--- /dev/null	1 Jan 1970 00:00:00 -0000
+++ Completion/Zsh/Type/_globquals	23 Feb 2008 00:04:32 -0000
@@ -0,0 +1,233 @@
+#autoload
+
+local state=qual expl char delim
+local -a alts
+
+while [[ -n $PREFIX ]]; do
+  char=$PREFIX[1]
+  compset -p 1
+  case $char in
+    ([-/F.@=p*rwxAIERWXsStUG^MTNDn,])
+    # no argument
+    ;;
+
+    (%)
+    # optional b, c
+    if [[ $PREFIX[1] = [bc] ]]; then
+      compset -p 1
+    fi
+    ;;
+
+    (f)
+    if ! compset -P "[-=+][0-7?]##"; then
+      if [[ -z $PREFIX ]]; then
+	_delimiters qualifier-f
+	return
+      elif ! _globqual_delims; then
+	# still completing mode spec
+	_message "mode spec"
+	return
+      fi
+    fi
+    ;;
+
+    (e)
+    # complete/skip delimited command line
+    if [[ -z $PREFIX ]]; then
+      _delimiters qualifer-e
+      return
+    elif ! _globqual_delims; then
+      # still completing command to eval
+      compset -q
+      _normal
+      return
+    fi
+    ;;
+
+    (+)
+    # complete/skip command name (no delimiters)
+    if [[ $PREFIX = [[:IDENT:]]# ]]; then
+      # either nothing there yet, or still on name
+      _command_names
+      return
+    fi
+    compset -P '[[:IDENT:]]##'
+    ;;
+
+    (d)
+    # complete/skip device
+    if [[ -z $PREFIX ]]; then
+      _message device ID
+      return
+    fi
+    # It's pointless trying to complete the device.
+    # Simply assume it's done.
+    compset -p '[[:digit:]]##'
+    ;;
+
+    (l)
+    # complete/skip link count
+    if [[ PREFIX = ([-+]|) ]]; then
+      _message link count
+      return
+    fi
+    # It's pointless trying to complete the link count.
+    # Simply assume it's done.
+    compset -P '([-+]|)[[:digit:]]##'
+    ;;
+
+    (u)
+    # complete/skip UID or delimited user
+    if ! compset -P '[[:digit:]]##'; then
+      if [[ -z $PREFIX ]]; then
+	_delimiters qualifier-u
+	return
+      elif ! _globqual_delims; then
+	# still completing user
+	_users -S $delim
+	return
+      fi
+    fi
+    ;;
+
+    (g)
+    # complete/skip GID or delimited group
+    if ! compset -P '[[:digit:]]##'; then
+      if [[ -z $PREFIX ]]; then
+	_delimiter qualifier-g
+	return
+      elif ! _globqual_delims; then
+	# still completing group
+	_groups -S $delim
+	return
+      fi
+    fi
+    ;;
+
+    ([amc])
+    if ! compset -P '([Mwhms]|)([-+]|)<->'; then
+      # complete/skip relative time spec
+      alts=()
+      if ! compset -P '[Mwhms]' && [[ -z $PREFIX ]]; then
+	alts+=(
+	  "time-specifiers:time specifier:\
+((M\:months w\:weeks h\:hours m:\minutes s\:seconds))")
+      fi
+      if ! compset -P '[-+]' && [[ -z $PREFIX ]]; then
+	alts+=("senses:sense:((-\:less\ than +\:more\ than))")
+      fi
+      alts+=('digits:digit: ')
+      _alternative $alts
+      return
+    fi
+    ;;
+
+    (L)
+    # complete/skip file size
+    if ! compset -P '([kKmMpP]|)([-+]|)<->'; then
+      # complete/skip size spec
+      alts=()
+      if ! compset -P '[kKmMpP]' && [[ -z $PREFIX ]]; then
+	alts+=(
+	  "size-specifiers:size specifier:\
+((k\:kb m\:mb p\:512-byte\ blocks))")
+      fi
+      if ! compset -P '[-+]' && [[ -z $PREFIX ]]; then
+	alts+=("senses:sense:((-\:less\ than +\:more\ than))")
+      fi
+      alts+=('digits:digit: ')
+      _alternative $alts
+      return
+    fi
+    ;;
+    
+    ([oO])
+    # complete/skip sort spec
+    if ! compset -P "?"; then
+      alts=(
+	"n:lexical order of name"
+	"L:size of file"
+	"l:number of hard links"
+	"a:last access time"
+	"m:last modification time"
+	"c:last inode change time"
+	"d:directory depth"
+	)
+      _describe -t sort-specifiers "sort specifier" alts -Q -S ''
+      return
+    fi
+    ;;
+
+    (\[)
+    # complete/skip range: check for closing bracket
+    if ! compset -P "(-|)[[:digit:]]##(,(-|)[[:digit:]]##|)]"; then
+      if compset -P "(-|)[[:digit:]]##,"; then
+	_message end of range
+      else
+	_message start of range
+      fi
+      return
+    fi
+    ;;
+
+    (:)
+    # complete modifiers and don't stop completing them
+    _history_modifiers
+    return
+    ;;
+  esac
+done
+
+case $state in
+  (qual)
+  local -a quals
+  quals=(
+    "/:directories"
+    "F:non-empty directories"
+    ".:plain files"
+    "@:symbolic links"
+    "=:sockets"
+    "p:name pipes (FIFOS)"
+    "*:executable plain files"
+    "%:device files"
+    "r:owner-readable"
+    "w:owner-writeable"
+    "x:owner-executable"
+    "A:group-readable"
+    "I:group-writeable"
+    "E:group-executable"
+    "R:world-readable"
+    "W:world-writeable"
+    "X:world-executable"
+    "s:setuid"
+    "S:setgid"
+    "t:sticky bit set"
+    "f:+ access rights"
+    "e:execute code"
+    "+:+ command name"
+    "d:+ device"
+    "l:+ link count"
+    "U:owned by EUID"
+    "G:owned by EGID"
+    "u:+ owning user"
+    "g:+ owning group"
+    "a:+ access time"
+    "m:+ modification time"
+    "c:+ inode change time"
+    "L:+ size"
+    "^:negate qualifiers"
+    "-:follow symlinks toggle"
+    "M:mark directories"
+    "T:mark types"
+    "N:use NULL_GLOB"
+    "D:glob dots"
+    "n:numeric glob sort"
+    "o:+ sort order, up"
+    "O:+ sort order, down"
+    "[:+ range of files"
+    "):end of qualifiers"
+    "\::modifier"
+    )
+  _describe -t globquals "glob qualifier" quals -Q -S ''
+  ;;
+esac
Index: Completion/Zsh/Type/_history_modifiers
===================================================================
RCS file: Completion/Zsh/Type/_history_modifiers
diff -N Completion/Zsh/Type/_history_modifiers
--- /dev/null	1 Jan 1970 00:00:00 -0000
+++ Completion/Zsh/Type/_history_modifiers	23 Feb 2008 00:04:32 -0000
@@ -0,0 +1,84 @@
+#autoload
+
+# Complete history-style modifiers; the first : will have
+# been matched and compset -p 1'd.
+# The single argument is the type of context:
+#   h  history
+#   q  glob qualifier
+#   p  parameter
+
+local -a list
+
+local type=$1 delim expl
+integer global
+
+while true; do
+  if [[ -n $PREFIX ]]; then
+    local char=$PREFIX[1]
+
+    global=0
+    compset -p 1
+    case $char in
+      ([hretpqQxlu\&])
+      # single character modifiers
+      ;;
+
+      (s)
+      # match delimiter string delimiter string delimiter
+      if [[ -z $PREFIX ]]; then
+	_delimiters modifier-s
+	return
+      fi
+      delim=$PREFIX[1]
+      compset -p 1
+      if ! compset "[^$delim]#$delim[^$delim]#$delim"; then
+	if compset "[^$delim]#$delim"; then
+	  _message original string
+	else
+	  _message replacement string
+	fi
+	return
+      fi
+      ;;
+
+      (g)
+      global=1
+      continue
+      ;;
+    esac
+
+    # modifier completely matched, see what's next.
+    compset -P : && continue
+    # if there's something other than colon next, bummer
+    [[ -n $PREFIX ]] && return 1
+
+    list=("\::modifier")
+    [[ $type = g ]] && list+=("):end of qualifiers")
+    # strictly we want a normal suffix if end of qualifiers
+    _describe -t delimiters "delimiter" list -Q -S ''
+  else
+    list=(
+      "s:substitute string"
+      "&:repeat substitution"
+      )
+    if (( ! global )); then
+      list+=(
+	"g:globally apply s or &"
+	"h:head - strip trailing path element"
+	"t:tail - strip directories"
+	"r:root - strip suffix"
+	"e:leave only extension"
+	"Q:strip quotes"
+	"l:lower case all words"
+	"u:upper case all words"
+	)
+      [[ $type = h ]] && list+=(
+	"p:print without executing"
+	"x:quote words, breaking on whitespace"
+	)
+      [[ $type = [hp] ]] && list+=("q:quote to escape further substitutions")
+    fi
+    _describe -t modifiers "modifier" list -Q -S ''
+    return
+  fi
+done
Index: Doc/Zsh/compsys.yo
===================================================================
RCS file: /cvsroot/zsh/zsh/Doc/Zsh/compsys.yo,v
retrieving revision 1.203
diff -u -r1.203 compsys.yo
--- Doc/Zsh/compsys.yo	25 Oct 2007 09:00:05 -0000	1.203
+++ Doc/Zsh/compsys.yo	23 Feb 2008 00:04:35 -0000
@@ -1262,6 +1262,15 @@
 insertion of matches should be delayed unconditionally. The default is 
 `true'.
 )
+kindex(delimiters, completion style)
+item(tt(delimiters))(
+This style is used when adding a delimiter for use with history
+modifiers or glob qualifiers that have delimited arguments.  It is
+an array of preferred delimiters to add.  Non-special characters are
+preferred as the completion system may otherwise become confused.
+The default list is tt(:), tt(+), tt(/), tt(-), tt(%).  The list
+may be empty to force a delimiter to be typed.
+)
 kindex(disabled, completion style)
 item(tt(disabled))(
 If this is set to `true', the tt(_expand_alias) completer and bindable 


-- 
Peter Stephenson <p.w.stephenson@xxxxxxxxxxxx>
Web page now at http://homepage.ntlworld.com/p.w.stephenson/



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