about summary refs log tree commit diff
diff options
context:
space:
mode:
-rw-r--r--Completion/Base/Widget/_read_comp151
1 files changed, 151 insertions, 0 deletions
diff --git a/Completion/Base/Widget/_read_comp b/Completion/Base/Widget/_read_comp
new file mode 100644
index 000000000..bc6e4c3c6
--- /dev/null
+++ b/Completion/Base/Widget/_read_comp
@@ -0,0 +1,151 @@
+#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 compadd to generate a list
+# of choices.  The possibilities are the same as the flags for generating
+# completions given in the zshcompwid 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
+setopt localoptions extendedglob nobadpattern # xtrace promptsubst
+# local PS4='%N:%i:$((#key))> '
+
+if [[ ${+NUMERIC} = 0 && -n $_read_comp ]]; then
+  if [[ $_read_comp = _* ]]; then
+    eval $_read_comp
+  else
+    eval "compadd $_read_comp"
+  fi
+  return
+fi
+
+_read_comp=
+
+local key search str str2 newch funcs funcs2 exact msg list
+integer pos
+
+msg="Completion: "
+
+zle -R $msg
+
+if ! read -k key; then
+  zle -cR ''
+  return 1
+fi
+
+while [[ '#key' -ne 10 && '#key' -ne 13 ]]; do
+  if [[ '#key' -eq 0 && '#key' -eq 3 || '#key' -eq 7 ]]; then
+    zle -cR ''
+    return 1
+  fi
+  if [[ ( '#key' -eq 8 || '#key' -eq 127 ) && -n $str ]]; then
+    # delete character
+    str="$str[1,-2]"
+    exact=
+    list=()
+  elif [[ '#key' -eq 21 ]]; then
+    # ^U: delete line
+    str=
+    exact=
+    list=()
+  elif [[ '#key' -eq 4 && $str = _[^\ ]# && $str != *' '* ]]; then
+    # ^D: list completions
+    list=(${$(whence -m "$str*" 2>/dev/null)%: function})
+  elif [[ ( -n $exact && $key != ' ' ) || '#key & 127' -lt 32 ]]; then
+    # If we've got an exact function, only allow a space after it.
+    # Don't try to insert non-printing characters.
+    if [[ -n $ZBEEP ]]; then
+      print -nb $ZBEEP
+    elif [[ -o beep ]]; then
+      print -n "\a"
+    fi
+    list=()
+  else
+    str="$str$key"
+    if [[ $str = _[^\ ]# ]]; then
+      # Rudimentary completion for function names.
+      # Allow arguments, i.e. don't do this after we've got a space.
+      funcs=(${$(whence -m "$str*" 2>/dev/null)%: function})
+      if [[ -o autolist && $#str -gt 1 ]]; then
+	list=($funcs)
+      else
+	list=()
+      fi
+      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 -n "\a"
+	fi
+	str="$str[1,-2]"
+	list=()
+      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
+    else
+      exact=
+    fi
+  fi
+  if (( $#list )); then
+    zle -R "$msg$str$exact" $list
+  else
+    zle -cR "$msg$str$exact"
+  fi
+  if ! read -k key; then
+    zle -cR ''
+    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 -cR ''
+
+if [[ $str = _* ]]; then
+  eval $str
+else
+  eval "compadd $str"
+fi