about summary refs log tree commit diff
path: root/Misc/new-completion-examples
diff options
context:
space:
mode:
Diffstat (limited to 'Misc/new-completion-examples')
-rw-r--r--Misc/new-completion-examples453
1 files changed, 453 insertions, 0 deletions
diff --git a/Misc/new-completion-examples b/Misc/new-completion-examples
new file mode 100644
index 000000000..659679891
--- /dev/null
+++ b/Misc/new-completion-examples
@@ -0,0 +1,453 @@
+# Define a new widget behaving like `expand-or-complete' but calling the
+# function `main-complete' to generate matches.
+
+zle -c my-comp expand-or-complete main-complete
+
+bindkey '\C-i' my-comp
+
+
+# Below is a proposed main loop and the things it needs.
+
+# One associative array for normal completions and one for patterns.
+
+typeset -A comps
+
+
+# These may be used to define completion handlers. First argument is the
+# name of the function/variable containing the definition, the other
+# arguments are the command names for which this definition should be used.
+# With only one argument the function/variable-name __$1 is used.
+
+defcomp() {
+  local v
+
+  if [[ $# -eq 1 ]] then
+    comps[$1]="__$1"
+  else
+    v="$1"
+    shift
+    for i; do
+      comps[$i]="$v"
+    done
+  fi
+}
+
+defpatcomp() {
+  if [[ ${+patcomps} == 1 ]] then
+    patcomps=("$patcomps[@]" "$2 $1" )
+  else
+    patcomps=( "$2 $1" )
+  fi
+}
+
+
+# These can be used to easily save and restore the state of the special
+# variables used by the completion code.
+
+alias compsave='local _opre _oipre _oargs _ocur;_opre="$PREFIX";_oipre="$IPREFIX";_oargs=( "$@" );_ocur="$CURRENT"'
+alias compreset='PREFIX="$_opre";IPREFIX="$_oipre";argv=( "$_oargs[@]" );CURRENT="$_ocur"'
+
+# This is an easy way to get completion for sub-commands.
+
+alias compsub='do-complete "$@" || return 1'
+
+# This searches $1 in the array for normal completions and calls the result.
+
+compalso() {
+  1="$comps[$1]"
+  [[ -z "$1" ]] || call-complete "$@"
+}
+
+# This generates matches. The first argument is something we got from one
+# of the associative arrays above. This is expected to be either the name
+# of a variable in which case we use its value as arguments to complist,
+# or it is the name of a function in which case we call this function with
+# the arguments from the command line as its arguments.
+
+call-complete() {
+  local var
+
+  eval var\=\$\{\+$1\}
+  if [[ "$var" == 0 ]] then
+    "$@"
+  else
+    eval complist \$\{${1}\[\@\]\}
+  fi
+}
+
+# The main loop of the competion code. This is what is called when TAB is
+# pressed. The completion code gives us the special variables and the
+# arguments from the command line are gives as positional parameters.
+
+main-complete() {
+  emulate -R zsh
+  local comp
+  setopt localoptions nullglob rcexpandparam globdots
+  unsetopt markdirs globsubst shwordsplit nounset
+
+  # An entry for `--first--' is the replacement for `compctl -T'
+  # The `|| return 1' is used throughout: if a function producing matches
+  # returns non-zero this is interpreted as `do not try to produce more matches'
+  # (this is the replacement for `compctl -t').
+
+  comp="$comps[--first--]"
+  [[ -z "$comp" ]] || call-complete "$comp" "$@" || return 1
+
+  # For arguments we use the `do-complete' function below called via the
+  # convenience alias `compsub'.
+
+  if [[ $CONTEXT == argument || $CONTEXT == command ]] then
+    compsub
+  else
+    # Let's see if we have a special completion definition for the other
+    # possible contexts.
+
+    comp=''
+
+    case $CONTEXT in
+    redirect)  comp="$comps[--redir--]";;
+    math)   comp="$comps[--math--]";;
+    subscript) comp="$comps[--subscr--]";;
+    value)  comp="$comps[--value--]";;
+    condition)   comp="$comps[--cond--]";;
+    esac
+
+    # If not, we use default completion, if any.
+
+    [[ -z "$comp" ]] && comp="$comps[--default--]"
+    [[ -z "$comp" ]] || call-complete "$comp" "$@" || return 1
+  fi
+}
+
+# This does completion for a command (in command position and for the
+# arguments).
+
+do-complete() {
+  local comp cmd1 cmd2 pat val
+
+  # Completing in command position? If not we set up `cmd1' and `cmd2' as
+  # two strings we have search in the completion definition arrays (e.g.
+  # a path and the last path name component).
+
+  if [[ $CONTEXT == command ]] then
+    comp="$comps[--command--]"
+    [[ -z "$comp" ]] || call-complete "$comp" "$@" || return 1
+    return 0
+  elif [[ "$COMMAND[1]" == '=' ]] then
+    eval cmd1\=$COMMAND
+    cmd2="$COMMAND[2,-1]"
+  elif [[ "$COMMAND" == */* ]] then
+    cmd1="$COMMAND"
+    cmd2="${COMMAND:t}"
+  else
+    cmd1="$COMMAND"
+    eval cmd2=$(whence -p $COMMAND)
+  fi
+
+  # See if there are any matching pattern completions.
+
+  for i in "$patcomps[@]"; do
+    pat="${i% *}"
+    val="${i#* }"
+    if [[ "$cmd1" == $~pat || "$cmd2" == $~pat ]] then
+      call-complete "$val" "$@" || return 1
+    fi
+  done
+
+  # Now look up the two names in the normal completion array.
+
+  comp="${comps[$cmd1]:-$comps[$cmd2]}"
+
+  # And generate the matches, probably using default completion.
+
+  [[ -z "$comp" ]] && comp="$comps[--default--]"
+  [[ -z "$comp" ]] || call-complete "$comp" "$@" || return 1
+}
+
+# Do sub-completion for pre-command modifiers.
+
+defcomp __precmd - noglob nocorrect exec command builtin
+__precmd() {
+  COMMAND="$1"
+  shift
+  (( CURRENT-- ))
+  if [[ CURRENT -eq 0 ]] then
+    CONTEXT=command
+  else
+    CONTEXT=argument
+  fi
+  compsub
+}
+
+# Utility function for in-path completion.
+# First argument should be an complist-option (e.g. -f, -/, -g). The other
+# arguments should be glob patterns, one per argument.
+# E.g.: files -g '*.tex' '*.texi'
+# This is intended as a replacement for `complist -f', `complist -/', and
+# `complist -g ...' (but don't use it with other options).
+# This function behaves as if you have a matcher definition like:
+#   compctl -M 'r:|[-.,_/]=* r:|=* m:{a-z}={A-Z} m:-=_ m:.=,'
+# so you may want to modify this.
+
+pfiles() {
+  local nm str pa pre epre a b c s rest
+
+  setopt localoptions nullglob rcexpandparam globdots extendedglob
+  unsetopt markdirs globsubst shwordsplit nounset
+
+  nm=$NMATCHES
+  if [[ $# -eq 0 ]] then
+    complist -f
+  elif [[ "$1" = -g ]] then
+    complist -g "$argv[2,-1]"
+    shift
+  else
+    complist $1
+    shift
+  fi
+  [[ -nmatches nm ]] || return
+
+  str="$PREFIX*$SUFFIX"
+
+  [[ -z "$1" ]] && 1='*'
+  if [[ $str[1] = \~ ]] then
+    pre="${str%%/*}/"
+    eval epre\=$pre
+    str="${str#*/}"
+    pa=''
+  else
+    pre=''
+    epre=''
+    if [[ $str[1] = / ]] then
+      str="$str[2,-1]"
+      pa='/'
+    else
+      pa=''
+    fi
+  fi
+  str="$str:gs/,/*,/:gs/_/*_/:gs./.*/.:gs/-/*[-_]/:gs/./*[.,]/:gs-*[.,]*[.,]*/-../-:gs.**.*."
+  while [[ "$str" = */* ]] do
+    rest="${str#*/}"
+    a="${epre}${pa}(#l)${str%%/*}(-/)"
+    a=( $~a )
+    if [[ $#a -eq 0 ]] then
+      return
+    elif [[ $#a -gt 1 ]] then
+      c=()
+      s=( $rest$@ )
+      s=( "${(@)s:gs.**.*.}" )
+      for i in $a; do
+        b=( $~i/(#l)$~s )
+        eval b\=\( \$\{b:/\*\(${(j:|:)fignore}\)\} \)
+        [[ $#b -ne 0 ]] && c=( $c $i )
+      done
+      if [[ $#c -eq 0 ]] then
+        return
+      elif [[ $#c -ne 1 ]] then
+        a="$epre$pa"
+        c=( $~c/(#l)$~s )
+        eval c\=\( \$\{c:/\*\(${(j:|:)fignore}\)\} \)
+	c=( ${c#$a} )
+        for i in $c; do
+          compadd -p "$pre$pa" -W "$a" -s "/${i#*/}" -f "${i%%/*}"
+        done
+	return
+      fi
+      a=( "$c[1]" )
+    fi
+    a="$a[1]"
+    pa="$pa${a##*/}/"
+    str="$rest"
+  done
+  a="$epre$pa"
+  s=( $str$@ )
+  s=( "${(@)s:gs.**.*.}" )
+  b=( $~a(#l)$~s )
+  eval b\=\( \$\{b:/\*\(${(j:|:)fignore}\)\} \)
+  compadd -p "$pre$pa" -W "$epre$pa" -f ${b#$a}
+}
+
+# Utility function for completing files of a given type or any file.
+# In many cases you will want to call this one instead of pfiles().
+
+files() {
+  local nm
+
+  nm=$NMATCHES
+  pfiles "$@"
+
+  [[ $# -ne 0 && -nmatches nm ]] && pfiles
+}
+
+# Simple default, command, and math completion defined with variables.
+
+defcomp __default --default--
+__default() {
+  files
+}
+
+defcomp __command --command--
+__command=( -c )
+
+defcomp __math --math--
+__math=( -v )
+
+defcomp __subscr --subscr--
+__subscr() {
+  compalso --math-- "$@"
+  # ...probably other stuff
+}
+
+# A simple pattern completion, just as an example.
+
+defpatcomp __x_options '*/X11/*'
+__x_options() {
+  complist -J options -k '(-display -name -xrm)'
+}
+
+# A better example: completion for `find'.
+
+defcomp find
+__find() {
+  compsave
+
+  if [[ -mbetween -(ok|exec) \\\; ]] then
+    compsub
+  elif [[ -iprefix - ]] then
+    complist -s 'daystart {max,min,}depth follow noleaf version xdev \
+	{a,c,}newer {a,c,m}{min,time} empty false {fs,x,}type gid inum links \
+	{i,}{l,}name {no,}{user,group} path perm regex size true uid used \
+	exec {f,}print{f,0,} ok prune ls'
+    compreset
+  elif [[ -position 1 ]] then
+    complist -g '. ..'
+    files -g '(-/)'
+  elif [[ -mcurrent -1 -((a|c|)newer|fprint(|0|f)) ]] then
+    files
+  elif [[ -current -1 -fstype ]] then
+    complist -k '(ufs 4.2 4.3 nfs tmp mfs S51K S52K)'
+  elif [[ -current -1 -group ]] then
+    complist -k groups
+  elif [[ -current -1 -user ]] then
+    complist -u
+  fi
+}
+
+# Various completions...
+
+defcomp __gunzip gunzip zcat
+__gunzip() {
+  files -g '*.[gG][z]'
+}
+
+defcomp gzip
+__gzip() {
+  files -g '*~*.[gG][zZ]'
+}
+
+defcomp xfig
+__xfig() {
+  files -g '*.fig'
+}
+
+defcomp __make make gmake
+__make() {
+  complist -s "\$(awk '/^[a-zA-Z0-9][^/ 	]+:/ {print \$1}' FS=: [mM]akefile)"
+}
+
+defcomp __ps gs ghostview gview psnup psselect pswrap pstops pstruct lpr
+__ps() {
+  files -g '*([pP][sS]|eps)'
+}
+
+defcomp __which which whence
+__which=( -caF )
+
+defcomp __rlogin rlogin rsh ssh
+__rlogin() {
+  if [[ -position 1 ]] then
+    complist -k hosts
+  elif [[ -position 2 ]] then
+    complist -k '(-l)'
+  elif [[ -position 3 && -word 1 artus ]] then
+    complist -k '(puck root)'
+  fi
+}
+
+defcomp __dvi xdvi dvips dvibook dviconcat dvicopy dvidvi dviselect dvitodvi dvitype
+__dvi() {
+  files -g '*.(dvi|DVI)'
+}
+
+defcomp __dirs rmdir df du dircmp cd
+__dirs() {
+  files -/ '*(-/)'
+}
+
+defcomp __jobs fg bg jobs
+__jobs=(-j -P '%?')
+
+defcomp kill
+__kill() {
+  if [[ -iprefix '-' ]] then
+    complist -k signals
+  else
+    complist -P '%?' -j
+  fi
+}
+
+defcomp __uncompress uncompress zmore
+__uncompress() {
+  files -g '*.Z'
+}
+
+defcomp compress
+__compress() {
+  files -g '*~*.Z'
+}
+
+defcomp __tex tex latex glatex slitex gslitex
+__tex() {
+  files -g '*.(tex|TEX|texinfo|texi)'
+}
+
+defcomp __options setopt unsetopt
+__options=(-M 'L:|[nN][oO]= M:_= M:{A-Z}={a-z}' -o)
+
+defcomp __funcs unfunction
+__funcs=(-F)
+
+defcomp __aliases unalias
+__aliases=(-a)
+
+defcomp __vars unset
+__vars=(-v)
+
+defcomp __enabled disable
+__enabled=(-FBwa)
+
+defcomp __disabled enable
+__disabled=(-dFBwa)
+
+defcomp __pdf acroread
+__pdf() {
+  files -g '*.(pdf|PDF)'
+}
+
+defcomp tar
+__tar() {
+  local nm tf
+  compsave
+
+  tf="$2"
+  nm=$NMATCHES
+  if [[ ( -mword 1 *t*f* || -mword 1 *x*f* ) && -position 3 100000 ]] then
+    complist -k "( $(tar tf $tf) )"
+    compreset
+  elif [[ -mword 1 *c*f* && -position 3 100000 ]] then
+    files
+    compreset
+  elif [[ -mcurrent -1 *f* && -position 2 ]] then
+    files -g '*.(tar|TAR)'
+  fi
+}