about summary refs log tree commit diff
path: root/Completion
diff options
context:
space:
mode:
Diffstat (limited to 'Completion')
-rw-r--r--Completion/Commands/_correct_filename2
-rw-r--r--Completion/Commands/_correct_word17
-rw-r--r--Completion/Core/compinit111
-rw-r--r--Completion/Core/compinstall415
4 files changed, 382 insertions, 163 deletions
diff --git a/Completion/Commands/_correct_filename b/Completion/Commands/_correct_filename
index 53ed6d113..baef38edf 100644
--- a/Completion/Commands/_correct_filename
+++ b/Completion/Commands/_correct_filename
@@ -1,4 +1,4 @@
-#compdef -k complete-word \C-xc
+#compdef -k complete-word \C-xC
 
 # Function to correct a filename.  Can be used as a completion widget,
 # or as a function in its own right, in which case it will print the
diff --git a/Completion/Commands/_correct_word b/Completion/Commands/_correct_word
index db3023860..d0abcd4fe 100644
--- a/Completion/Commands/_correct_word
+++ b/Completion/Commands/_correct_word
@@ -3,10 +3,23 @@
 # Simple completion front-end implementing spelling correction.
 # The maximum number of errors is set quite high, and
 # the numeric prefix can be used to specify a different value.
+#
+# If configurations keys with the prefix `correctword_' are
+# given they override those starting with `correct_'.
 
 local oca="$compconfig[correct_accept]"
-compconfig[correct_accept]=6n
+local oco="$compconfig[correct_original]"
+local ocp="$compconfig[correct_prompt]"
+local oci="$compconfig[correct_insert]"
+
+compconfig[correct_accept]="${compconfig[correctword_accept]-6n}"
+compconfig[correct_original]="${compconfig[correctword_original]-$oco}"
+compconfig[correct_prompt]="${compconfig[correctword_prompt]-$ocp}"
+compconfig[correct_insert]="${compconfig[correctword_insert]}"
 
 _main_complete _correct
 
-compconfig[correct_accept]=$oca
+compconfig[correct_accept]="$oca"
+compconfig[correct_original]="$oco"
+compconfig[correct_prompt]="$ocp"
+compconfig[correct_insert]="$oci"
diff --git a/Completion/Core/compinit b/Completion/Core/compinit
index 72d5fde28..77f918502 100644
--- a/Completion/Core/compinit
+++ b/Completion/Core/compinit
@@ -42,14 +42,32 @@
 
 # If we got the `-d'-flag, we will automatically dump the new state (at
 # the end).
+# `-f dir' is used to pass down the directory where this file was
+#   found.  This is necessary if functionargzero is not set.
 # If we were given an argument, this will be taken as the name of the
 # file in which to store the dump.
 
-if [[ "$1" = -d ]]; then
-  _i_autodump=1
-  shift
-else
-  _i_autodump=0
+_i_fdir=''
+_i_dumpfile=''
+_i_autodump=0
+while [[ $1 = -[df] ]]; do
+  if [[ "$1" = -d ]]; then
+    _i_autodump=1
+    shift
+    if [[ -n "$1" && "$1" != -[df] ]]; then
+      _i_dumpfile="$1"
+      shift
+    fi
+  elif [[ "$1" = -f ]]; then
+    # Used by compinstall to pass down directory where compinit was found
+    shift
+    _i_fdir="$1"
+    shift
+  fi
+done
+# Get the directory if we don't have it already and we can
+if [[ -z "$_i_fdir" && -o functionargzero && $0 = */* ]]; then
+  _i_fdir=${0:h}
 fi
 
 # The associative array containing the definitions for the commands.
@@ -63,9 +81,19 @@ _patcomps=()
 typeset -A compconfig
 
 # Standard initialisation for `compconfig'.
-
-(( $# )) && compconfig[dumpfile]="$1"
-[[ -z "$compconfig[dumpfile]" ]] && compconfig[dumpfile]="$0.dump"
+if [[ -n $_i_dumpfile ]]; then
+  # Explicitly supplied dumpfile.
+  compconfig[dumpfile]="$_i_dumpfile"
+elif [[ -o functionargzero ]]; then
+  # We can deduce it from the name of this script
+  compconfig[dumpfile]="$0.dump"
+elif [[ -n $_i_fdir ]]; then
+  # We were told what directory to use.
+  compconfig[dumpfile]="$_i_fdir/compinit.dump"
+else
+  # Now we're stuck, but we'd better do something.
+  compconfig[dumpfile]="$HOME/.compinit.dump"
+fi
 
 compconfig[correct_accept]=2n
 compconfig[correct_prompt]='correct to:'
@@ -180,9 +208,15 @@ compdef() {
     *)
       # For commands store the function name in the `_comps'
       # associative array, command names as keys.
-      for i; do
-        [[ -z "$new" || "${+_comps[$i]}" -eq 0 ]] && _comps[$i]="$func"
-      done
+      if [[ -z "$new" ]]; then
+	for i; do
+	  _comps[$i]="$func"
+	done
+      else
+        for i; do
+          [[ "${+_comps[$i]}" -eq 0 ]] && _comps[$i]="$func"
+        done
+      fi
       ;;
     esac
   else
@@ -265,8 +299,24 @@ compconf() {
 # Now we automatically make the definition files autoloaded.
 
 typeset -U _i_files
-_i_files=( ${^~fpath}/_(|*[^~])(N:t) )
-_i_initname=$0
+_i_files=( ${^~fpath:/.}/_(|*[^~])(N:t) )
+if [[ $#_i_files -lt 20 ]]; then
+  # Too few files:  we need some more directories
+  # Assume that we need to add the compinit directory to fpath.
+  if [[ -n $_i_fdir ]]; then
+    if [[ $_i_fdir = */Core ]]; then
+      # Add all the Completion subdirectories
+      fpath=(${_i_fdir:h}/*(/) $fpath)
+    elif [[ -d $_i_fdir/Core ]]; then
+      # Likewise
+      fpath=(${_i_fdir}/*(/) $fpath)
+    else
+      fpath=($_i_fdir $fpath)
+    fi
+    _i_files=( ${^~fpath:/.}/_(|*[^~])(N:t) )
+  fi
+fi
+
 _i_done=''
 
 # If we have a dump file, load it.
@@ -286,38 +336,45 @@ if [[ -z "$_i_done" ]]; then
       read -rA _i_line < $_i_file
       _i_tag=$_i_line[1]
       shift _i_line
-      if [[ $_i_tag = '#compdef' ]]; then
+      case $_i_tag in
+      (\#compdef)
 	if [[ $_i_line[1] = -[pk] ]]; then
 	  compdef ${_i_line[1]}a "${_i_file:t}" "${(@)_i_line[2,-1]}"
 	else
 	  compdef -na "${_i_file:t}" "${_i_line[@]}"
 	fi
-      elif [[ $_i_tag = '#autoload' ]]; then
+	;;
+      (\#autoload)
 	autoload ${_i_file:t}
-      fi
+	;;
+      esac
     done
   done
 
   bindkey |
     while read -rA _i_line; do
-      if [[ "$_i_line[2]" = complete-word ||
-	"$_i_line[2]" = delete-char-or-list ||
-	"$_i_line[2]" = expand-or-complete ||
-	"$_i_line[2]" = expand-or-complete-prefix ||
-	"$_i_line[2]" = list-choices ||
-	"$_i_line[2]" = menu-complete ||
-	"$_i_line[2]" = menu-expand-or-complete ||
-	"$_i_line[2]" = reverse-menu-complete ]]; then
+      case "$_i_line[2]" in
+      (complete-word) ;&
+      (delete-char-or-list) ;&
+      (expand-or-complete) ;&
+      (expand-or-complete-prefix) ;&
+      (list-choices) ;&
+      (menu-complete) ;&
+      (menu-expand-or-complete) ;&
+      (reverse-menu-complete)
 	zle -C _complete_$_i_line[2] $_i_line[2] _main_complete
 	bindkey "${_i_line[1][2,-2]}" _complete_$_i_line[2]
-      fi
+	;;
+      esac
     done
 
   unset _i_dir _i_line _i_file _i_tag
 
   # If autodumping was requested, do it now.
 
-  (( _i_autodump )) && builtin . ${_i_initname:h}/compdump
+  if [[ -n ${_i_fdir} && $_i_autodump = 1 ]]; then
+    builtin . ${_i_fdir}/compdump
+  fi
 fi
 
-unset _i_files _i_initname _i_done _i_autodump
+unset _i_files _i_initname _i_done _i_autodump _i_fdir _i_dumpfile
diff --git a/Completion/Core/compinstall b/Completion/Core/compinstall
index d96121cf2..d494ba302 100644
--- a/Completion/Core/compinstall
+++ b/Completion/Core/compinstall
@@ -1,49 +1,129 @@
-# This script is to be run by a user to setup the new function based
+# This script is to be run by a user to set up the new function based
 # completion system.  The functions themselves are assumed to be already
 # available in some directory; they should have been installed with the
 # the shell (except we haven't written that yet).
 #
-# Run it as a script under zsh and answer the questions.
-# You can run it as `zsh compinstall $FPATH' and it will be able to check
-# your function path for the completion functions.
+# Source this script (e.g. `. /path/compinstall') and answer the questions.
 #
-# Normally, this will alter ~/.zshrc (or wherever ZDOTDIR puts it),
-# but you can make that unwritable and it will leave the lines in a
-# temporary file instead.
-#
-# You can use this script to modify what compinstall previously
-# added to ~/.zshrc.
+# Normally, this will alter ~/.zshrc (or wherever ZDOTDIR puts it), but you
+# can make that unwritable and it will leave the lines in a temporary file
+# instead.  It doesn't matter if .zshrc didn't exist before.  If your
+# .zshrc usually exits before the end, then you should take the code added
+# by compinstall and put it (including the comment lines at the start and
+# end) at the point you want it to be executed.  If you run compinstall
+# again it will find and replace those lines, so you can use this script to
+# modify what compinstall previously added to ~/.zshrc.
 #
 # It is safe to abort with ^C any time you are being prompted for
 # information; your .zshrc will not be altered.
 #
 # To do:
-#  - Maybe this should be sourced, then it can check the user's current
-#    setup better.  But then there is a potentially horrendous option
-#    setting/resetting problem.  (Maybe we need another way of doing that.)
 #  - Should probably offer to set different options for _approximate than
 #    for _complete if both are used.
 #  - Could add code for setting other completers and options.
 #  - Could add keys for context-sensitive help.
-#  - Probably should allow a set of directories to be added to $fpath,
-#    like Core, Base, etc.
 
-# In case a startup script changed options
+# Save the options.  We will need to trap ^C to make sure they get
+# restored properly.
+typeset -A _ci_options
+_ci_options=($(setopt kshoptionprint;setopt))
+[[ -o kshoptionprint ]] || _ci_options[kshoptionprint]=off
+[[ -o monitor ]] && _ci_options[monitor]=on
+[[ -o zle ]] && _ci_options[zle]=on
+
 emulate zsh
 
-[[ -n $1 ]] && FPATH=$1
+TRAPINT() { 
+  unsetopt ${(k)_ci_options[(R)off]}
+  setopt ${(k)_ci_options[(R)on]}
 
-for f in $fpath; do
-  if [[ $f != . && -f $f/compinit && -f $f/compdump ]]; then
-    fdir=$f
-    break
+  unset _ci_options _ci_f _ci_fdir _ci_files _ci_dumpfile _ci_lines
+  unset _ci_type _ci_completer _ci_accept _ci_cprompt _ci_startline
+  unset _ci_endline _ci_ifile _ci_tmpf _ci_defaults _ci_compconf _ci_warn
+  unset _ci_dtype _ci_existing _ci_line
+
+  if (( $1 )); then
+    print Aborted.
+    unfunction TRAPINT
+    return 1
   fi
-done
+  return 0
+}
+
+
+# Look for the defaults.
+_ci_startline='# The following lines were added by compinstall'
+_ci_endline='# End of lines added by compinstall'
+
+_ci_ifile=${ZDOTDIR:-~}/.zshrc
+_ci_lines=''
+_ci_existing=''
+
+typeset -A _ci_defaults
+if [[ -f $_ci_ifile ]]; then
+  # This assumes the lines haven't been altered by the user too much
+  # after they were added.
+  _ci_compconf=0
+  sed -n "/^$_ci_startline/,/^$_ci_endline/p" $_ci_ifile |
+  while read -rA _ci_line; do
+    if (( $_ci_compconf )); then
+      # parse a compconf component as first argument
+      if [[ $_ci_line[-1] == \\ ]]; then
+	_ci_line=(${_ci_line[1,-2]})
+      else
+	_ci_compconf=0
+      fi
+      if [[ $_ci_line[1] = *=* ]]; then
+	_ci_f="${${_ci_line[*]}#*=}"
+	if [[ $_ci_f = \'*\' ]]; then
+	  # strip quotes
+	  _ci_f=${_ci_f[2,-2]//\'\\\'\'/\'}
+	fi
+	_ci_defaults[${_ci_line[1]%%\=*}]=$_ci_f
+      fi
+      _ci_existing="${_ci_existing}  $_ci_line
+"
+    elif [[ $_ci_line[1] = . && $_ci_line[2] = */compinit ]]; then
+      # parse the line sourcing compinit
+      [[ $_ci_line[3] = -f ]]  && _ci_fdir=$_ci_line[4]
+      [[ $_ci_line[-2] = -d ]] && _ci_dumpfile=$_ci_line[-1]
+    elif [[ $_ci_line[1] = compconf ]]; then
+      # parse a compconf component as second argument (should be completer)
+      [[ $_ci_line[2] = completer=* ]] &&
+        _ci_completer=${_ci_line[2]#completer=}
+      [[ $_ci_line[-1] == \\ ]] && _ci_compconf=1
+      _ci_existing="${_ci_existing}$_ci_line
+"
+    elif [[ $_ci_line[1] != \#* ]]; then
+      if [[ -z $_ci_warn ]]; then
+	_ci_warn=1
+	print "Warning:  existing lines in compinstall setup not understood:"
+      fi
+      print - $_ci_line
+      _ci_existing="${_ci_existing}$_ci_line
+"
+    fi
+  done
+fi
+
+
+# Find out where the completion functions are kept.
 
-if [[ -z $fdir ]]; then
+if [[ -z $_ci_fdir || ! -f $_ci_f/compinit || ! -f $_ci_f/compdump ]]; then
+  for _ci_f in $fpath; do
+    if [[ $_ci_f != . && -f $_ci_f/compinit && -f $_ci_f/compdump ]]; then
+      _ci_fdir=$_ci_f
+      break
+    fi
+  done
+fi
+
+if [[ -z $_ci_fdir || ! -d ${~_ci_fdir} ]]; then
   print "Trying to find where the completion functions are..."
-  if [[ $0 = */* && -f $0:h/compinit && -f $0:h/compdump ]]; then
-    fdir=$0:h
+  if [[ $0 = */* && -o functionargzero &&
+        -f $0:h/compinit && -f $0:h/compdump ]]; then
+    _ci_fdir=$0:h
+    print "Using my directory, $_ci_fdir"
   else
     # more guesses?
     print \
@@ -51,22 +131,26 @@ if [[ -z $fdir ]]; then
 installed.  If they are not installed, you will need to find them in the
 Completion/* directories of the zsh distribution and install them yourself,
 or insult your system manager for incompetence."
-    vared -c fdir
-    while [[ ! -d ${~fdir} || ! -f ${~fdir}/compinit || 
-      ! -f ${~fdir}/compdump ]]; do
+    vared -c _ci_fdir
+    while [[ ! -d ${~_ci_fdir} || ! -f ${~_ci_fdir}/compinit || 
+      ! -f ${~_ci_fdir}/compdump ]]; do
       print "I can't find them in that directory.  Try again or abort."
-      vared fdir
+      vared _ci_fdir
     done
   fi
-  eval "fpath=($fdir \$fpath)"
-  fdir=${fdir/#$HOME/\~}
-  lines="fpath=($fdir \$fpath)\n"
 else
-  print "Found completion functions in your fpath, will not alter it."
+  print "Keeping existing completion directiory $_ci_fdir"
 fi
 
-files=( ${^~fpath:/.}/_(|*[^~])(N:t) )
-if [[ $#files -lt 20 ]]; then
+# Check if this is in fpath already, else put it there (with ~'s expanded).
+_ci_f=${~_ci_fdir}
+[[ -z ${fpath[(r)$_ci_f]} ]] && fpath=($_ci_f $fpath)
+# Contract $HOME to ~ in the parameter to be used for writing.
+_ci_fdir=${_ci_fdir/#$HOME/\~}
+
+# Now check the fpath, ignoring the directory .
+_ci_files=( ${^~fpath:/.}/_(|*[^~])(N:t) )
+if [[ $#_ci_files -lt 20 ]]; then
   print "
 Hmmm, completion functions seem a bit thin on the ground.  There should
 be lots of files with names beginning with an underscore (_).  You should
@@ -75,12 +159,20 @@ look and see what's happened to these.
   read
 fi
 
-if [[ -w ${~fdir} && ( ! -f ${~fdir}/compinit.dump ||
-  -w ${~fdir}/compinit.dump ) ]]
+
+# Set up the dumpfile
+_ci_dtype=existing
+if [[ -z $_ci_dumpfile ]]; then
+  _ci_dumpfile="${_ci_fdir}/compinit.dump"
+  _ci_dtype=standard
+fi
+
+if [[ -w ${~_ci_dumpfile:h} && ( ! -f ${~_ci_dumpfile} ||
+  -w ${~_ci_dumpfile} ) ]]
 then
   print "
-Using standard dumpfile
-  ${~fdir}/compinit.dump
+Using $_ci_dtype dumpfile
+  ${_ci_dumpfile}
 to speed up initialisation.
 [Hit return to continue]"
   read
@@ -88,23 +180,30 @@ else
   print "
 I will force completion to dump its status, which will speed up the shell's
 start-up considerably.  However, I can't write the file I'd like to, namely
-$fdir/compinit.dump.  Please edit a replacement."
-  dumpfile='~/.compinit.dump'
-  vared dumpfile
-  while ! touch ${~dumpfile} >& /dev/null; do
+${_ci_dumpfile}.  Please edit a replacement."
+  _ci_dumpfile='~/.compinit.dump'
+  vared _ci_dumpfile
+  while ! touch ${~_ci_dumpfile} >& /dev/null; do
     print "Sorry, I can't write that either.  Try again."
-    vared dumpfile
+    vared _ci_dumpfile
   done
-  [[ -s $dumpfile ]] || rm -f $dumpfile
-  dumpfile=" $dumpfile"
+  [[ -s $_ci_dumpfile ]] || rm -f $_ci_dumpfile
 fi
 
-fdir=${fdir/#$HOME/\~}
-
-lines="${lines}. $fdir/compinit -d$dumpfile\n"
+_ci_lines="${_ci_lines}. $_ci_fdir/compinit -f $_ci_fdir -d"
+[[ $_ci_dtype != standard ]] && _ci_lines="${_ci_lines} $_ci_dumpfile"
+_ci_lines="${_ci_lines}
+"
 
 
 print "
+Would you like to set some more advanced options?  Otherwise, you
+can re-run compinstall later to set these. [n]"
+
+# The whole of the next part should be indented, but I can't be bothered.
+if read -q; then
+
+ print "
 In addition to completion, zsh can also perform correction of the
 current word, or approximate completion, i.e. completion where the part of
 the word typed so far can be corrected; or it can try correction, then
@@ -112,105 +211,155 @@ approximate completion if that fails.  Would you like:
   0:  Just ordinary completion
   C:  Correction
   A:  Approximate completion
-  B:  Both?
-Please type one of the keys above:"
-while read -k type; do
-  print
-  case $type in
-    0*) completer=_complete
-	break
-	;;
-    [cC]*) completer=_complete:_correct
-	   break
-	   ;;
-    [aA]*) completer=_complete:_approximate
-	   break;
-	   ;;
-    [bB]*) completer=_complete:_correct:_approximate
-	   break
-	   ;;
-    *) print Try again
-       ;;
-  esac
-done
-
-lines="${lines}compconf completer=$completer"
-
-
-if [[ $completer = *(correct|approx)* ]]; then
-  print "
-Correction and approximation will normally allow up to two errors,
-and you will be able to use a numeric prefix (e.g. <Esc>4) to allow
-more.  The standard prompt is \`correct to:'. Do you want to change
-any of this? [n]"
-  if read -q; then
-    print "Number of errors to accept normally (0 is OK):"
-    read accept
-    while [[ $accept != <-> ]]; do
-      read accept"?Please enter a number: "
-    done
-    print \
+  B:  Both"
+  if [[ -n $_ci_completer ]]; then
+    print "  Default: use the current completer:\n$_ci_completer"
+  else
+    print "Please type one of the keys above."
+  fi
+  while read -k _ci_type; do
+    print
+    case $_ci_type in
+      0*) _ci_completer=_complete
+	  break
+	  ;;
+      [cC]*) _ci_completer=_complete:_correct
+	     break
+	     ;;
+      [aA]*) _ci_completer=_complete:_approximate
+	     break;
+	     ;;
+      [bB]*) _ci_completer=_complete:_correct:_approximate
+	     break
+	     ;;
+      *) [[ -n $_ci_completer ]] && break
+	 print Try again
+	 ;;
+    esac
+  done
+
+  _ci_lines="${_ci_lines}compconf completer=$_ci_completer"
+
+
+  if [[ $_ci_completer = *(correct|approx)* ]]; then
+    _ci_accept=${_ci_defaults[correct_accept]}
+    _ci_cprompt=${_ci_defaults[correct_prompt]}
+    print "
+Correction and approximation will allow up to ${${_ci_accept:-2}%%[^0-9]*} \
+errors. "
+    case $_ci_accept in
+      *n*!*|*!*n) print "A numeric prefix, if not 1, will cause correction \
+not to be done."
+		  ;;
+      *n*) print "A numeric prefix gives the maximum number of errors which \
+will be accepted."
+           ;;
+      *) print "The numeric prefix will not be used."
+    esac
+print "The correction prompt is \`${_ci_cprompt:-correct to:}'.
+Do you want to change any of this? [n]"
+    if read -q; then
+      print "Number of errors to accept normally (0 is OK):"
+      _ci_accept=${_ci_accept%%[^0-9]*}
+      vared _ci_accept
+      while [[ $_ci_accept != <-> ]]; do
+	print "Please enter a number:"
+	vared _ci_accept
+      done
+      print \
 "How would you like the numeric prefix to be treated:
   0:  Not used by correction
-  U:  Used to given the number of errors
+  U:  The number gives the largest number of errors which will be
+      accepted when correcting
   I:  If present, and not 1, do not perform correction?
 Please type one of the keys above:"
-    while read -k type; do
-      print
-      case $type in
-	0*) break
-	    ;;
-	[uU]*) accept="${accept}n"
-	       break
-	       ;;
-	[Ii]*) accept="${accept}!n"
-	       break
-	       ;;
-	*) print Try again
-	   ;;
-      esac
-    done
-    lines="$lines \\\\
-  correct_accept='$accept'"
-    print "
+      while read -k _ci_type; do
+	print
+	case $_ci_type in
+	  0*) break
+	      ;;
+	  [uU]*) _ci_accept="${_ci_accept}n"
+		 break
+		 ;;
+	  [Ii]*) _ci_accept="${_ci_accept}!n"
+		 break
+		 ;;
+	  *) print Try again
+	     ;;
+	esac
+      done
+      print "
 Instead of the prompt \`correct to:', you can have no prompt, or a
 prompt of your choosing which can display the number of errors found by
 containing the string \`%e'.  Do you wish to change the correction
 prompt? [n]"
-    if read -q; then
-      cprompt=''
-      print "Edit a new prompt (may be empty):"
-      vared cprompt
-      lines="$lines \\\\
-  correct_prompt='${cprompt//\'/\'\\\'\'}'"
+      if read -q; then
+	print "Edit a new prompt (may be empty):"
+	vared _ci_cprompt
+	[[ -z $_ci_cprompt ]] && _ci_cprompt=':empty:'
+      fi
+    fi
+    if [[ -n $_ci_accept ]]; then
+      _ci_lines="$_ci_lines \\
+  correct_accept='$_ci_accept'"
+      unset '_ci_defaults[correct_accept]'
+    fi
+    if [[ -n $_ci_cprompt ]]; then
+      _ci_cprompt=${_ci_cprompt##:empty:}
+      _ci_lines="$_ci_lines \\
+  correct_prompt='${_ci_cprompt//\'/\'\\\'\'}'"
+      unset '_ci_defaults[correct_prompt]'
     fi
   fi
-fi
 
-lines="$lines\n"
+  _ci_warn=''
+  for _ci_f in ${(k)_ci_defaults}; do
+    if [[ -z $_ci_warn ]]; then
+      print "
+(Keeping other existing configuration settings...)"
+      _ci_warn=1
+    fi
+    _ci_lines="$_ci_lines \\
+  ${_ci_f}='${_ci_defaults[$_ci_f]//\'/\'\\\'\'}'"
+  done
 
+  _ci_lines="$_ci_lines
+"
 
-startline='# The following lines were added by compinstall'
-endline='# End of lines added by compinstall'
+else
 
-ifile=${ZDOTDIR:-~}/.zshrc
-[[ -f $ifile ]] || touch $ifile
-tmpf=${TMPPPREFIX:-/tmp/zsh}compinstall$$
+  if [[ -n $_ci_existing ]]; then
+    print -nr "
+I will retain the following lines from the existing completion setup:
+$_ci_existing"
+    _ci_lines="$_ci_lines${_ci_existing}"
+  fi
+
+fi				# End of advanced options
 
-if [[ ! -w $ifile ]]; then
-  print "\nI can't write to $ifile.  I will leave the lines to add in
-\`$tmpf' and you must add them by hand."
-  print "\n$startline\n$lines\n$endline" >$tmpf
-  return 0
-fi
 
-if grep $endline $ifile >& /dev/null; then
-  print -- "$startline\n$lines$endline" >$tmpf
-  sed -e "/^$endline/r $tmpf
-/^$startline/,/^$endline/d" $ifile >${tmpf}2 && mv ${tmpf}2 $ifile &&
-  print "\nSuccesfully modified old compinstall lines in $ifile."
-  rm -f $tmpf ${tmpf}2
+[[ -f $_ci_ifile ]] || touch $_ci_ifile
+_ci_tmpf=${TMPPPREFIX:-/tmp/zsh}compinstall$$
+
+if [[ ! -w $_ci_ifile ]]; then
+  print "\nI can't write to $_ci_ifile.  I will leave the lines to add in
+\`$_ci_tmpf' and you must add them by hand."
+  print -r - "$_ci_startline
+$_ci_lines$_ci_endline" >$_ci_tmpf
+elif grep $_ci_endline $_ci_ifile >& /dev/null; then
+  print -r - "$_ci_startline
+$_ci_lines$_ci_endline" >$_ci_tmpf
+  sed -e "/^$_ci_endline/r $_ci_tmpf
+/^$_ci_startline/,/^$_ci_endline/d" $_ci_ifile >${_ci_tmpf}2 && 
+  mv ${_ci_tmpf}2 $_ci_ifile &&
+  print "\nSuccesfully modified old compinstall lines in $_ci_ifile."
+  rm -f $_ci_tmpf ${_ci_tmpf}2
 else
-  print "\n$startline\n$lines\n$endline" >>$ifile &&
-  print "\nSuccessfully appended lines to $ifile."
+  print -r - "$_ci_startline
+$_ci_lines$_ci_endline" >>$_ci_ifile &&
+  print "\nSuccessfully appended lines to $_ci_ifile."
 fi
+
+TRAPINT 0
+
+return 0