about summary refs log tree commit diff
diff options
context:
space:
mode:
authorPeter Stephenson <pws@users.sourceforge.net>2008-02-23 00:10:24 +0000
committerPeter Stephenson <pws@users.sourceforge.net>2008-02-23 00:10:24 +0000
commit485a008075ce19bfdf19922c803d1637ebb5255e (patch)
treefce4fa1a9d5ca8b236760b8c9b05bb06e7d9a801
parent21307324337a613ef53e437219ddcbc3f3bb53ff (diff)
downloadzsh-485a008075ce19bfdf19922c803d1637ebb5255e.tar.gz
zsh-485a008075ce19bfdf19922c803d1637ebb5255e.tar.xz
zsh-485a008075ce19bfdf19922c803d1637ebb5255e.zip
24585: completion for glob qualifiers plus
bug fix for _alternative
-rw-r--r--ChangeLog11
-rw-r--r--Completion/Base/Utility/_alternative2
-rw-r--r--Completion/Unix/Type/_path_files17
-rw-r--r--Completion/Zsh/Type/_delimiters16
-rw-r--r--Completion/Zsh/Type/_globqual_delims24
-rw-r--r--Completion/Zsh/Type/_globquals233
-rw-r--r--Completion/Zsh/Type/_history_modifiers84
-rw-r--r--Doc/Zsh/compsys.yo9
8 files changed, 393 insertions, 3 deletions
diff --git a/ChangeLog b/ChangeLog
index 18b351bee..7ad5991c9 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,14 @@
+2008-02-23  Peter Stephenson  <p.w.stephenson@ntlworld.com>
+
+	* 24585: Completion/Base/Utility/_alternative,
+	Completion/Unix/Type/_path_files,
+	Completion/Zsh/Type/_delimiters,
+	Completion/Zsh/Type/_globqual_delims,
+	Completion/Zsh/Type/_globquals,
+	Completion/Zsh/Type/_history_modifiers, Doc/Zsh/compsys.yo:
+	completion for glob qualifiers plus bug fix for message-only
+	completion in _alternative.
+
 2008-02-22  Peter Stephenson  <pws@csr.com>
 
 	* unposted: Completion/Unix/Command/_perforce: new option
diff --git a/Completion/Base/Utility/_alternative b/Completion/Base/Utility/_alternative
index c7b71d9bc..bfb34a604 100644
--- a/Completion/Base/Utility/_alternative
+++ b/Completion/Base/Utility/_alternative
@@ -75,7 +75,7 @@ while _tags; do
 done
 
 for descr in "$mesgs[@]"; do
-  _message -e "${descr%%:*}" "${desc#*:}"
+  _message -e "${descr%%:*}" "${descr#*:}"
 done
 
 return 1
diff --git a/Completion/Unix/Type/_path_files b/Completion/Unix/Type/_path_files
index 4176005c3..e75e81efd 100644
--- a/Completion/Unix/Type/_path_files
+++ b/Completion/Unix/Type/_path_files
@@ -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 @@ for prepath in "$prepaths[@]"; do
 
     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[@]"
diff --git a/Completion/Zsh/Type/_delimiters b/Completion/Zsh/Type/_delimiters
new file mode 100644
index 000000000..bb5bba8d0
--- /dev/null
+++ b/Completion/Zsh/Type/_delimiters
@@ -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
diff --git a/Completion/Zsh/Type/_globqual_delims b/Completion/Zsh/Type/_globqual_delims
new file mode 100644
index 000000000..bba4241e8
--- /dev/null
+++ b/Completion/Zsh/Type/_globqual_delims
@@ -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
diff --git a/Completion/Zsh/Type/_globquals b/Completion/Zsh/Type/_globquals
new file mode 100644
index 000000000..0262c8b6f
--- /dev/null
+++ b/Completion/Zsh/Type/_globquals
@@ -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
diff --git a/Completion/Zsh/Type/_history_modifiers b/Completion/Zsh/Type/_history_modifiers
new file mode 100644
index 000000000..085867159
--- /dev/null
+++ b/Completion/Zsh/Type/_history_modifiers
@@ -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
diff --git a/Doc/Zsh/compsys.yo b/Doc/Zsh/compsys.yo
index 04fc6ecfa..c609991d6 100644
--- a/Doc/Zsh/compsys.yo
+++ b/Doc/Zsh/compsys.yo
@@ -1262,6 +1262,15 @@ This style is used by the tt(_list) completer function to decide if
 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