From 7a0415cfd70a02b2280d27556c6c54cef1c86e1a Mon Sep 17 00:00:00 2001 From: Tanaka Akira Date: Thu, 15 Apr 1999 18:18:42 +0000 Subject: zsh-3.1.5-pws-11 --- Completion/Base/_brace_parameter | 5 + Completion/Base/_command_names | 6 +- Completion/Base/_condition | 10 +- Completion/Base/_default | 3 +- Completion/Base/_equal | 3 + Completion/Base/_match_pattern | 6 +- Completion/Base/_match_test | 8 +- Completion/Base/_parameter | 3 + Completion/Base/_precommand | 5 +- Completion/Base/_subscript | 5 +- Completion/Base/_tilde | 10 + Completion/Base/_vars | 2 +- Completion/Builtins/_aliases | 2 +- Completion/Builtins/_arrays | 2 +- Completion/Builtins/_autoload | 2 +- Completion/Builtins/_bg_jobs | 2 +- Completion/Builtins/_bindkey | 6 +- Completion/Builtins/_builtin | 8 +- Completion/Builtins/_cd | 63 ++- Completion/Builtins/_command | 6 +- Completion/Builtins/_disable | 10 +- Completion/Builtins/_echotc | 2 +- Completion/Builtins/_enable | 10 +- Completion/Builtins/_fc | 8 +- Completion/Builtins/_functions | 2 +- Completion/Builtins/_hash | 6 +- Completion/Builtins/_jobs | 2 +- Completion/Builtins/_kill | 6 +- Completion/Builtins/_limits | 2 +- Completion/Builtins/_sched | 2 +- Completion/Builtins/_set | 10 +- Completion/Builtins/_setopt | 7 +- Completion/Builtins/_source | 4 +- Completion/Builtins/_trap | 6 +- Completion/Builtins/_unhash | 10 +- Completion/Builtins/_unsetopt | 7 +- Completion/Builtins/_vars_eq | 2 +- Completion/Builtins/_wait | 4 +- Completion/Builtins/_which | 2 +- Completion/Builtins/_zftp | 14 +- Completion/Builtins/_zle | 6 +- Completion/Builtins/_zmodload | 12 +- Completion/Commands/_correct_filename | 6 +- Completion/Commands/_most_recent_file | 24 +- Completion/Core/_comp_parts | 25 +- Completion/Core/_compalso | 6 +- Completion/Core/_files | 7 +- Completion/Core/_main_complete | 219 ++++++-- Completion/Core/_multi_parts | 201 ++++++++ Completion/Core/_normal | 30 +- Completion/Core/_path_files | 110 ++-- Completion/README | 31 +- Completion/User/_a2ps | 8 +- Completion/User/_configure | 29 +- Completion/User/_dd | 4 +- Completion/User/_find | 24 +- Completion/User/_hosts | 2 +- Completion/User/_make | 2 +- Completion/User/_man | 6 +- Completion/User/_mh | 36 +- Completion/User/_rcs | 8 +- Completion/User/_rlogin | 10 +- Completion/User/_stty | 6 +- Completion/User/_tar | 68 ++- Completion/User/_x_options | 2 +- Config/version.mk | 4 +- Doc/Zsh/builtins.yo | 2 +- Doc/Zsh/compctl.yo | 28 +- Doc/Zsh/compwid.yo | 256 +++++++--- Doc/Zsh/expn.yo | 2 +- Doc/Zsh/params.yo | 5 + Doc/Zsh/zle.yo | 4 + INSTALL | 9 +- Src/Makefile.in | 15 +- Src/Zle/comp.h | 39 +- Src/Zle/comp1.c | 57 ++- Src/Zle/comp1.export | 15 + Src/Zle/compctl.c | 260 +++++++--- Src/Zle/zle_hist.c | 6 +- Src/Zle/zle_main.c | 4 + Src/Zle/zle_misc.c | 6 +- Src/Zle/zle_params.c | 21 +- Src/Zle/zle_refresh.c | 8 +- Src/Zle/zle_tricky.c | 912 +++++++++++++++++++++------------- Src/Zle/zle_word.c | 2 +- Src/builtin.c | 12 +- Src/compat.c | 10 +- Src/glob.c | 4 +- Src/mem.c | 18 +- Src/params.c | 149 ++++-- Src/subst.c | 4 +- Src/system.h | 2 +- Src/utils.c | 6 +- Src/zsh.export | 6 +- acconfig.h | 3 + config.sub | 117 +++-- configure.in | 34 +- patchlist.txt | 101 ++++ 98 files changed, 2354 insertions(+), 922 deletions(-) create mode 100644 Completion/Base/_brace_parameter create mode 100644 Completion/Base/_equal create mode 100644 Completion/Base/_parameter create mode 100644 Completion/Base/_tilde create mode 100644 Completion/Core/_multi_parts diff --git a/Completion/Base/_brace_parameter b/Completion/Base/_brace_parameter new file mode 100644 index 000000000..092376e78 --- /dev/null +++ b/Completion/Base/_brace_parameter @@ -0,0 +1,5 @@ +#defcomp -brace-parameter- + +# Simple but without spiffy suffix handling: compgen -v -S '} ' + +compadd -S '} ' -r '-:?#%+=[/' - "${(@)${${${(f)$(typeset)}%%\=*}##* }:gs/'//}" diff --git a/Completion/Base/_command_names b/Completion/Base/_command_names index d3b8a109a..eab314dfa 100644 --- a/Completion/Base/_command_names +++ b/Completion/Base/_command_names @@ -1,3 +1,7 @@ #defcomp -command- -complist -c +local nm=$compstate[nmatches] + +compgen -c + +[[ nm -eq compstate[nmatches] ]] && _path_files -/g "*(*)" diff --git a/Completion/Base/_condition b/Completion/Base/_condition index 3e45e1b8f..fb6b98b1b 100644 --- a/Completion/Base/_condition +++ b/Completion/Base/_condition @@ -1,10 +1,12 @@ #defcomp -condition- -if [[ -current -1 -o ]]; then - complist -o -M 'L:|[nN][oO]= M:_= M:{A-Z}={a-z}' -elif [[ -current -1 -nt || -current -1 -ot || -current -1 -ef ]]; then +local prev="$words[CURRENT-1]" + +if [[ "$prev" = -o ]]; then + compgen -o -M 'L:|[nN][oO]= M:_= M:{A-Z}={a-z}' +elif [[ "$prev" = -([no]t|ef) ]]; then _files else _files - complist -v + compgen -v fi diff --git a/Completion/Base/_default b/Completion/Base/_default index 8bcf14f6a..569bd6382 100644 --- a/Completion/Base/_default +++ b/Completion/Base/_default @@ -6,7 +6,8 @@ # immediatly. If you want to use new style completion anyway, remove the # `|| return'. Also, you may want to use new style completion if the # `compctl' didn't produce any matches. In that case remove the `|| return' -# and at the line `[[ -nmatches 0 ]] || return' after `compcall'. +# and insert the line `[[ compstate[nmatches] -eq 0 ]] || return' after +# `compcall'. compcall || return diff --git a/Completion/Base/_equal b/Completion/Base/_equal new file mode 100644 index 000000000..f407014fe --- /dev/null +++ b/Completion/Base/_equal @@ -0,0 +1,3 @@ +#defcomp -equal- + +compgen -am diff --git a/Completion/Base/_match_pattern b/Completion/Base/_match_pattern index c5debc0b9..3df115d5b 100644 --- a/Completion/Base/_match_pattern +++ b/Completion/Base/_match_pattern @@ -10,7 +10,7 @@ # the match specs currently in use do. # In the calling function this pattern may be changed again or used only # in parts. The second parameter whose name is given as the third argument -# allows to give pattern flags liek `(#l)' that are to be used whenever +# allows to give pattern flags like `(#l)' that are to be used whenever # matching is done. # # As an example, if you have global match specifications like: @@ -20,12 +20,12 @@ # This function would look like: # # eval "${3}='(#l)'" -# [[ MATCHER -eq 2 ]] && eval "$1='${(P)2:gs/./*./:gs/-/*-/}'" +# [[ compstate[matcher] -eq 2 ]] && eval "$2='${(P)2:gs/./*./:gs/-/*-/}'" # # The first line makes sure that matching is done case-insensitive as # specified by `m:{a-z}={A-Z}'. The second line replaces dots and hyphens # in the given string by patterns matching any characters before them, # like the `r:|[.-]=* r:|=*'. To make this work, the function `_match_test' -# would have to be changed to `(( MATCHERS <= 2 ))' +# would have to be changed to `(( compstate[matcher] <= 2 ))' # # The default implementation of this function is empty. diff --git a/Completion/Base/_match_test b/Completion/Base/_match_test index e8b6e6424..7db521e81 100644 --- a/Completion/Base/_match_test +++ b/Completion/Base/_match_test @@ -1,9 +1,9 @@ #autoload # This function is called at the beginning of functions that do matching in -# shell code. It should test the value of the `MATCHER' special parameter -# and return non-zero if the calling function should try to generate matches -# for the global match specification in use. +# shell code. It should test the value of `compstate[matcher]' and return +# non-zero if the calling function should try to generate matches for the +# global match specification in use. # # This function gets one argument, the name of the function calling it. # @@ -12,4 +12,4 @@ # match specifications and modify the function `_match_pattern' to build the # pattern to use in the calling function. -(( MATCHER == 1 )) +(( compstate[matcher] <= 1 )) diff --git a/Completion/Base/_parameter b/Completion/Base/_parameter new file mode 100644 index 000000000..2bd66ec93 --- /dev/null +++ b/Completion/Base/_parameter @@ -0,0 +1,3 @@ +#defcomp -parameter- + +compgen -v diff --git a/Completion/Base/_precommand b/Completion/Base/_precommand index 2cf661147..c13cd7465 100644 --- a/Completion/Base/_precommand +++ b/Completion/Base/_precommand @@ -1,5 +1,6 @@ #defcomp - nohup nice eval time rusage noglob nocorrect exec -[[ -position 1 -1 ]] +shift words +(( CURRENT-- )) -_normal "$@" +_normal diff --git a/Completion/Base/_subscript b/Completion/Base/_subscript index 2b827a117..d50fd8335 100644 --- a/Completion/Base/_subscript +++ b/Completion/Base/_subscript @@ -1,4 +1,5 @@ #defcomp -subscript- -_compalso -math- "$@" -[[ ${(Pt)${COMMAND}} = assoc* ]] && complist -k "( ${(kP)${COMMAND}} )" +_compalso -math- +[[ ${(Pt)${compstate[parameter]}} = assoc* ]] && + compgen -k "( ${(kP)${compstate[parameter]}} )" diff --git a/Completion/Base/_tilde b/Completion/Base/_tilde new file mode 100644 index 000000000..aef575e19 --- /dev/null +++ b/Completion/Base/_tilde @@ -0,0 +1,10 @@ +#defcomp -tilde- + +# We use all named directories and user names here. If this is too slow +# for you or if there are too many of them, you may want to use +# `compgen -k friends -qS/' or something like that. To get all user names +# if there are no matches in the `friends' array, add +# `(( compstate[nmatches] )) || compgen -nu -qS/' +# below that. + +compgen -nu -qS/ diff --git a/Completion/Base/_vars b/Completion/Base/_vars index 7153b6f38..92de51e1f 100644 --- a/Completion/Base/_vars +++ b/Completion/Base/_vars @@ -1,3 +1,3 @@ #defcomp -math- getopts read unset vared -complist -v +compgen -v diff --git a/Completion/Builtins/_aliases b/Completion/Builtins/_aliases index 1038a726e..2ccf18439 100644 --- a/Completion/Builtins/_aliases +++ b/Completion/Builtins/_aliases @@ -1,3 +1,3 @@ #defcomp unalias -complist -a +compgen -a diff --git a/Completion/Builtins/_arrays b/Completion/Builtins/_arrays index cbeac7118..94401f28a 100644 --- a/Completion/Builtins/_arrays +++ b/Completion/Builtins/_arrays @@ -1,3 +1,3 @@ #defcomp shift -complist -A +compgen -A diff --git a/Completion/Builtins/_autoload b/Completion/Builtins/_autoload index 4f506baeb..d1462e09a 100644 --- a/Completion/Builtins/_autoload +++ b/Completion/Builtins/_autoload @@ -1,3 +1,3 @@ #defcomp autoload -complist -s '${^fpath}/*(N:t)' +compgen -s '${^fpath}/*(N:t)' diff --git a/Completion/Builtins/_bg_jobs b/Completion/Builtins/_bg_jobs index 511bb8308..4abee070c 100644 --- a/Completion/Builtins/_bg_jobs +++ b/Completion/Builtins/_bg_jobs @@ -1,3 +1,3 @@ #defcomp bg -complist -z -P '%' +compgen -z -P '%' diff --git a/Completion/Builtins/_bindkey b/Completion/Builtins/_bindkey index 8eddeb2a8..d3d019492 100644 --- a/Completion/Builtins/_bindkey +++ b/Completion/Builtins/_bindkey @@ -1,7 +1,7 @@ #defcomp bindkey -if [[ -mword 1 -*[DAN]* || -mcurrent -1 -*M ]]; then - complist -s '$(bindkey -l)' +if [[ "$words[2]" = -*[DAN]* || "$words[CURRENT-1] = -*M ]]; then + compgen -s '$(bindkey -l)' else - complist -b + compgen -b fi diff --git a/Completion/Builtins/_builtin b/Completion/Builtins/_builtin index a967932ee..bee67fe8f 100644 --- a/Completion/Builtins/_builtin +++ b/Completion/Builtins/_builtin @@ -1,7 +1,9 @@ #defcomp builtin -if [[ -position 2 -1 ]]; then - _normal "$@" +if (( $CURRENT > 2 )); then + shift words + (( CURRENT -- )) + _normal else - complist -eB + compgen -eB fi diff --git a/Completion/Builtins/_cd b/Completion/Builtins/_cd index f3ce67ec7..65ce7f293 100644 --- a/Completion/Builtins/_cd +++ b/Completion/Builtins/_cd @@ -1,3 +1,62 @@ -#defcomp cd +#defcomp cd pushd -_files -W cdpath -g '*(-/)' +# Handling of cd. +# - Normally just completes directories. Uses cdpath if that's set +# and the string doesn't begin with ~, /, ./ or ../. +# - In the second argument to cd for the form `cd old new', completes +# possible `new' strings by examining `old' and $PWD. +# - After pushd - or pushd +, completes numbers, but the listing +# gives you the list of directories to complete. This turns on +# menu-completion and lists the possibilities automatically, otherwise +# it's not a lot of use. If you don't type the + or - it will +# complete directories as normal. + +local pushdminus +[[ -o pushdminus ]] && pushdminus=1 + +emulate -LR zsh +setopt extendedglob + +if [[ -position 3 ]]; then + # cd old new: look for old in $PWD and see what can replace it + local rep + # Get possible completions using word in position 2 + rep=(${~PWD/$words[2]/*}~$PWD(-/N)) + # Now remove all the common parts of $PWD and the completions from this + rep=(${${rep#${PWD%%$words[2]*}}%${PWD#*$words[2]}}) + (( $#rep )) && compadd $rep +elif [[ $words[1] = pu* && $PREFIX = [-+]* ]]; then + # pushd: just complete the numbers, but show the full directory list with + # numbers. + # For - we do the same thing, but reverse the numbering (other + # way round if pushdminus is set). + # The test is for pu* because I have an alias pu since I'm too + # lazy to type pushd. + IPREFIX=$PREFIX[1] + PREFIX=$PREFIX[2,-1] + local list lines + # get the list of directories with their canonical number + lines="$(dirs -v)" + # turn the lines into an array, removing the current directory + list=(${${(f)lines}##0*}) + if [[ ( $IPREFIX = - && -z $pushdminus ) || + ( $IPREFIX = + && -n $pushdminus ) ]]; then + # reverse the numbering: it counts the last one as -0, which + # is a little strange. + integer tot i + for (( i = 1, tot = $#list-1; tot >= 0; i++, tot-- )); do + list[$i]="$tot${list[$i]##[0-9]#}" + done + fi + # make sure -y treats this as a single string + lines="${(F)list}" + # get the array of numbers only + list=(${list%%[ ]*}) + compgen -y '$lines' -Q -k list + [[ -z $compstate[list] ]] && compstate[list]=list + [[ -n $compstate[insert] ]] && compstat[insert]=menu +elif [[ $PREFIX != (\~|/|./|../)* && $#cdpath -ne 0 ]]; then + _path_files -W cdpath -/ +else + _path_files -/ +fi diff --git a/Completion/Builtins/_command b/Completion/Builtins/_command index b2812de25..47eb0d667 100644 --- a/Completion/Builtins/_command +++ b/Completion/Builtins/_command @@ -1,7 +1,7 @@ #defcomp command -if [[ -position 2 -1 ]]; then - _normal "$@" +if [[ -position 3 -1 ]]; then + _normal else - complist -em + compgen -em fi diff --git a/Completion/Builtins/_disable b/Completion/Builtins/_disable index 063b65a7d..e3edafe2b 100644 --- a/Completion/Builtins/_disable +++ b/Completion/Builtins/_disable @@ -1,6 +1,8 @@ #defcomp disable -[[ -mcurrent -1 -*a* ]] && complist -ea -[[ -mcurrent -1 -*f* ]] && complist -eF -[[ -mcurrent -1 -*r* ]] && complist -ew -[[ ! -mcurrent -1 -* ]] && complist -eB +local prev="$words[CURRENT-1]" + +[[ "$prev" = -*a* ]] && compgen -ea +[[ "$prev" = -*f* ]] && compgen -eF +[[ "$prev" = -*r* ]] && compgen -ew +[[ "$prev" != -* ]] && compgen -eB diff --git a/Completion/Builtins/_echotc b/Completion/Builtins/_echotc index 85ebb97ce..135cabada 100644 --- a/Completion/Builtins/_echotc +++ b/Completion/Builtins/_echotc @@ -1,3 +1,3 @@ #defcomp echotc -complist -k '(al dc dl do le up al bl cd ce cl cr dc dl do ho is le ma nd nl se so up)' +compgen -k '(al dc dl do le up al bl cd ce cl cr dc dl do ho is le ma nd nl se so up)' diff --git a/Completion/Builtins/_enable b/Completion/Builtins/_enable index 22ff53ee7..111d1ae26 100644 --- a/Completion/Builtins/_enable +++ b/Completion/Builtins/_enable @@ -1,6 +1,8 @@ #defcomp enable -[[ -mcurrent -1 -*a* ]] && complist -da -[[ -mcurrent -1 -*f* ]] && complist -dF -[[ -mcurrent -1 -*r* ]] && complist -dw -[[ ! -mcurrent -1 -* ]] && complist -dB +local prev="$words[CURRENT-1]" + +[[ "$prev" = -*a* ]] && compgen -da +[[ "$prev" = -*f* ]] && compgen -dF +[[ "$prev" = -*r* ]] && compgen -dw +[[ "$prev" != -* ]] && compgen -dB diff --git a/Completion/Builtins/_fc b/Completion/Builtins/_fc index f0d2c03fd..f8cf4dde8 100644 --- a/Completion/Builtins/_fc +++ b/Completion/Builtins/_fc @@ -1,7 +1,9 @@ #defcomp fc -if [[ -mcurrent -1 -*e ]]; then - complist -c -elif [[ -mcurrent -1 -[ARWI]## ]]; then +local prev="$words[CURRENT-1]" + +if [[ "$prev" = -*e ]]; then + compgen -c +elif [[ "$prev" = -[ARWI]## ]]; then _files fi diff --git a/Completion/Builtins/_functions b/Completion/Builtins/_functions index 8a352ea08..7e3174af5 100644 --- a/Completion/Builtins/_functions +++ b/Completion/Builtins/_functions @@ -1,3 +1,3 @@ #defcomp unfunction -complist -F +compgen -F diff --git a/Completion/Builtins/_hash b/Completion/Builtins/_hash index 171c5e2e8..8c100b801 100644 --- a/Completion/Builtins/_hash +++ b/Completion/Builtins/_hash @@ -1,13 +1,13 @@ #defcomp hash -if [[ -mword 1 -*d* ]]; then +if [[ "$words[2]" = -*d* ]]; then if [[ -string 1 '=' ]]; then _path_files -g '*(-/)' else - complist -n -q -S '=' + compgen -n -q -S '=' fi elif [[ -string 1 '=' ]]; then _files -/g '*(*)' else - complist -m -q -S '=' + compgen -m -q -S '=' fi diff --git a/Completion/Builtins/_jobs b/Completion/Builtins/_jobs index 018883c61..8f6991de0 100644 --- a/Completion/Builtins/_jobs +++ b/Completion/Builtins/_jobs @@ -1,3 +1,3 @@ #defcomp fg jobs -complist -j -P '%' +compgen -j -P '%' diff --git a/Completion/Builtins/_kill b/Completion/Builtins/_kill index 50796d36f..c1afa78cb 100644 --- a/Completion/Builtins/_kill +++ b/Completion/Builtins/_kill @@ -3,9 +3,9 @@ local list if [[ -iprefix '-' ]]; then - complist -k "($signals[1,-3])" + compgen -k "($signals[1,-3])" else - complist -P '%' -j + compgen -P '%' -j list=("$(ps 2>/dev/null)") - complist -y '$list' -s '`ps 2>/dev/null | tail +2 | cut -c1-5`' + compgen -y '$list' -s '`ps 2>/dev/null | tail +2 | cut -c1-5`' fi diff --git a/Completion/Builtins/_limits b/Completion/Builtins/_limits index 35ccbe07e..8b0b41c71 100644 --- a/Completion/Builtins/_limits +++ b/Completion/Builtins/_limits @@ -1,3 +1,3 @@ #defcomp limit unlimit -complist -k "(${(j: :)${(f)$(limit)}%% *})" +compgen -k "(${(j: :)${(f)$(limit)}%% *})" diff --git a/Completion/Builtins/_sched b/Completion/Builtins/_sched index 1e8ae3445..62cdbb070 100644 --- a/Completion/Builtins/_sched +++ b/Completion/Builtins/_sched @@ -1,3 +1,3 @@ #defcomp sched -[[ -position 2 -1 ]] && _normal "$@" +[[ -position 3 -1 ]] && _normal diff --git a/Completion/Builtins/_set b/Completion/Builtins/_set index 5597025bc..959dac75d 100644 --- a/Completion/Builtins/_set +++ b/Completion/Builtins/_set @@ -1,7 +1,9 @@ #defcomp set -if [[ -mcurrent -1 [-+]o ]]; then - complist -o -elif [[ -current -1 -A ]]; then - complist -A +local prev="$words[CURRENT-1]" + +if [[ "$prev" = [-+]o ]]; then + compgen -o +elif [[ "$prev" = -A ]]; then + compgen -A fi diff --git a/Completion/Builtins/_setopt b/Completion/Builtins/_setopt index 4abb3ccee..98800152f 100644 --- a/Completion/Builtins/_setopt +++ b/Completion/Builtins/_setopt @@ -1,7 +1,8 @@ #defcomp setopt -local nm=$NMATCHES +local nm=$compstate[nmatches] -complist -M 'L:|[nN][oO]= M:_= M:{A-Z}={a-z}' \ +compgen -M 'L:|[nN][oO]= M:_= M:{A-Z}={a-z}' \ -s '$({ unsetopt kshoptionprint; unsetopt } 2>/dev/null)' -[[ -nmatches nm ]] && complist -M 'L:|[nN][oO]= M:_= M:{A-Z}={a-z}' -o +[[ compstate[nmatches] -eq nm ]] && + compgen -M 'L:|[nN][oO]= M:_= M:{A-Z}={a-z}' -o diff --git a/Completion/Builtins/_source b/Completion/Builtins/_source index aae2c7320..1bbbf15a4 100644 --- a/Completion/Builtins/_source +++ b/Completion/Builtins/_source @@ -1,7 +1,7 @@ #defcomp source -if [[ -position 2 -1 ]]; then - _normal "$@" +if [[ -position 3 -1 ]]; then + _normal else _files fi diff --git a/Completion/Builtins/_trap b/Completion/Builtins/_trap index 59e81c589..36ab1f1a8 100644 --- a/Completion/Builtins/_trap +++ b/Completion/Builtins/_trap @@ -1,7 +1,7 @@ #defcomp trap -if [[ -position 1 ]]; then - complist -c +if [[ CURRENT -eq 2 ]]; then + compgen -c else - complist -k signals + compgen -k signals fi diff --git a/Completion/Builtins/_unhash b/Completion/Builtins/_unhash index fe40c25a2..63d61c991 100644 --- a/Completion/Builtins/_unhash +++ b/Completion/Builtins/_unhash @@ -1,6 +1,8 @@ #defcomp unhash -[[ -mword 1 -*d* ]] && complist -n -[[ -mword 1 -*a* ]] && complist -a -[[ -mword 1 -*f* ]] && complist -F -[[ ! -mword 1 -* ]] && complist -m +local fl="$words[2]" + +[[ "$fl" = -*d* ]] && compgen -n +[[ "$fl" = -*a* ]] && compgen -a +[[ "$fl" = -*f* ]] && compgen -F +[[ "$fl" != -* ]] && compgen -m diff --git a/Completion/Builtins/_unsetopt b/Completion/Builtins/_unsetopt index 90d642b51..a5c85b1ef 100644 --- a/Completion/Builtins/_unsetopt +++ b/Completion/Builtins/_unsetopt @@ -1,7 +1,8 @@ #defcomp unsetopt -local nm=$NMATCHES +local nm=$compstate[nmatches] -complist -M 'L:|[nN][oO]= M:_= M:{A-Z}={a-z}' \ +compgen -M 'L:|[nN][oO]= M:_= M:{A-Z}={a-z}' \ -s '$({ unsetopt kshoptionprint; setopt } 2>/dev/null)' -[[ -nmatches nm ]] && complist -M 'L:|[nN][oO]= M:_= M:{A-Z}={a-z}' -o +[[ compstate[nmatches] -eq nm ]] && + compgen -M 'L:|[nN][oO]= M:_= M:{A-Z}={a-z}' -o diff --git a/Completion/Builtins/_vars_eq b/Completion/Builtins/_vars_eq index fcbb0148c..9488cb7f9 100644 --- a/Completion/Builtins/_vars_eq +++ b/Completion/Builtins/_vars_eq @@ -1,3 +1,3 @@ #defcomp declare export integer local readonly typeset -complist -v -q -S '=' +compgen -v -q -S '=' diff --git a/Completion/Builtins/_wait b/Completion/Builtins/_wait index 29a7f6002..6e3a4c3c9 100644 --- a/Completion/Builtins/_wait +++ b/Completion/Builtins/_wait @@ -2,6 +2,6 @@ local list -complist -P '%' -j +compgen -P '%' -j list=("$(ps 2>/dev/null)") -complist -y '$list' -s '`ps 2>/dev/null | tail +2 | cut -c1-5`' +compgen -y '$list' -s '`ps 2>/dev/null | tail +2 | cut -c1-5`' diff --git a/Completion/Builtins/_which b/Completion/Builtins/_which index 324256e3d..9248f9c9f 100644 --- a/Completion/Builtins/_which +++ b/Completion/Builtins/_which @@ -1,3 +1,3 @@ #defcomp which whence where type -complist -caF +compgen -caF diff --git a/Completion/Builtins/_zftp b/Completion/Builtins/_zftp index 9be9c94db..e93021acf 100644 --- a/Completion/Builtins/_zftp +++ b/Completion/Builtins/_zftp @@ -9,28 +9,28 @@ _compskip=1 local subcom -if [[ $COMMAND = zftp ]]; then +if [[ $words[1] = zftp ]]; then if [[ $CURRENT -eq 1 ]]; then - compadd -m open params user login type ascii binary mode put \ + compadd open params user login type ascii binary mode put \ putat get getat append appendat ls dir local remote mkdir rmdir return fi - subcom=$1 + subcom=$words[2] else - subcom=$COMMAND + subcom=$words[1] fi case $subcom in *(cd|ls|dir)) # complete remote directories; we could be smarter about hiding prefixes zfcd_match $PREFIX $SUFFIX - (( $#reply )) && compadd -m -S/ -q $reply + (( $#reply )) && compadd -S/ -q - $reply ;; *(get(|at)|gcp|delete|remote)) # complete remote files zfget_match $PREFIX $SUFFIX - (( $#reply )) && compadd -F fignore -m $reply + (( $#reply )) && compadd -F fignore - $reply ;; *(put(|at)|pcp)) @@ -40,7 +40,7 @@ case $subcom in *(open|anon|params)) # complete hosts: should do cleverer stuff with user names - complist -k hosts + compgen -k hosts ;; *) diff --git a/Completion/Builtins/_zle b/Completion/Builtins/_zle index bb1102e74..0a9ad0a9e 100644 --- a/Completion/Builtins/_zle +++ b/Completion/Builtins/_zle @@ -1,7 +1,7 @@ #defcomp zle -if [[ -word 1 -N && -position 3 ]]; then - complist -F +if [[ "$words[2]" = -N && CURRENT -eq 3 ]]; then + compgen -F else - complist -b + compgen -b fi diff --git a/Completion/Builtins/_zmodload b/Completion/Builtins/_zmodload index 112acb57c..4259adf06 100644 --- a/Completion/Builtins/_zmodload +++ b/Completion/Builtins/_zmodload @@ -1,9 +1,11 @@ #defcomp zmodload -if [[ -mword 1 -*(a*u|u*a)* || -mword 1 -*a* && -position 3 -1 ]]; then - complist -B -elif [[ -mword 1 -*u* ]]; then - complist -s '$(zmodload)' +local fl="$words[2]" + +if [[ "$fl" = -*(a*u|u*a)* || "$fl" = -*a* && -position 4 -1 ]]; then + compgen -B +elif [[ "$fl" = -*u* ]]; then + compgen -s '$(zmodload)' else - complist -s '${^module_path}/*(N:t:r)' + compgen -s '${^module_path}/*(N:t:r)' fi diff --git a/Completion/Commands/_correct_filename b/Completion/Commands/_correct_filename index edf1c65c2..582555587 100644 --- a/Completion/Commands/_correct_filename +++ b/Completion/Commands/_correct_filename @@ -17,7 +17,8 @@ integer approx max_approx=6 if [[ -e "$file" ]]; then if [[ -n $WIDGET ]]; then - compadd "$file" + compadd -U -i "$IPREFIX" "$file" + [[ -n "$compstate[insert]" ]] && compstate[insert]=menu else print "$file" fi @@ -31,7 +32,8 @@ done (( $#trylist )) || return 1 if [[ -n $WIDGET ]]; then - compadd -U "${trylist[@]}" + compadd -U -i "$IPREFIX" -U "${trylist[@]}" + [[ -n "$compstate[insert]" ]] && compstate[insert]=menu else print "${trylist[@]}" fi diff --git a/Completion/Commands/_most_recent_file b/Completion/Commands/_most_recent_file index ff5645de5..df35ecba7 100644 --- a/Completion/Commands/_most_recent_file +++ b/Completion/Commands/_most_recent_file @@ -1,4 +1,22 @@ #defkeycomp complete-word \C-xm -local file -file=($~PREFIX*$~SUFFIX(om[1]N)) -(( $#file )) && compadd -f $file + +# Complete the most recent file matching the pattern on the line so +# far: globbing is active, i.e. *.txt will be expanded to the most recent +# file ending in .txt +# +# With a prefix argument, select the Nth most recent matching file; +# negative arguments work in the opposite direction, so for example +# `Esc - \C-x m' gets you the oldest file. +# +# (`Most recent' means most recently modified.) + +local file tilde etilde +if [[ $PREFIX = \~*/* ]]; then + tilde=${PREFIX%%/*} + etilde=${~tilde} + file=($~PREFIX*$~SUFFIX(om[$NUMERIC]N)) + file=(${file/#$etilde/$tilde}) +else + file=($~PREFIX*$~SUFFIX(om[$NUMERIC]N)) +fi +(( $#file )) && compadd -U -f -Q $file diff --git a/Completion/Core/_comp_parts b/Completion/Core/_comp_parts index 7c24fd19d..d58669f29 100644 --- a/Completion/Core/_comp_parts +++ b/Completion/Core/_comp_parts @@ -21,11 +21,11 @@ # `_match_test' and `_match_pattern' for this. local str arr sep test testarr tmparr prefix suffixes matchers autosuffix -local matchflags opt group expl +local matchflags opt group expl nm=$compstate[nmatches] # Test if we should use this function for the global matcher in use. -_match_test _comp_parts || return +_match_test _comp_parts || return 1 # Get the options. @@ -42,6 +42,7 @@ shift OPTIND-1 # Get the string from the line. str="$PREFIX$SUFFIX" +[[ -o globcomplete ]] && str="$str:q" prefix="" # Walk through the arguments to find the longest unambiguous prefix. @@ -63,12 +64,14 @@ while [[ $# -gt 1 ]]; do test="${str%%${sep}*}" matchflags="" _match_pattern _comp_parts test matchflags + [[ -n "$_comp_correct" ]] && matchflags="$matchflags(#a$_comp_correct)" test="${matchflags}${test}" testarr=( "${(@M)${(@P)arr}:#${~test}*}" ) + testarr=( "${(@)testarr:#}" ) # If there are no matches we give up. If there is more than one # match, this is the part we will complete. - (( $#testarr )) || return + (( $#testarr )) || return 1 [[ $#testarr -gt 1 ]] && break # Only one match, add it to the prefix and skip over it in `str', @@ -89,11 +92,13 @@ if [[ $# -le 1 || "$str" != *${2}* ]]; then matchflags="" test="$str" _match_pattern _comp_parts test matchflags + [[ -n "$_comp_correct" ]] && matchflags="$matchflags(#a$_comp_correct)" test="${matchflags}${test}" testarr=( "${(@M)${(@P)arr}:#${~test}*}" ) + testarr=( "${(@)testarr:#}" ) fi -[[ $#testarr -eq 0 || ${#testarr[1]} -eq 0 ]] && return +[[ $#testarr -eq 0 || ${#testarr[1]} -eq 0 ]] && return 1 # Now we build the suffixes to give to the completion code. shift @@ -114,6 +119,7 @@ while [[ $# -gt 0 && "$str" == *${1}* ]]; do fi matchflags="" _match_pattern _comp_parts test matchflags + [[ -n "$_comp_correct" ]] && matchflags="$matchflags(#a$_comp_correct)" test="${matchflags}${test}" # We incrementally add suffixes by appending to them the seperators @@ -124,7 +130,9 @@ while [[ $# -gt 0 && "$str" == *${1}* ]]; do tmparr=( ${=arr[2,-2]} ) arr=tmparr fi - suffixes=("${^suffixes[@]}${1}${(@M)^${(@P)arr}:#${~test}*}") + tmparr=( "${(@M)${(@P)arr}:#${~test}*}" ) + tmparr=( "${(@)testarr:#}" ) + suffixes=("${^suffixes[@]}${1}$^tmparr") # We want the completion code to generate the most specific suffix # for us, so we collect matching specifications that allow partial @@ -143,5 +151,10 @@ done # Add the matches for each of the suffixes. for i in "$suffixes[@]"; do - compadd "$group[@]" "$expl[@]" "$matchers[@]" "$autosuffix[@]" -p "$prefix" -s "$i" - "$testarr[@]" + compadd -U "$group[@]" "$expl[@]" "$matchers[@]" "$autosuffix[@]" \ + -i "$IPREFIX" -p "$prefix" -s "$i" - "$testarr[@]" done + +# This sets the return value to indicate that we added matches (or not). + +[[ nm -ne compstate[nmatches] ]] diff --git a/Completion/Core/_compalso b/Completion/Core/_compalso index 23a40e2d0..6ff6cf0bf 100644 --- a/Completion/Core/_compalso +++ b/Completion/Core/_compalso @@ -4,10 +4,10 @@ # It is used to include completions for another command or special context # into the list generated by the calling function. # For example the function for `-subscript-' could call this as in -# `_compalso -math- "$@"' to get the completions that would be generated -# for a mathematical context. +# `_compalso -math-' to get the completions that would be generated for a +# mathematical context. local tmp tmp="$_comps[$1]" -[[ -z "$tmp" ]] || "$tmp" "$@" +[[ -z "$tmp" ]] || "$tmp" diff --git a/Completion/Core/_files b/Completion/Core/_files index d2cce35e7..471824bfe 100644 --- a/Completion/Core/_files +++ b/Completion/Core/_files @@ -3,11 +3,12 @@ # Utility function for completing files of a given type or any file. # In many cases you will want to call this one instead of _path_files(). -local nm=$NMATCHES +local nm=$compstate[nmatches] ret _path_files "$@" +ret=$? -if [[ $# -ne 0 && -nmatches nm ]]; then +if [[ $# -ne 0 && compstate[nmatches] -eq nm ]]; then local opt opts # We didn't get any matches for those types of files described by @@ -23,4 +24,6 @@ if [[ $# -ne 0 && -nmatches nm ]]; then done _path_files "$opts[@]" +else + return $ret fi diff --git a/Completion/Core/_main_complete b/Completion/Core/_main_complete index c7f5a5a96..34c5a3d3c 100644 --- a/Completion/Core/_main_complete +++ b/Completion/Core/_main_complete @@ -2,47 +2,198 @@ # The main loop of the completion code. This is what is called when # completion is attempted from the command line. -# The completion code gives us the special variables and the arguments -# from the command line are given as positional parameters. +# +# This code will automatically try to correct the string on the +# line based on the strings generated for the context if the +# parameter `COMPCORRECT' is set and normal completion didn't yield +# any matches. These corrected strings will be shown in a list and +# one can cycle through them as in a menucompletion. To use this +# feature, `COMPCORRECT' should be set to a number, specifying the +# maximum number of errors that should be accepted. If the string also +# contains a `n' or `N', the code will use the numeric argument as the +# maximum number of errors if a numeric argument was given. If no +# numeric argument was given, the number from the value of +# `COMPCORRECT' will be used. E.g. with `COMPCORRECT=2n' two errors +# will be accepted, but if the user gives another number with the +# numeric argument, this will be prefered. Also, with `COMPCORRECT=0n', +# normally no automatic correction will be tried, but if a numeric +# argument is given, automatic correction will be used. Once the +# number of errors to accept is determined, the code will repeatedly +# try to generate matches by allowing one error, two errors, and so +# on. +# If the parameter `CCORIG' is set (independent of the value), the +# line will first be left unchanged and consecutive TABs cycle through +# the list. +# When using automatic correction, one can also set the parameter +# `CCPROMPT' to a string that will be shown when multiple +# correction results are displayed and the code starts cycling +# through them (this string is used with the `-X' option and thus may +# contain the control sequences `%n', `%B',...). -local comp name +local comp name _comp_correct comax setopt localoptions nullglob rcexpandparam globdots -unsetopt markdirs globsubst shwordsplit nounset - -# An entry for `-first-' is the replacement for `compctl -T' -# Completion functions may set `_compskip' to any value to make the -# main loops stop calling other completion functions. - -comp="$_comps[-first-]" -if [[ ! -z "$comp" ]]; then - "$comp" "$@" - if (( $+_compskip )); then - unset _compskip - return - fi +unsetopt markdirs globsubst shwordsplit nounset ksharrays + +# Special completion contexts after `~' and `='. + +if [[ -iprefix '=' ]]; then + compstate[context]=equal +elif [[ "$PREFIX$SUFFIX" != */* && -iprefix '~' ]]; then + compstate[context]=tilde fi -# For arguments we use the `_normal function. +# This is not an endless loop. -if [[ $CONTEXT == argument || $CONTEXT == command ]]; then - _normal "$@" -else - # Let's see if we have a special completion definition for the other - # possible contexts. +while true; do - comp='' + # An entry for `-first-' is the replacement for `compctl -T' + # Completion functions may set `_compskip' to any value to make the + # main loops stop calling other completion functions. - case $CONTEXT in - redirect) comp="$_comps[-redirect-]";; - math) comp="$_comps[-math-]";; - subscript) comp="$_comps[-subscript-]";; - value) comp="$_comps[-value-]";; - condition) comp="$_comps[-condition-]";; - esac + comp="$_comps[-first-]" + if [[ ! -z "$comp" ]]; then + "$comp" + if (( $+_compskip )); then + unset _compskip + return + fi + fi - # If not, we use default completion, if any. + # For arguments and command names we use the `_normal' function. - [[ -z "$comp" ]] && comp="$_comps[-default-]" - [[ -z "$comp" ]] || "$comp" "$@" -fi + if [[ "$compstate[context]" = command ]]; then + _normal + else + # Let's see if we have a special completion definition for the other + # possible contexts. + + comp='' + + case $compstate[context] in + equal) comp="$_comps[-equal-]";; + tilde) comp="$_comps[-tilde-]";; + redirect) comp="$_comps[-redirect-]";; + math) comp="$_comps[-math-]";; + subscript) comp="$_comps[-subscript-]";; + value) comp="$_comps[-value-]";; + array_value) comp="$_comps[-array-value-]";; + condition) comp="$_comps[-condition-]";; + parameter) comp="$_comps[-parameter-]";; + brace_parameter) comp="$_comps[-brace-parameter-]";; + esac + + # If not, we use default completion, if any. + + [[ -z "$comp" ]] && comp="$_comps[-default-]" + [[ -z "$comp" ]] || "$comp" + fi + + # Use automatic correction? + + if (( $+COMPCORRECT )); then + + # Do we have matches? + if (( compstate[nmatches] )); then + + # Yes, were they added using correction? (More than one match?) + + if [[ -n "$_comp_correct" && compstate[nmatches] -gt 1 ]]; then + + # If we got more than one string from correction, we add the + # original string as a possible match, let it not be shown in + # the list, and probably display the `CCPROMPT'. + + (( $+CCORIG )) && builtin compadd -nQ - "$PREFIX$SUFFIX" + + # If you always want to see the list of possible corrections, + # set `compstate[list]=list' here. + fi + # Since we have matches, we don't want to try again. + break + fi + + # No matches, so let's see if we already tried correction. + + if [[ -n "$_comp_correct" ]]; then + + # Yes, give up if we reached the maximum number of tries, + # otherwise increment our counter. + + [[ _comp_correct -eq comax ]] && break + (( _comp_correct++ )) + + elif [[ compstate[matcher] -eq compstate[total_matchers] ]]; then + + # No matches and no correction tried yet, but we just tried the + # last global match specification, so let's see if we should use + # correction now. First, get the maximum number of errors. + + if [[ "$COMPCORRECT" = *[nN]* && NUMERIC -ne 1 ]]; then + # Prefer the numeric argument if that has a sensible value. + comax="$NUMERIC" + else + comax="${COMPCORRECT//[^0-9]}" + fi + # If the number of errors to accept is to small, give up. + + [[ "$comax" -lt 1 ]] && break + + # Otherwise temporarily define functions to use instead of + # the builtins that add matches. This is used to be able + # to stick the `(#a...)' into the right place (after an + # ignored prefix). + + compadd() { + if [[ "$PREFIX" = \~*/* ]]; then + PREFIX="${PREFIX%%/*}/(#a${_comp_correct})${PREFIX#*/}" + else + PREFIX="(#a${_comp_correct})$PREFIX" + fi + if (( $+CCPROMPT )); then + builtin compadd -X "$CCPROMPT" -J _correct "$@" + else + builtin compadd -J _correct "$@" + fi + } + compgen() { + if [[ "$PREFIX" = \~*/* ]]; then + PREFIX="${PREFIX%%/*}/(#a${_comp_correct})${PREFIX#*/}" + else + PREFIX="(#a${_comp_correct})$PREFIX" + fi + if (( $+CCPROMPT )); then + builtin compgen "$@" -X "$CCPROMPT" -J _correct + else + builtin compgen "$@" -J _correct + fi + } + # Now initialise our counter. We also set `compstate[matcher]' + # to `-1'. This allows completion functions to use the simple + # `[[ compstate[matcher] -gt 1 ]] && return' to avoid being + # called for multiple global match specs and still be called + # again when correction is done. Also, this makes it easy to + # test if correction is attempted since `compstate[matcher]' + # will never be set to a negative value by the completion code. + + _comp_correct=1 + compstate[matcher]=-1 + + # We also need to set `extendedglob' and to make the completion + # code behave as if globcomplete were set. + + setopt extendedglob + compstate[pattern_match]=yes + else + # We are still trying global match specifications... + break + fi + else + # No automatic correction to try, just give up. + break + fi +done + +# If we added wrapper functions, remove them. + +[[ -n "$_comp_correct" ]] && unfunction compadd compgen diff --git a/Completion/Core/_multi_parts b/Completion/Core/_multi_parts new file mode 100644 index 000000000..1f51d2f6d --- /dev/null +++ b/Completion/Core/_multi_parts @@ -0,0 +1,201 @@ +#autoload + +# This gets two arguments, a separator (which should be only one +# character) and an array. As usual, the array may be given by it's +# name or literal as in `(foo bar baz)' (words separated by spaces in +# parentheses). +# The parts of words from the array that are separated by the +# separator character are then completed independently. + +local sep matches patstr orig matchflags pref i tmp1 tmp2 nm +local group expl + +_match_test _multi_parts || return 1 + +# Save the current number of matches to be able to return if we added +# matches or not. + +nm=$compstate[nmatches] + +# Get the options. + +group=() +expl=() +while getopts "J:V:X:" opt; do + case "$opt" in + [JV]) group=("-$opt" "$OPTARG");; + X) expl=(-X "$OPTARG");; + esac +done +shift OPTIND-1 + +# Get the arguments, first the separator, then the array. The array is +# stored in `matches'. Further on this array will always contain those +# words from the original array that still match everything we have +# tried to match while we walk through the string from the line. + +sep="$1" +if [[ "${2[1]}" = '(' ]]; then + matches=( ${2[2,-2]} ) +else + matches=( "${(@P)2}" ) +fi + +# Now build the pattern from what we have on the line. We also save +# the original string in `orig'. The `eval' is used to replace our +# separator character by `*'. + +if [[ -o globcomplete ]]; then + patstr="${PREFIX}*${SUFFIX}*" +else + patstr="${PREFIX:q}*${SUFFIX:q}*" +fi +orig="${PREFIX}${SUFFIX}" + +matchflags="" +_match_pattern _path_files patstr matchflags +[[ -n "$_comp_correct" ]] && matchflags="$matchflags(#a$_comp_correct)" + +patstr="${${patstr//$sep/*$sep}//\*##/*}" +#eval patstr\="\$patstr:gs-${sep}-\*${sep}-:gs/\*\*/\*/" + +# First we will skip over those parts of the matches for which we have +# exact substrings on the line. In `pref' we will build the +# unambiguous prefix string. + +pref='' +while [[ "$orig" = *${sep}* ]] do + + # First build the pattern to use, then collect all strings from + # `matches' that match the prefix we have and the exact substring in + # the array `tmp1'. + + pat="${${${patstr#*${sep}}%${sep}*}//\*/[^${sep}]#}${patstr##*${sep}}" + tmp1=( "${(@M)matches:#${~matchflags}${orig%%${sep}*}${sep}${~pat}}" ) + + # If there are no words matching the exact substring, stop. + + (( $#tmp1 )) || break + + # Otherwise add the part to the prefix, remove it from the matches + # (which will also remove all words not matching the string at all), + # and set `patstr' and `orig' to the next component. + + pref="$pref${orig%%${sep}*}${sep}" + matches=( "${(@)${(@)matches#${orig%%${sep}*}${sep}}:#}" ) + orig="${orig#*${sep}}" + patstr="${patstr#*${sep}}" +done + +# Now we get all the words that still match in `tmp1'. + +if [[ "$patstr" = *${sep}* ]]; then + tmp1="${patstr%${sep}*}${sep}" + pat="${tmp1//\*/[^${sep}]#}${patstr##*${sep}}" +else + pat="$patstr" +fi +tmp1=( "${(@M)matches:#${~matchflags}${~pat}}" ) + +if (( $#tmp1 )); then + + # There are words that are matched, put them int `matches' and then + # move all unambiguous components from the beginning into `pref'. + + matches=( "$tmp1[@]" ) + while [[ "$matches[1]" = *${sep}* ]]; do + + # We just take the first component of the first match and see if + # there are other matches with a different prefix (these are + # collected in `tmp2'). If there are any, we give up. + + tmp1="${matches[1]%%${sep}*}${sep}" + tmp2=( "${(@)matches:#${tmp1}*}" ) + (( $#tmp2 )) && break + + # All matches have the same prefix, but it into `pref' and remove + # it from the matches. + + pref="$pref$tmp1" + matches=( "${(@)${(@)matches#$tmp1}:#}" ) + + if [[ "$orig" = *${sep}* ]]; then + orig="${orig#*${sep}}" + else + orig='' + fi + done + + # Now we can tell the completion code about the things we + # found. Strings that have a separator will be added with a suffix. + + if [[ -z "$orig" && "$PREFIX$SUFFIX" != "$pref$orig" ]]; then + compadd -QU "$group[@]" "$expl[@]" -i "$IPREFIX" -S '' - "${pref}${orig}" + elif [[ $compstate[insert] = *menu ]]; then + for i in "$matches[@]" ; do + if [[ "$i" = *${sep}* ]]; then + compadd -U "$group[@]" "$expl[@]" -i "$IPREFIX" \ + -p "$pref" -qS "$sep" - "${i%%${sep}*}" + else + compadd -U "$group[@]" "$expl[@]" -i "$IPREFIX" \ + -p "$pref" - "${i%%${sep}*}" + fi + done + else + for i in "$matches[@]" ; do + if [[ "$i" = *${sep}* ]]; then + compadd -U -i "$IPREFIX" -p "$pref" -s "${sep}${i#*${sep}}" \ + "$group[@]" "$expl[@]" -M "r:|${sep}=*" - "${i%%${sep}*}" + else + compadd -U "$group[@]" "$expl[@]" -i "$IPREFIX" -p "$pref" - "$i" + fi + done + fi +elif [[ "$patstr" = *${sep}* ]]; then + + # We had no words matching the string from the line. But we want to + # be friendly and at least expand the prefix as far as we can. So we + # will loop through the rest of the string from the line and test + # the components one by one. + + while [[ "$patstr" = *${sep}* ]]; do + + # First we get all words matching at least this component in + # `tmp1'. If there are none, we give up. + + tmp1=( "${(@M)matches:#${~matchflags}${~patstr%%${sep}*}${sep}*}" ) + (( $#tmp1 )) || break + + # Then we check if there are words that have a different prefix. + + tmp2=( "${(@)tmp1:#${tmp1[1]%%${sep}*}${sep}*}" ) + if (( $#tmp2 )); then + + # There are words with another prefix, so we have found an + # ambiguous component. So we just give all possible prefixes to + # the completion code together with our prefix and the rest of + # the string from the line as the suffix. + + compadd -U "$group[@]" "$expl[@]" -S '' -i "$IPREFIX" -p "$pref" \ + -s "${sep}${orig#*${sep}}" - "${(@)matches%%${sep}*}" + return 0 + fi + + # All words have the same prefix, so add it to `pref' again and + # try the next component. + + pref="$pref${tmp1[1]%%${sep}*}${sep}" + matches=( "${(@)matches#${tmp1[1]%%${sep}*}${sep}}" ) + orig="${orig#*${sep}}" + patstr="${patstr#*${sep}}" + done + + # Finally, add the unambiguous prefix and the rest of the string + # from the line. + + compadd -U "$group[@]" "$expl[@]" -S '' -i "$IPREFIX" -p "$pref" - "$orig" +fi + +# This sets the return value to indicate that we added matches (or not). + +[[ nm -ne compstate[nmatches] ]] diff --git a/Completion/Core/_normal b/Completion/Core/_normal index 19da6d79b..f56849194 100644 --- a/Completion/Core/_normal +++ b/Completion/Core/_normal @@ -1,24 +1,25 @@ #autoload -local comp cmd1 cmd2 pat val name +local comp command cmd1 cmd2 pat val name i ret # 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 +command="$words[1]" +if [[ CURRENT -eq 1 ]]; then comp="$_comps[-command-]" - [[ -z "$comp" ]] || "$comp" "$@" + [[ -z "$comp" ]] || "$comp" return -elif [[ "$COMMAND[1]" == '=' ]]; then - eval cmd1\=$COMMAND - cmd2="$COMMAND[2,-1]" -elif [[ "$COMMAND" == */* ]]; then - cmd1="$COMMAND" - cmd2="${COMMAND:t}" +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) + cmd1="$command" + eval cmd2=$(whence -p $command) fi # See if there are any matching pattern completions. @@ -27,10 +28,11 @@ for i in "$_patcomps[@]"; do pat="${i% *}" val="${i#* }" if [[ "$cmd1" == $~pat || "$cmd2" == $~pat ]]; then - "$val" "$@" + "$val" + ret=$? if (( $+_compskip )); then unset _compskip - return + return $ret fi fi done @@ -51,4 +53,4 @@ if [[ -z "$comp" ]]; then name=-default- comp="$_comps[-default-]" fi -[[ -z "$comp" ]] || "$comp" "$@" +[[ -z "$comp" ]] || "$comp" diff --git a/Completion/Core/_path_files b/Completion/Core/_path_files index 83b6e8a09..3c03c0c61 100644 --- a/Completion/Core/_path_files +++ b/Completion/Core/_path_files @@ -3,7 +3,7 @@ # Utility function for in-path completion. # Supported arguments are: `-f', `-/', `-g ', `-J ', # `-V ', `-W paths', `-X explanation', and `-F '. All but -# the last have the same syntax and meaning as for `complist'. The +# the last have the same syntax and meaning as for `compgen'. The # `-F ' option may be used to give a list of suffixes either by # giving the name of an array or literally by giving them in a string # surrounded by parentheses. Files with one of the suffixes thus given @@ -14,13 +14,13 @@ # First see if we should generate matches for the global matcher in use. -_match_test _path_files || return +_match_test _path_files || return 1 # Yes, so... local nm prepaths str linepath realpath donepath patstr prepath testpath rest local tmp1 collect tmp2 suffixes i ignore matchflags opt group sopt pats gopt -local addpfx addsfx expl +local addpfx addsfx expl orig ostr nm=$compstate[nmatches] setopt localoptions nullglob rcexpandparam globdots extendedglob unsetopt markdirs globsubst shwordsplit nounset @@ -91,14 +91,14 @@ fi # str holds the whole string from the command line with a `*' between # the prefix and the suffix. -str="${PREFIX:q}*${SUFFIX:q}" - -# If the string began with a `~', the quoting turned this into `\~', -# remove the slash. - -[[ "$str" = \\\~* ]] && str="$str[2,-1]" +if [[ -o globcomplete ]]; then + str="${PREFIX}*${SUFFIX}" +else + str="${PREFIX:q}*${SUFFIX:q}" +fi +orig="${PREFIX}${SUFFIX}" -# We will first try normal completion called with `complist', but only if we +# We will first try normal completion called with `compgen', but only if we # weren't given a `-F' option. if (( ! $#ignore )); then @@ -112,18 +112,18 @@ if (( ! $#ignore )); then tmp1=(-W "( $prepaths )") fi - # Now call complist. + # Now call compgen. - nm=$NMATCHES + nm=$compstate[nmatches] if [[ -z "$gopt" ]]; then - complist "$addpfx[@]" "$addsfx[@]" "$group[@]" "$expl[@]" "$tmp1[@]" $sopt + compgen "$addpfx[@]" "$addsfx[@]" "$group[@]" "$expl[@]" "$tmp1[@]" $sopt else - complist "$addpfx[@]" "$addsfx[@]" "$group[@]" "$expl[@]" "$tmp1[@]" $sopt -g "$pats" + compgen "$addpfx[@]" "$addsfx[@]" "$group[@]" "$expl[@]" "$tmp1[@]" $sopt -g "$pats" fi # If this generated any matches, we don't want to do in-path completion. - [[ -nmatches nm ]] || return + [[ compstate[nmatches] -eq nm ]] || return 0 # No `-F' option, so we want to use `fignore'. @@ -142,14 +142,16 @@ if [[ "$str[1]" = \~ ]]; then linepath="${str%%/*}/" eval realpath\=$linepath + [[ "$realpath" = "$linepath" ]] && return 1 str="${str#*/}" + orig="${orig#*/}" donepath='' prepaths=( '' ) else # If the string does not start with a `~' we don't remove a prefix from the # string. - liniepath='' + linepath='' realpath='' if [[ "$str[1]" = / ]]; then @@ -158,6 +160,7 @@ else # Also, we don't use the paths from `-W'. str="$str[2,-1]" + orig="$orig[2,-1]" donepath='/' prepaths=( '' ) else @@ -169,28 +172,31 @@ else fi fi -# First we skip over all pathname components in `str' which really exist in -# the file-system, so that `/usr/lib/l' doesn't offer you `lib' and -# `lib5'. Pathname components skipped this way are taken from `str' and added -# to `donepath'. - -while [[ "$str" = */* ]] do - [[ -e "$realpath$donepath${str%%/*}" ]] || break - donepath="$donepath${str%%/*}/" - str="${str#*/}" -done - # Now build the glob pattern by calling `_match_pattern'. patstr="$str" matchflags="" _match_pattern _path_files patstr matchflags +[[ -n "$_comp_correct" ]] && matchflags="$matchflags(#a$_comp_correct)" # We almost expect the pattern to have changed `..' into `*.*.', `/.' into # `/*.', and probably to contain two or more consecutive `*'s. Since these # have special meaning for globbing, we remove them. But before that, we # add the pattern for matching any characters before a slash. -patstr="$patstr:gs-/-*/-:gs/*.*.//:gs-/*.-/.-:gs/**/*/" +patstr="$patstr:gs-/-*/-:gs/*.*./../:gs-/*.-/.-:gs/**/*/:gs-.*/-./-" + +# First we skip over all pathname components in `str' which really exist in +# the file-system, so that `/usr/lib/l' doesn't offer you `lib' and +# `lib5'. Pathname components skipped this way are taken from `orig' and added +# to `donepath'. + +while [[ "$orig" = */* ]] do + tmp1=( ${~matchflags}$realpath$donepath${orig%%/*}/${~patstr#*/}$^pats ) + [[ $#tmp1 -gt 0 && -e "$realpath$donepath${orig%%/*}" ]] || break + donepath="$donepath${orig%%/*}/" + orig="${orig#*/}" + patstr="${patstr#*/}" +done # Finally, generate the matches. First we loop over all the paths from `-W'. # Note that in this loop `str' is used as a modifyable version of `patstr' @@ -199,6 +205,9 @@ patstr="$patstr:gs-/-*/-:gs/*.*.//:gs-/*.-/.-:gs/**/*/" for prepath in "$prepaths[@]"; do str="$patstr" testpath="$donepath" + ostr="$orig" + + [[ -z "$prepath" || "$prepath[-1]" = / ]] || prepath="${prepath}/" # The second loop tests the components of the path in `str' to get the # possible matches. @@ -235,16 +244,20 @@ for prepath in "$prepaths[@]"; do # the suffixes we just built are used to produce possible matches # via globbing. - for i in $tmp1; do + for i in "$tmp1[@]" ; do tmp2=( ${~i}/${~matchflags}${~suffixes} ) [[ $#tmp2 -ne 0 ]] && collect=( $collect $i ) done # If this test showed that none of the matches from the glob in `tmp1' - # has a possible sub-path matching what's on the line, we give up and - # continue with the next `-W' path. + # has a possible sub-path matching what's on the line, we add the + # matches found in `tmp1' and otherwise give up and continue with the + # next `-W' path. if [[ $#collect -eq 0 ]]; then + compadd -QU "$addpfx[@]" "$addsfx[@]" "$group[@]" "$expl[@]" \ + -i "$IPREFIX" -p "${linepath:q}${testpath:q}" -S "/${ostr#*/}" \ + -W "$tmp1" -f "$ignore[@]" - "${(@)tmp1:q}" continue 2 elif [[ $#collect -ne 1 ]]; then # If we have more than one possible match, this means that the @@ -269,9 +282,17 @@ for prepath in "$prepaths[@]"; do # these are file names and that `fignore' should be used as usual # (the `-f' and `-F' options). - for i in $collect; do - compadd "$addpfx[@]" "$addsfx[@]" "$group[@]" "$expl[@]" -p "$linepath$testpath" -W "$tmp1" -s "/${i#*/}" -f "$ignore[@]" - "${i%%/*}" - done + if [[ $compstate[insert] = *menu ]]; then + compadd -QU "$addpfx[@]" "$addsfx[@]" "$group[@]" "$expl[@]" \ + -i "$IPREFIX" -p "${linepath:q}${testpath:q}" -S "/${ostr#*/}" \ + -W "$tmp1" -f "$ignore[@]" - "${(@)${(@)collect%%/*}:q}" + else + for i in $collect; do + compadd -U "$addpfx[@]" "$addsfx[@]" "$group[@]" "$expl[@]" \ + -i "$IPREFIX" -p "$linepath$testpath" -s "/${i#*/}" \ + -M 'r:|/=*' -W "$tmp1" -f "$ignore[@]" - "${i%%/*}" + done + fi # We have just finished handling all the matches from above, so we # can continue with the next `-W' path. @@ -291,6 +312,7 @@ for prepath in "$prepaths[@]"; do tmp1="$tmp1[1]" testpath="$testpath${tmp1##*/}/" str="$rest" + ostr="${ostr#*/}" done # We are here if all pathname components except the last one (which is still @@ -302,10 +324,24 @@ for prepath in "$prepaths[@]"; do suffixes=( $str$^pats ) suffixes=( "${(@)suffixes:gs.**.*.}" ) tmp2=( ${~tmp1}${~matchflags}${~suffixes} ) - if [[ $#tmp2 -eq 0 && "$sopt" = */* ]]; then + if [[ $#tmp2 -eq 0 ]]; then + # No match, insert the expanded path and add the original tail. + [[ "$testpath[-1]" = / ]] && testpath="$testpath[1,-2]" - compadd "$addpfx[@]" "$addsfx[@]" "$group[@]" "$expl[@]" -f - "$linepath$testpath" + [[ -n "$ostr" && -n "$linepath$testpath" ]] && ostr="/$ostr" + + # But only if something changed. + [[ "$linepath$testpath$ostr" = "$PREFIX$SUFFIX" ]] && return 1 + + compadd -QU -S '' "$group[@]" "$expl[@]" \ + -i "$IPREFIX" -f - "${linepath:q}${testpath:q}$ostr" else - compadd "$addpfx[@]" "$addsfx[@]" "$group[@]" "$expl[@]" -p "$linepath$testpath" -W "$prepath$realpath$testpath" -f "$ignore[@]" - ${(@)tmp2#$tmp1} + compadd -U "$addpfx[@]" "$addsfx[@]" "$group[@]" "$expl[@]" \ + -i "$IPREFIX" -p "$linepath$testpath" -f "$ignore[@]" \ + -W "$prepath$realpath$testpath" - "${(@)tmp2#$tmp1}" fi done + +# This sets the return value to indicate that we added matches (or not). + +[[ nm -ne compstate[nmatches] ]] diff --git a/Completion/README b/Completion/README index ac2accfca..43ffcbcc2 100644 --- a/Completion/README +++ b/Completion/README @@ -11,14 +11,15 @@ loading much faster. For example, [[ -f ~/completion/compinit ]] && . ~/completion/compinit -d This will rebind any keys which do completion to use the new system. For more detailed instructions, including how to add new completions, see -the top of Core/compinit . +the top of Core/compinit. The subdirectories contain: Core: The basic functions and files to be sourced. You will certainly need - these, and will most likely not feel like altering them (or, in some - cases, even reading them, unless you are a shell wizard). The files are: + these, and will most likely not want to alter them --- if you do, it + would probably help to give your version a different name. The files + are: compinit As already described, this is not a function, but is sourced once (with the `source' or `.' commands) to set up the completion system. @@ -29,6 +30,9 @@ Core: _comp_parts Utility used for completing words with multiple separate parts, such as `@' + _multi_parts + Utility for completion parts of words given a separator character and + a list of words. _compalso Utility for calling a function to add additional completions to an already existing set. @@ -46,7 +50,7 @@ Core: it is wider than just command+argument.) _path_files The function usually called to complete filenames and directories. It - replaces the standard -f and -/ options for the basic completion + replaces the standard -f, -g and -/ options for the basic completion commands: it can do various extra tricks, such as expanding a whole path at once, e.g. F/C/C/_p -> Functions/Completion/Core/_path_files Base: @@ -65,22 +69,29 @@ Base: as you wish. _match_pattern _match_test - These are used by Base/_path_files (and hence also Base/_files) for - file completion with control over matching (whether to complete - case-insensitively, or to allow insertion before `.', etc.) See - _match_test for instructions. Note _path_files expects these files - to be present. + These are used by Base/_path_files (and hence also Base/_files) + and Base/_comp_parts for file completion with control over + matching (whether to complete case-insensitively, or to allow + insertion before `.', etc.) See _match_test for instructions. + Note _path_files expects these files to be present. _precommand Allows completion when the first word on the line has to be ignored, for example `noglob ...' should ignore the noglob and just complete as if it wasn't there. Add other such commands to the top line. _redirect - Completes after `<' or `<': this version calls _files. + Completes after `<' or `>': this version calls _files. _subscript For completion in subscripts of parameters, e.g $foo[...]. _vars Completion for commands which need variables (so this could also be in the Builtins directory), but also in math environments such as ((...)). + _tilde + Completion after `~', defaults to user names and named directories. + _equal + Completion after `=', normally command and alias names are used. + _parameter + _brace_parameter + For completion inside parameter expansions ($... and ${...). Builtins: Define completions for various shell builtins. The top line of each file says which builtins they apply to; in many cases you can guess from the diff --git a/Completion/User/_a2ps b/Completion/User/_a2ps index 9aa9d3d99..600b58872 100644 --- a/Completion/User/_a2ps +++ b/Completion/User/_a2ps @@ -1,22 +1,22 @@ #defcomp a2ps -if [[ -prefix -- ]]; then +if [[ "$PREFIX[1,2]" = -- ]]; then _comp_parts '(--borders --compact --truncate-lines --interpret --print-anyway --delegate)' '=' '(yes no)' _comp_parts '(--major)' '=' '(rows columns)' _comp_parts '(--end-of-line)' '=' '(r n nr rn any)' - complist -S= -k '(--medium --columns --rows --line-numbers + compgen -S= -k '(--medium --columns --rows --line-numbers --font-size --lines-per-page --chars-per-line --tabsize --non-printable-format --encoding --title --stdin --prologue --highlight-level --strip-level --output --version-control --suffix --printer --copies --sides --page-prefeed --no-page-prefeed)' - complist -qS= -k '(--margin --header --underlay --left-title + compgen -qS= -k '(--margin --header --underlay --left-title --right-title --left-footer --footer --right-footer --pages --pretty-print)' - complist -k '(--landscape --portrait --catman --no-header)' + compgen -k '(--landscape --portrait --catman --no-header)' else _files -F fignore -g "*~*.ps" fi diff --git a/Completion/User/_configure b/Completion/User/_configure index de8d5fba5..050701fac 100644 --- a/Completion/User/_configure +++ b/Completion/User/_configure @@ -1,12 +1,35 @@ #defcomp configure +setopt localoptions extendedglob + if [[ $PREFIX = *=* ]]; then # Complete filenames after e.g. --prefix= IPREFIX=${PREFIX%%=*}= PREFIX=${PREFIX#*=} - complist -f + compgen -f else # Generate a list of options from configure --help - complist -s '$($COMMAND --help | - sed -n -e '\''s/^ *\(--[-a-z0-9]*\)[ =,].*$/\1/p'\'')' + local -a pars + local i + pars=($($words[1] --help | awk '$1 ~ /--[a-z]*.*/ {print $1}')) + for i in $pars + do + case $i in + (--(((en|dis)able-FEATURE)|(with(out|)-PACKAGE))*) + : Skip standard help output + ;; + --enable) + : Skip standard help output + ;; + --*\[=* ) + compadd -M 'r:|-=* r:|=*' -q -S = -- ${i%%\[=*} + ;; + --*=* ) + compadd -M 'r:|-=* r:|=*' -S = -- ${i%%=*} + ;; + * ) + compadd -M 'r:|-=* r:|=*' -- $i + ;; + esac + done fi diff --git a/Completion/User/_dd b/Completion/User/_dd index 2458541ea..86a47b1ab 100644 --- a/Completion/User/_dd +++ b/Completion/User/_dd @@ -4,10 +4,10 @@ if [[ -iprefix conv= ]]; then # If there's a comma present, ignore up to the last one. The # test alone will have that effect. [[ -string , ]] - complist -S, -q \ + compgen -S, -q \ -k '(ascii ebcdic ibm block unblock lcase ucase swab noerror sync)' elif [[ -iprefix 'if=' || -iprefix 'of=' ]]; then _files else - complist -S '=' -k '(if of ibs obs bs cbs skip files seek count conv)' + compgen -S '=' -k '(if of ibs obs bs cbs skip files seek count conv)' fi diff --git a/Completion/User/_find b/Completion/User/_find index ca4f79908..8fcdafb83 100644 --- a/Completion/User/_find +++ b/Completion/User/_find @@ -1,21 +1,23 @@ #defcomp find +local prev="$words[CURRENT-1]" + if [[ -mbetween -(ok|exec) \\\; ]]; then - _normal "$@" + _normal elif [[ -iprefix - ]]; then - complist -s 'daystart {max,min,}depth follow noleaf version xdev \ + compgen -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' -elif [[ -position 1 ]]; then - complist -g '. ..' +elif [[ -position 2 ]]; then + compgen -g '. ..' _files -g '(-/)' -elif [[ -mcurrent -1 -((a|c|)newer|fprint(|0|f)) ]]; then +elif [[ "$prev" = -((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 +elif [[ "$prev" = -fstype ]]; then + compgen -k '(ufs 4.2 4.3 nfs tmp mfs S51K S52K)' +elif [[ "$prev" = -group ]]; then + compgen -k groups +elif [[ "$prev" = -user ]]; then + compgen -u fi diff --git a/Completion/User/_hosts b/Completion/User/_hosts index 3acc327ac..eb418c5b3 100644 --- a/Completion/User/_hosts +++ b/Completion/User/_hosts @@ -1,3 +1,3 @@ #defcomp ftp ncftp ping rwho rup xping traceroute nslookup -complist -k hosts +compgen -k hosts diff --git a/Completion/User/_make b/Completion/User/_make index d576b0308..24d2cf3f5 100644 --- a/Completion/User/_make +++ b/Completion/User/_make @@ -1,3 +1,3 @@ #defcomp make gmake pmake -complist -s "\$(awk '/^[a-zA-Z0-9][^/ ]+:/ {print \$1}' FS=: [mM]akefile)" +compgen -s "\$(awk '/^[a-zA-Z0-9][^/ ]+:/ {print \$1}' FS=: [mM]akefile)" diff --git a/Completion/User/_man b/Completion/User/_man index 8204fba0b..67d59f24a 100644 --- a/Completion/User/_man +++ b/Completion/User/_man @@ -2,10 +2,10 @@ setopt localoptions rcexpandparam local rep -if [[ $2 = (<->*|ln) ]]; then - rep=( $manpath/(man|cat)$2/$PREFIX*$SUFFIX.<->*(N:t:r) ) +if [[ $words[2] = (<->*|ln) ]]; then + rep=( $manpath/(man|cat)${words[2]}/$PREFIX*$SUFFIX.<->*(N:t:r) ) else rep=( $manpath/(man|cat)*/$PREFIX*$SUFFIX.<->*(N:t:r) ) fi -(( $#rep )) && compadd -m $rep +(( $#rep )) && compadd - $rep diff --git a/Completion/User/_mh b/Completion/User/_mh index 67ce49fd2..7e8575123 100644 --- a/Completion/User/_mh +++ b/Completion/User/_mh @@ -1,4 +1,4 @@ -#defcomp folder comp inc mark refile repl scan show next prev rmm pick whom mhn mhpath mhpatch +#defcomp folder folders comp inc mark refile repl scan show next prev rmm pick whom mhn mhpath # Completion for all possible MH commands. # Alter the following two to your own mh directory and the directory @@ -7,6 +7,8 @@ local mymhdir=~/Mail local mhlib=/usr/lib/mh +local prev="$words[CURRENT-1]" + # To be on the safe side, check this exists and if not, get it anyway. [[ -d $mymhdir ]] || mymhdir=$(mhpath +) @@ -14,13 +16,13 @@ if [[ -iprefix - ]]; then # get list of options, which MH commands can generate themselves # awk is just too icky to use for this, sorry. send me one if # you come up with it. - compadd -m $($COMMAND -help | perl -ne 'if (/^\s*-\(?(\S+)/) { + compadd - $($words[1] -help | perl -ne 'if (/^\s*-\(?(\S+)/) { $n = $1; $n =~ s/\)//g; print $n =~ s/^\[([a-z]+)\]// ? "$n\n$1$n\n" : "$n\n"; }') return -elif [[ -iprefix '+' || -iprefix '@' || -current -1 -draftfolder ]]; then +elif [[ -iprefix '+' || -iprefix '@' || "$prev" = -draftfolder ]]; then # Complete folder names. local mhpath if [[ $IPREFIX != '@' ]]; then @@ -31,12 +33,12 @@ elif [[ -iprefix '+' || -iprefix '@' || -current -1 -draftfolder ]]; then fi # painless, or what? - complist -W mhpath -/ -elif [[ -mcurrent -1 -(editor|(whatnow|rmm|show|more)proc) ]]; then - complist -c -elif [[ -current -1 -file ]]; then - complist -f -elif [[ -mcurrent -1 -(form|audit|filter) ]]; then + _path_files -W mhpath -/ +elif [[ "$prev" = -(editor|(whatnow|rmm|show|more)proc) ]]; then + compgen -c +elif [[ "$prev" = -file ]]; then + compgen -f +elif [[ "$prev" = -(form|audit|filter) ]]; then # Need some MH template file, which may be in our own MH directory # or with the standard library. local mhfpath @@ -44,11 +46,11 @@ elif [[ -mcurrent -1 -(form|audit|filter) ]]; then [[ -d $mhlib ]] || { mhlib=$(mhparam mhlproc); mhlib=$mhlib:h; } mhfpath=($mymhdir $mhlib) - complist -W mhfpath -g '*(.)' -elif [[ -mcurrent -1 -(no|)cc ]]; then - compadd -m all to cc me -elif [[ -mcurrent -1 -[rw]cache ]]; then - compadd -m public private never ask + compgen -W mhfpath -g '*(.)' +elif [[ "$prev" = -(no|)cc ]]; then + compadd all to cc me +elif [[ "$prev" = -[rw]cache ]]; then + compadd public private never ask else # Generate sequences. local foldnam folddir f @@ -64,7 +66,7 @@ else # leaving foldnam empty works here fi - complist -s '$(mark $foldnam | awk -F: '\''{ print $1 }'\'')' - compadd -m reply next cur prev first last all unseen - complist -W folddir -g '<->' + compgen -s '$(mark $foldnam 2>/dev/null | awk -F: '\''{ print $1 }'\'')' + compadd reply next cur prev first last all unseen + compgen -W folddir -g '<->' fi diff --git a/Completion/User/_rcs b/Completion/User/_rcs index 537db6278..5a751605c 100644 --- a/Completion/User/_rcs +++ b/Completion/User/_rcs @@ -1,9 +1,11 @@ #defcomp co ci rcs -[[ $COMMAND = ci || $COMMAND = rcs ]] && _files +local nm=$compstate[nmatches] -if [[ $NMATCHES -eq 0 && -d RCS && $COMMAND != ci ]]; then +[[ $words[1] = ci || $words[1] = rcs ]] && _files + +if [[ $compstate[nmatches] -eq nm && -d RCS && $words[1] != ci ]]; then local rep rep=(RCS/$PREFIX*$SUFFIX,v(:t:s/\,v//)) - (( $#rep )) && compadd -m $rep + (( $#rep )) && compadd - $rep fi diff --git a/Completion/User/_rlogin b/Completion/User/_rlogin index e36554f23..5d6daef9b 100644 --- a/Completion/User/_rlogin +++ b/Completion/User/_rlogin @@ -1,9 +1,9 @@ #defcomp rlogin rsh ssh -if [[ -position 1 ]]; then - complist -k hosts -elif [[ -position 2 ]]; then - complist -k '(-l)' +if [[ CURRENT -eq 2 ]]; then + compgen -k hosts +elif [[ CURRENT -eq 3 ]]; then + compgen -k '(-l)' else - complist -u + compgen -u fi diff --git a/Completion/User/_stty b/Completion/User/_stty index 6b54b5007..d32d6bdff 100644 --- a/Completion/User/_stty +++ b/Completion/User/_stty @@ -1,12 +1,12 @@ #defcomp stty -if [[ -mcurrent -1 \ +if [[ "$words[CURRENT-1]" = \ (*erase|discard|status|dsusp|intr|kill|lnext|quit|reprint|start|s*p) ]] then - compadd -m -Q '^-' '^h' '^?' '^c' '^u' + compadd -Q '^-' '^h' '^?' '^c' '^u' else [[ -string '-' || -string '+' ]] - compadd -m rows columns intr quit erase kill eof eol \ + compadd rows columns intr quit erase kill eof eol \ eol2 start stop susp dsusp reprint discard werase lnext \ parenb parodd cs8 cstopb hupcl cread clocal parext \ ignbrk brkint ignpar parmrk inpck istrip inlcr igncr icrnl iuclc \ diff --git a/Completion/User/_tar b/Completion/User/_tar index 91767e44d..84c490f1e 100644 --- a/Completion/User/_tar +++ b/Completion/User/_tar @@ -1,11 +1,69 @@ #defcomp tar -local nm=$NMATCHES tf="$2" +# Tar completion. Features: +# - Assumes tar commands are in second position, tar archive is in third +# e.g. tar xvzf zsh-3.0.5.tar.gz ... +# Could search better. Send me the patch. +# - `tar' can be called anything, will use the correct name +# - Preferentially completes *.tar and *.TAR files in third position +# - unless z or Z appears in the commands, in which case prefer *.tar.gz +# and similar (GNU tar). +# - From fourth position on, if command is x or t, completes files inside +# archive. This is supposed to look pretty much as if the files are +# in an ordinary directory hierarchy. Handles extraction from compressed +# archives (GNU tar). +# - Anywhere -- appears, gets a list of long options to complete from +# tar itself (GNU tar); this needs perl. If you have GNU tar but not +# perl: your system manager is weird. +# - Things like --directory=... are also completed correctly. -if [[ ( -mword 1 *t*f* || -mword 1 *x*f* ) && -position 3 100000 ]]; then - complist -k "( $(tar tf $tf) )" -elif [[ -mword 1 *c*f* && -position 3 100000 ]]; then +emulate -LR zsh +setopt extendedglob + +local nm=$NMATCHES tcmd="$words[2]" tf="$words[3]" + +if [[ $PREFIX = *=* ]]; then + # For GNU tar arguments like --directory= + IPREFIX=${PREFIX%%\=*}= + PREFIX=${PREFIX#*=} + if [[ $IPREFIX = --directory* ]]; then + _path_files -/ + else + _files + fi +elif [[ $PREFIX = --* ]]; then + # gnu tar, generate completions from --help + # ones followed by = get that as a suffix + local -a ownlist eqlist + local comp + $words[1] --help | + perl -ne 'while (/--[^[\s,='\'']+=?/g) { print "$&\n"; }' | + while read comp; do + if [[ $comp = *= ]]; then + eqlist[$#eqlist+1]=${comp%=} + else + ownlist[$#ownlist+1]=$comp + fi + done + compgen -S '=' -k eqlist + compgen -k ownlist +elif [[ "$tcmd" = *[tx]*f* && $CURRENT -ge 4 ]] then + # Listing or extracting a particular file. We run `tar t...' + # on the file, keeping the list of filenames cached, plus the + # name of the tarfile so we know if it changes. + local largs=-tf + + [[ $words[2] = *z* ]] && largs=-tzf + [[ $words[2] = *Z* ]] && largs=-tZf + if [[ $tf != $tar_cache_name ]]; then + tar_cache_list=("${(@f)$($words[1] $largs $tf)}") + tar_cache_name=$tf + fi + _multi_parts / tar_cache_list +elif [[ "$tcmd" = *c*f* && $CURRENT -ge 4 ]] then _files -elif [[ -mcurrent -1 *f* && -position 2 ]]; then +elif [[ "$tcmd" = *[zZ]*f* && $CURRENT -eq 3 ]] then + _files -g '*.((tar|TAR).(gz|Z)|.tgz)' +elif [[ "$tcmd" = *f* && $CURRENT -eq 3 ]] then _files -g '*.(tar|TAR)' fi diff --git a/Completion/User/_x_options b/Completion/User/_x_options index cc469286d..3190ee377 100644 --- a/Completion/User/_x_options +++ b/Completion/User/_x_options @@ -2,4 +2,4 @@ # A simple pattern completion, just as an example. -complist -J options -k '(-display -name -xrm)' +compgen -J options -k '(-display -name -xrm)' diff --git a/Config/version.mk b/Config/version.mk index 496dea13a..be39570f4 100644 --- a/Config/version.mk +++ b/Config/version.mk @@ -27,5 +27,5 @@ # This must also serve as a shell script, so do not add spaces around the # `=' signs. -VERSION=3.1.5-pws-10 -VERSION_DATE='February 26, 1999' +VERSION=3.1.5-pws-11 +VERSION_DATE='March 3, 1999' diff --git a/Doc/Zsh/builtins.yo b/Doc/Zsh/builtins.yo index 0b2b9a4f8..ffc9f3cfe 100644 --- a/Doc/Zsh/builtins.yo +++ b/Doc/Zsh/builtins.yo @@ -924,7 +924,7 @@ both tt(typeset -xT ...) and tt(export -T ...) work, but only the scalar will be marked for export. If no var(name) is present, the names and values of all parameters are -printed. In this case the attribute flags restrict the the display to +printed. In this case the attribute flags restrict the display to only those parameters that have the specified attributes. Using `tt(PLUS())' rather than `tt(-)' to introduce the flag causes the attribute to be turned off, and suppresses printing of the names and diff --git a/Doc/Zsh/compctl.yo b/Doc/Zsh/compctl.yo index 124f9e604..4e1a98dab 100644 --- a/Doc/Zsh/compctl.yo +++ b/Doc/Zsh/compctl.yo @@ -124,9 +124,9 @@ startlist() list([ tt(-fcFBdeaRGovNAIOPZEnbjrzu/) ]) list([ tt(-k) var(array) ] [ tt(-g) var(globstring) ] \ [ tt(-s) var(subststring) ]) -list([ tt(-K) var(function) ] [ tt(-H) var(num pattern) ]) +list([ tt(-K) var(function) ] [ tt(-i) var(function) ]) list([ tt(-Q) ] [ tt(-P) var(prefix) ] [ tt(-S) var(suffix) ]) -list([ tt(-W) var(file-prefix) ]) +list([ tt(-W) var(file-prefix) ] [ tt(-H) var(num pattern) ]) list([ tt(-q) ] [ tt(-X) var(explanation) ] [ tt(-Y) var(explanation) ]) list([ tt(-y) var(func-or-var) ] [ tt(-l) var(cmd) ] [ tt(-U) ]) list([ tt(-t) var(continue) ] [ tt(-J) var(name) ] [ tt(-V) var(name) ]) @@ -280,7 +280,8 @@ completions. The tt(fignore) special parameter is not applied to the resulting files. Note that tt(-g) is faster for filenames. ) item(tt(-K) var(function))( -Call the given function to get the completions. The function is +Call the given function to get the completions. Unless the name +starts with an underscode, the function is passed two arguments: the prefix and the suffix of the word on which completion is to be attempted, in other words those characters before the cursor position, and those from the cursor position onwards. The @@ -300,6 +301,13 @@ compctl -K whoson talk)) completes only logged-on users after `tt(talk)'. Note that `tt(whoson)' must return an array, so `tt(reply=`users`)' would be incorrect. ) +item(tt(-i) var(function))( +Like tt(-K), but the function is invoked in a context like that for +completion widgets, see +ifzman(zmanref(zshzle))\ +ifnzman(noderef(The zle Module))\ +for more information. +) item(tt(-H) var(num pattern))( The possible completions are taken from the last var(num) history lines. Only words matching var(pattern) are taken. If var(num) is @@ -427,9 +435,19 @@ printed literally and if they appear output in columns is suppressed. ) item(tt(-X) var(explanation))( Print var(explanation) when trying completion on the current set of -options. A `tt(%n)' in this string is replaced by the number of matches. +options. A `tt(%n)' in this string is replaced by the number of +matches that were added for this explanation string. The explanation only appears if completion was tried and there was -no unique match, or when listing completions. +no unique match, or when listing completions. Explanation strings +will be listed together with the matches of the group specified +together with the tt(-X) option (using the tt(-J) or tt(-V) +option). If the same explanation string is given to multiple tt(-X) +options, the string appears only once (for each group) and the number +of matches shown for the `tt(%n)' is the total number of all matches +for each of these uses. In any case, the explanation string will only +be shown if there was at least one match added for the explanation +string. + The sequences tt(%B), tt(%b), tt(%S), tt(%s), tt(%U), and tt(%u) specify output attributes (bold, standout, and underline) as in prompts. ) diff --git a/Doc/Zsh/compwid.yo b/Doc/Zsh/compwid.yo index 4208317fb..44ae72002 100644 --- a/Doc/Zsh/compwid.yo +++ b/Doc/Zsh/compwid.yo @@ -54,91 +54,162 @@ widget is active, these parameters are reseton each function exit to the values they had when the function was entered. startitem() -item(tt(argv))( -The positional parameters are set to the arguments on the command line -when the widget function is invoked from the completion code. +item(tt(words))( +This array contains the words from the line. ) item(tt(CURRENT))( This is the number of the current word, i.e. the word the cursor is -currently on in the tt(argv) array. +currently on in the tt(words) array. Note that this value is only +correct, if the tt(ksharrays) options is not set. ) -item(tt(CONTEXT))( +item(tt(PREFIX))( +This should be set to that part of the current word that should be +taken as the string every possible match has to begin with. Initially +this will be set to the part of the current word from the beginning of +the word up to the position of the cursor. When +) +item(tt(IPREFIX))( +When a part of the current word should not be considered part of the +matches, this part should be taken from the tt(PREFIX) parameter and +appended to this parameter. This will initially be set to the empty +string when called from the completion code. +) +item(tt(SUFFIX))( +This should be set to that part of the current word that should be +taken as the string every possible match has to end with. The +completion code sets this to the part of the current word from the +cursor position to the end. +) +item(tt(compstate))( +This is an associative array with various keys and values the +completion uses to give informtaion to the completion widget and to +get information regarding the further processing from it. The keys +are: + +startitem() +item(tt(context))( This will be set by the completion code to the overall context completion is attempted in. Possible values are: startitem() item(tt(command))( -when completing in a command position, e.g. in the first word on the -command line -) -item(tt(argument))( -when completing an argument for a command +when completing for a normal command (in a command position or for an +argument) ) item(tt(redirect))( -when completing after a redirection operator; in this case the -positional parameters contain not only the arguments but also the -command name itself as the first element +when completing after a redirection operator ) item(tt(condition))( when completing inside a `tt([[)...tt(]])' conditional expressing; in -this case the positional parameters are set to the words inside the -conditional expressions +this case the tt(words) array contains the words inside the +conditional expression ) item(tt(math))( when completing in a mathematical environment such as a `tt(LPAR()LPAR())...tt(RPAR()RPAR())' construct ) item(tt(value))( -when completing the value of a parameter assignment; in case of an -array value the positional parameters are set to the words in -parentheses +when completing the value of a parameter assignment +) +item(tt(array_value))( +when completing inside the value of an array parameter assignment; in +this case the tt(words) array contains the words inside the parentheses ) item(tt(subscript))( -when completing inside a parameter expansion subscript +when completing inside a parameter subscript +) +item(tt(parameter))( +when the name of a parameter in a parameter expansion +) +item(tt(brace_parameter))( +when the name of a parameter in a parameter expansion that started +with tt(${) ) enditem() ) -item(tt(COMMAND))( -In most cases this is set to name of the command for which completion -is tried. When completing after a redirection operator it contains the -string forming that operator. Also, when completing in the value of a -parameter assignment or in a parameter subscript it is set to the name -of the parameter. +item(tt(parameter))( +The name of the parameter when completing in a subscript or in the +value of a parameter assignment. ) -item(tt(PREFIX))( -This should be set to that part of the current word that should be -taken as the string every possible match has to begin with. Initially -this will be set to the part of the current word from the beginning of -the word up to the position of the cursor. When +item(tt(redirect))( +The redirection operator when completing in a redirection position. ) -item(tt(IPREFIX))( -When a part of the current word should not be considered part of the -matches, this part should be taken from the tt(PREFIX) parameter and -appended to this parameter. This will initially be set to the empty -string when called from the completion code. +item(tt(quoting))( +If completion is done inside single quotes, this is set to the string +tt(single). When completing inside double quotes this is set to +tt(double). When completing inside backticks it is set to tt(backtick). +Otherwise it is unset. ) -item(tt(SUFFIX))( -This should be set to that part of the current word that should be -taken as the string every possible match has to end with. The -completion code sets this to the part of the current word from the -cursor position to the end. +item(tt(quote))( +When completing inside quotes, this contains the quotation character +(i.e. either a single quote, a double quote, or a backtick). ) -item(tt(NMATCHES))( +item(tt(nmatches))( This is always set to the number of matches generated and accepted by the completion code so far. ) -item(tt(MATCHER))( +item(tt(matcher))( When completion is used with a global match specification (i.e. a -tt(compctl) with only a tt(-M) option), this parameter is set to the +tt(compctl) with only a tt(-M) option), this contains the number of the specification string which is currently used. ) +item(tt(matcher_string))( +This is set to the global match specification string currently used. +) +item(tt(total_matchers))( +The total number of global match specifications. +) +item(tt(restore))( +This is set to tt(auto) before a function is entered. If a function +unsets it or sets it to any other string, the special parameters +mentioned above (tt(words), tt(CURRENT), tt(PREFIX), tt(IPREFIX), and +tt(SUFFIX)) will not be restored to their previous values when the +function exits as is normally done. +) +item(tt(list))( +On entry to the completion widget this will be unset, if the set of +matches generated will not be listed. It is set to tt(list), +tt(autolist), or tt(ambiguous) if the matches will always be listed, +if they will be listed due to tt(AUTO_LIST) being set, or if they will +be listed if there is no unambiguous string to insert and +tt(LIST_AMBIGUOUS) is set, respectively. Inside the completion widget +it may be set to any of these values to make the completion code as if +the appropriate options had been set. +) +item(tt(insert))( +This will be unset by the completon code if the contents of the +command line will not be changed. It is set to tt(unambiguous), +tt(menu), or tt(automenu) if a common unambiguous string will be +inserted or if the first match will be inserted and menu completion +will be started (due to tt(MENU_COMPLETE) or tt(AUTO_MENU) being set), +respectively. +) +item(tt(exact))( +This is set to tt(accept) if an exact match would be accepted by the +completion code due to tt(REC_EXACT) being set or it is unset if an +exact match would not be accepted. +) +item(tt(exact_string))( +This is set to the string of an exact match if one was found and unset +otherwise. +) +item(tt(pattern_match))( +If the option tt(GLOB_COMPLETE) is set, this is initially set to +tt(yes) and unset otherwise. If the completion widget sets it to a +non-empty string, the completion code will from then on behave as if +tt(GLOB_COMPLETE) is set, i.e.. if the strings in tt(PREFIX) and +tt(SUFFIX) contain unquoted metacharacters, they will be treated as +patterns. +) +enditem() +) enditem() texinode(Builtin Commands)(Condition Codes)(Special Parameters)(Completion Widgets) sect(Builtin Commands) startitem() -findex(complist) -item(tt(complist) var(flags ...))( +findex(compgen) +item(tt(compgen) var(flags ...))( Generate matches according to the given var(flags) which can be any of the option flags supported by the tt(compctl) builtin command (see @@ -154,9 +225,12 @@ flags. The completion code will consider only those matches as possible completions that match the prefix and suffix from the special parameters desribed above. These strings will be compared with the generated matches using the normal matching rules and any matching -specifications given with the tt(-M) flag to tt(complist) and the +specifications given with the tt(-M) flag to tt(compgen) and the global matching specifications given to the tt(compctl) builtin command. + +The return value can be used to test if matches were added. It is zero +if at least one match was added and non-zero otherwise. ) xitem(tt(compadd) [ tt(-qQfnUam) ] [ tt(-F) var(array) ]) xitem([ tt(-P) var(prefix) ] [ tt(-S) var(suffix) ]) @@ -168,13 +242,38 @@ item([ tt(-M) var(match-spec) ] [ tt(--) ] [ var(words) ... ])( This builtin command can be used to add matches and directly control all the information the completion code stores with each possible -match. +match. The return value is zero if at least one match was added and +non-zero if no matches were added. + +The completion code breaks the string to complete into six fields in +the order: + +indent( +var() +) + +The first field +is an ignored prefix taken from the line, the contents of the +tt(IPREFIX) parameter plus the string given with the tt(-i) +option. With the tt(-U) option given, only the string from the tt(-i) +option is used. The field var() is a optional prefix string that +should automatically be added by the completion code, this is what can +be gievn with the tt(-P) option. The var() field is a string +that is considered part of the match but that should not be shown when +listing completions, it is given with the tt(-p) option. E.g. for +functions that do filename generation, one might want to use this for +a common path prefix. var() is the part of the match that should +appear in the list of completions, one of the tt(words) given at the +end. The field var() is like var() but gives a suffix that +should be matched but will not be listed. Finally, var() is the +suffix given with tt(-S) that should automatically be added by the +completion code. The supported flags are: startitem() item(tt(-P) var(prefix))( -The same as for tt(compctl) and tt(complist), it gives a string that +The same as for tt(compctl) and tt(compgen), it gives a string that should be inserted before the given words when they are completed. The string given is not considered to be part of the match. ) @@ -183,7 +282,9 @@ Like tt(-P) but gives a string that has to be inserted after the match. ) item(tt(-p) var(hidden-prefix))( This gives a string that should be inserted in the line before the -match but that should not appear in the list of matches. +match but that should not appear in the list of matches. Unless the +tt(-U) option is given, the string on the line has to match this +string. ) item(tt(-s) var(hidden-suffix))( Like `tt(-p)', but gives a string to insert after the match. @@ -195,7 +296,7 @@ inserted before the string given with `tt(-p)' or directly before the match. ) item(tt(-J) var(name))( -As for tt(compctl) and tt(complist) this gives the name of the group +As for tt(compctl) and tt(compgen) this gives the name of the group of matches the words should be stored in. ) item(tt(-V) var(name))( @@ -206,7 +307,7 @@ The var(explanation) string will be printed with the list of matches, as for tt(compctl -X). ) item(tt(-q))( -This flag has the same meaning as for tt(compctl) and tt(complist), +This flag has the same meaning as for tt(compctl) and tt(compgen), too. It makes the suffix given with tt(-S) be automatically removed if the next character typed is a blank or does not insert anything or if the suffix consists of only one character and the next character typed @@ -246,7 +347,7 @@ completed. ) item(tt(-W) var(file-prefix))( This option has the same meaning as for the tt(compctl) and -tt(complist) builtin commands. Here, however, only one string may be +tt(compgen) builtin commands. Here, however, only one string may be given, not an array. This string is used as a pathname that will be prepended to the given words and the prefix given with the tt(-p) option to perform the file-tests when showing completion @@ -254,7 +355,7 @@ listings. Hence it is only useful if combined with the tt(-f) flag, since the tests will only be performed if that flag is given. ) item(tt(-a))( -When used by tt(compctl) or tt(complist) the completion code normally +When used by tt(compctl) or tt(compgen) the completion code normally builds two sets of matches: the normal one where words with one of the suffixes in the array parameter tt(fignore) are not considered possible matches, and the alternate set where the words excluded @@ -279,22 +380,13 @@ the name of an array is given, the elements of the array are taken as the suffixes. ) item(tt(-Q))( -As for tt(compctl) and tt(complist) this flag instructs the completion +As for tt(compctl) and tt(compgen) this flag instructs the completion code not to quote any metacharacters in the words when inserting them in the command line. ) -item(tt(-m))( -Normally the matches added by tt(compadd) will not be compared with -what is already on the line. If this flag is given, this comparison is -performed as usual and the match specifications given with the tt(-M) -option to tt(compadd) and the global match specifications defined with -tt(compctl) will be used. This means that probably not all the word -given will be stored as matches since some of them may not match the -string on the line. -) item(tt(-M) var(match-spec))( This option allows one to give local match specifications with the -same meaning and format as for the tt(compctl) and tt(complist) +same meaning and format as for the tt(compctl) and tt(compgen) builtin commands. Note that they will only be used if the tt(-m) is given, too. ) @@ -303,9 +395,13 @@ Words added with tt(compadd) with this flag will be used as possible matches as usual but they not appear in the completion listing. ) item(tt(-U))( -If this flag is given to one of the calls to tt(compadd) and the -option tt(AUTO_MENU) is set, the completion code will immediatly -switch to menucompletion. +If this flag is given, all words given will be accepted, no matching +will be done by the completion code. Normally this is used in +functions that do the matching themselves. + +Note that with tt(compadd) this option does not automatically turn on +menu completion if tt(AUTO_LIST) is set as the same options for the +tt(compctl) and tt(compgen) builtin command do. ) item(tt(-), tt(--))( This flag ends the list of flags and options. All arguments after it @@ -317,7 +413,7 @@ enditem() item(tt(compcall) [ tt(-TD) ])( This allows one to use completion definitions given with the -tt(compctl) builtin from within completion widgets. It makes +tt(compctl) builtin from within completion widgets. It makes the completion code complete the current word according to the tt(compctl)s defined. Normally only tt(compctl)s given for specific commands are used. To make the code use the completion flags given to @@ -325,6 +421,10 @@ the tt(-T) option of tt(compctl), one can give the tt(-T) flag to tt(compctl). Likewise, the tt(-D) flag to tt(compcall) makes the default completion flags given to tt(compctl) with the tt(-D) option be used. + +The return value can be used to test if a matching tt(compctl) +definition was found. It is non-zero if a tt(compctl) was found and +zero otherwise. ) enditem() @@ -352,12 +452,14 @@ item(tt(-position) var(beg) [ var(end) ])( true if tt(CURRENT) is equal to var(beg) or, if var(end) is given, equal to or greater than var(beg) and equal to or less than var(end); both of var(beg) and var(end) may be arithmetic expressions, if they -are less than zero the number of words in tt(argv) are added to them +are less than zero the number of words in tt(words) are added to them before comparing them to tt(CURRENT); thus, tt(-1) is the last word, -tt(-2) is the word before that and so on +tt(-2) is the word before that and so on; note that positions are +taken as indexes into the tt(words) array and thus are counted as if +the tt(ksharray) is not set ) item(tt(-word) var(index) var(string))( -true if the word number var(index) in tt(argv) is equal to +true if the word number var(index) in tt(words) is equal to var(string); again, var(index) may be negative, counting backwards ) item(tt(-mword) var(index) var(pattern))( @@ -375,7 +477,7 @@ true if the current word contains var(string); anything up to the last occurrence of this string will be ingnored by removing it from tt(PREFIX) and adding it to tt(IPREFIX); if var(number) is given, anything up to the var(number)'th occurrence of the var(string) will -be ignored; again, var(nmuber) may be any arithmetic expression and +be ignored; again, var(number) may be any arithmetic expression and negative values count backward ) item(tt(-class) [ var(number) ] var(class))( @@ -391,7 +493,7 @@ var(min) and equal to or less than var(max) item(tt(-after) var(string))( true if the cursor is after a word that is equal to var(string); this removes all words up to and including the matched word from the -positional parameters +tt(words) array ) item(tt(-mafter) var(pattern))( like tt(-after) but using pattern matching @@ -401,16 +503,16 @@ true if the cursor is after a word that is equal to var(string1), if there is also a word that is equal to var(string2), this is true only if the cursor is before it; as a side effect, all words before var(string1) and after var(string2) (both inclusive) are removed from -the positional parameters +the tt(words) array ) item(tt(-mbetween) var(pattern1) var(pattern2))( like tt(-between) but using pattern matching ) item(tt(-nmatches) var(number))( -true if the the value of tt(NMATCHES) is equal to var(number) +true if the the value of tt(compstate[nmatches]) is equal to var(number) ) item(tt(-matcher) var(number))( -true if the value of tt(MATCHER) is equal to var(number) +true if the value of tt(compstate[matcher]) is equal to var(number) ) enditem() @@ -433,7 +535,7 @@ after typing control-X and TAB. The function should then generte the matches, e.g.: indent(nofill( -tt(complete-history LPAR()RPAR() { complist -H 0 '' }))) +tt(complete-history LPAR()RPAR() { compgen -H 0 '' }))) In this the function will complete words from the history matching the current word. diff --git a/Doc/Zsh/expn.yo b/Doc/Zsh/expn.yo index fa56bc0af..4fd64981f 100644 --- a/Doc/Zsh/expn.yo +++ b/Doc/Zsh/expn.yo @@ -227,7 +227,7 @@ Note the same record of the last var(l) and var(r) is maintained across all forms of expansion. By default, a history reference with no event specification refers to the same -line as the last history reference on that command line, unless it is the +line as the previous history reference on that command line, unless it is the first history reference in a command. In that case, a history reference with no event specification always refers to the previous command. However, if the option tt(CSH_JUNKIE_HISTORY) is set, diff --git a/Doc/Zsh/params.yo b/Doc/Zsh/params.yo index 41dd91510..bfb2238ed 100644 --- a/Doc/Zsh/params.yo +++ b/Doc/Zsh/params.yo @@ -155,6 +155,11 @@ if combined with `tt(r)', `tt(R)', `tt(i)' or `tt(I)', makes them give the var(n)th or var(n)th last match (if var(expr) evaluates to var(n)). This flag is ignored when the array is associative. ) +item(tt(b:)var(expr)tt(:))( +if combined with `tt(r)', `tt(R)', `tt(i)' or `tt(I)', makes them begin +at the var(n)th or var(n)th last element, word, or character (if var(expr) +evaluates to var(n)). This flag is ignored when the array is associative. +) enditem() texinode(Positional Parameters)(Local Parameters)(Array Parameters)(Parameters) sect(Positional Parameters) diff --git a/Doc/Zsh/zle.yo b/Doc/Zsh/zle.yo index c372c58eb..439caa2f8 100644 --- a/Doc/Zsh/zle.yo +++ b/Doc/Zsh/zle.yo @@ -154,6 +154,10 @@ key. Control-keys are reported with a leading `tt(^)', as in `tt(^A)', and meta-keys are repoted with a leading `tt(M-)', as in `tt(M-a)' and `tt(M-^A)'. ) +vindex(NUMERIC) +item(tt(NUMERIC) (integer))( +The numeric argument. +) enditem() sect(Standard Widgets) cindex(widgets, standard) diff --git a/INSTALL b/INSTALL index 1ed6847e3..f8200feff 100644 --- a/INSTALL +++ b/INSTALL @@ -56,10 +56,11 @@ Controlling what is compiled into the main zsh binary By default the comp1, compctl, zle, sched and rlimits modules are compiled into non-dynamic zsh and no modules are compiled into the main binary if -dynamic loading is available. This can be overridden by creating the -Src/modules-bltin file with the list of modules which are to be compiled -into the main binary. See the zshmodules manual page for the list of -available modules. +dynamic loading is available. This can be overridden by creating the file +mymods.conf in the compilation directory (Src, unless you have told +configure to use another directory) with the list of modules which are to +be compiled into the main binary. See the zshmodules manual page for the +list of available modules. Compiler Options or Using a Different Compiler ---------------------------------------------- diff --git a/Src/Makefile.in b/Src/Makefile.in index 1b5256e16..0babdf47b 100644 --- a/Src/Makefile.in +++ b/Src/Makefile.in @@ -112,8 +112,10 @@ FORCE: # ========== LINKING IN MODULES ========== -modules-bltin: - if test @D@ = N; then \ +modules-bltin: Makefile + if test -f mymods.conf; then \ + cat mymods.conf > $@; \ + elif test @D@ = N; then \ cat $(sdir)/xmods.conf > $@; \ elif test @RTLD_GLOBAL_OK@ != yes; then \ echo comp1 > $@; \ @@ -175,18 +177,21 @@ uninstall.bin-L: # ========== DEPENDENCIES FOR CLEANUP ========== -@@clean.mk@@ +# Since module cleanup rules depend on Makemod, they come first. This +# forces module stuff to get cleaned before Makemod itself gets +# deleted. mostlyclean-here: rm -f stamp-modobjs stamp-modobjs.tmp clean-here: rm -f modules.index.tmp modules.stamp zsh ansi2knr.o ansi2knr + rm -f modules.index modules-bltin rm -f libzsh-*.$(DL_EXT) distclean-here: rm -f TAGS tags - rm -f modules.index modules-bltin Makefile + rm -f Makefile mymods.conf mostlyclean: mostlyclean-modules clean: clean-modules @@ -196,6 +201,8 @@ realclean: realclean-modules mostlyclean-modules clean-modules distclean-modules realclean-modules: Makemod @$(MAKE) -f Makemod $(MAKEDEFS) `echo $@ | sed 's/-modules//'` +@@clean.mk@@ + # ========== RECURSIVE MAKES ========== install.modules uninstall.modules \ diff --git a/Src/Zle/comp.h b/Src/Zle/comp.h index 76ac67114..d7f3610f1 100644 --- a/Src/Zle/comp.h +++ b/Src/Zle/comp.h @@ -103,6 +103,7 @@ struct compctl { char *glob; /* for -g (globbing) */ char *str; /* for -s (expansion) */ char *func; /* for -K (function) */ + char *widget; /* for -i (function) */ char *explain; /* for -X (explanation) */ char *ylist; /* for -y (user-defined desc. for listing) */ char *prefix, *suffix; /* for -P and -S (prefix, suffix) */ @@ -284,7 +285,37 @@ struct cline { /* Flags for compadd and addmatches(). */ #define CAF_QUOTE 1 -#define CAF_MENU 2 -#define CAF_NOSORT 4 -#define CAF_ALT 8 -#define CAF_MATCH 16 +#define CAF_NOSORT 2 +#define CAF_ALT 4 +#define CAF_MATCH 8 + +/* Flags for special parameters. */ + +#define CP_WORDS (1 << 0) +#define CP_CURRENT (1 << 1) +#define CP_PREFIX (1 << 2) +#define CP_SUFFIX (1 << 3) +#define CP_IPREFIX (1 << 4) +#define CP_COMPSTATE (1 << 5) + +#define CP_REALPARAMS 6 + +#define CP_NMATCHES (1 << 6) +#define CP_MATCHER (1 << 7) +#define CP_MATCHERSTR (1 << 8) +#define CP_MATCHERTOT (1 << 9) +#define CP_CONTEXT (1 << 10) +#define CP_PARAMETER (1 << 11) +#define CP_REDIRECT (1 << 12) +#define CP_QUOTE (1 << 13) +#define CP_QUOTING (1 << 14) +#define CP_RESTORE (1 << 15) +#define CP_LIST (1 << 16) +#define CP_INSERT (1 << 17) +#define CP_EXACT (1 << 18) +#define CP_EXACTSTR (1 << 19) +#define CP_PATMATCH (1 << 20) + +#define CP_NUM 21 + +#define CP_ALLMASK ((1 << CP_NUM) - 1) diff --git a/Src/Zle/comp1.c b/Src/Zle/comp1.c index 72f3cea53..ccccf5a34 100644 --- a/Src/Zle/comp1.c +++ b/Src/Zle/comp1.c @@ -46,10 +46,13 @@ Cmlist cmatcher; /**/ void (*makecompparamsptr) _((void)); +/**/ +void (*comp_setunsetptr) _((int, int)); + /* pointers to functions required by compctl and defined by zle */ /**/ -void (*addmatchesptr) _((char *, char *, char *, char *, char *, char *, char *, char *, char *, char *, int, int, Cmatcher, char *, char **)); +int (*addmatchesptr) _((char *, char *, char *, char *, char *, char *, char *, char *, char *, char *, int, int, Cmatcher, char *, char **)); /**/ char *(*comp_strptr) _((int*, int*, int)); @@ -58,7 +61,7 @@ char *(*comp_strptr) _((int*, int*, int)); int (*getcpatptr) _((char *, int, char *, int)); /**/ -void (*makecomplistcallptr) _((Compctl)); +int (*makecomplistcallptr) _((Compctl)); /**/ int (*makecomplistctlptr) _((int)); @@ -96,14 +99,29 @@ int incompfunc; /**/ long compcurrent, compnmatches, - compmatcher; + compmatcher, + compmatchertot; /**/ -char *compcontext, - *compcommand, +char **compwords, *compprefix, *compsuffix, - *compiprefix; + *compiprefix, + *compmatcherstr, + *compcontext, + *compparameter, + *compredirect, + *compquote, + *compquoting, + *comprestore, + *complist, + *compinsert, + *compexact, + *compexactstr, + *comppatmatch; + +/**/ +Param *comppms; /* The function rembslash() came from zle_tricky.c, but is now used * * in compctl.c, too. */ @@ -154,6 +172,7 @@ freecompctl(Compctl cc) zsfree(cc->glob); zsfree(cc->str); zsfree(cc->func); + zsfree(cc->widget); zsfree(cc->explain); zsfree(cc->ylist); zsfree(cc->prefix); @@ -408,9 +427,14 @@ setup_comp1(Module m) cc_first.refc = 10000; cc_first.mask = 0; cc_first.mask2 = CC_CCCONT; - compcontext = compcommand = compprefix = compsuffix = - compiprefix = NULL; + comppms = NULL; + compwords = NULL; + compprefix = compsuffix = compiprefix = compmatcherstr = + compcontext = compparameter = compredirect = compquote = + compquoting = comprestore = complist = compinsert = + compexact = compexactstr = comppatmatch = NULL; makecompparamsptr = NULL; + comp_setunsetptr = NULL; return 0; } @@ -437,11 +461,22 @@ finish_comp1(Module m) deletehashtable(compctltab); zfree(clwords, clwsize * sizeof(char *)); compctlreadptr = fallback_compctlread; - zsfree(compcontext); - zsfree(compcommand); + freearray(compwords); zsfree(compprefix); - zsfree(compiprefix); zsfree(compsuffix); + zsfree(compiprefix); + zsfree(compmatcherstr); + zsfree(compcontext); + zsfree(compparameter); + zsfree(compredirect); + zsfree(compquote); + zsfree(compquoting); + zsfree(comprestore); + zsfree(complist); + zsfree(compinsert); + zsfree(compexact); + zsfree(compexactstr); + zsfree(comppatmatch); return 0; } diff --git a/Src/Zle/comp1.export b/Src/Zle/comp1.export index 278006b6a..35b63e7d3 100644 --- a/Src/Zle/comp1.export +++ b/Src/Zle/comp1.export @@ -13,12 +13,27 @@ compcommand compcontext compctltab compcurrent +compexact +compexactstr +compinsert compiprefix +complist compmatcher +compmatcherstr +compmatchertot compnmatches +compparameter +comppatmatch +comppms compprefix +compredirect +compquote +compquoting +comprestore +comp_setunsetptr comp_strptr compsuffix +compwords freecmatcher freecmlist freecompcond diff --git a/Src/Zle/compctl.c b/Src/Zle/compctl.c index f71d67510..b5c8e4b3f 100644 --- a/Src/Zle/compctl.c +++ b/Src/Zle/compctl.c @@ -140,7 +140,7 @@ get_gmatcher(char *name, char **argv) while (*argv) { if ((m = parse_cmatcher(name, *argv)) == pcm_err) return 2; - *q = n = (Cmlist) halloc(sizeof(struct cmlist)); + *q = n = (Cmlist) zhalloc(sizeof(struct cmlist)); n->next = NULL; n->matcher = m; n->str = *argv++; @@ -578,6 +578,19 @@ get_compctl(char *name, char ***av, Compctl cc, int first, int isdef, int cl) *argv = "" - 1; } break; + case 'i': + if ((*argv)[1]) { + cct.widget = (*argv) + 1; + *argv = "" - 1; + } else if (!argv[1]) { + zwarnnam(name, "function name expected after -%c", NULL, + **argv); + return 1; + } else { + cct.widget = *++argv; + *argv = "" - 1; + } + break; case 'Y': cct.mask |= CC_EXPANDEXPL; goto expl; @@ -1197,6 +1210,7 @@ cc_assign(char *name, Compctl *ccptr, Compctl cct, int reass) zsfree(cc->glob); zsfree(cc->str); zsfree(cc->func); + zsfree(cc->widget); zsfree(cc->explain); zsfree(cc->ylist); zsfree(cc->prefix); @@ -1217,6 +1231,7 @@ cc_assign(char *name, Compctl *ccptr, Compctl cct, int reass) cc->glob = ztrdup(cct->glob); cc->str = ztrdup(cct->str); cc->func = ztrdup(cct->func); + cc->widget = ztrdup(cct->widget); cc->explain = ztrdup(cct->explain); cc->ylist = ztrdup(cct->ylist); cc->prefix = ztrdup(cct->prefix); @@ -1423,6 +1438,7 @@ printcompctl(char *s, Compctl cc, int printflags, int ispat) printif(cc->gname, 'J'); printif(cc->keyvar, 'k'); printif(cc->func, 'K'); + printif(cc->widget, 'i'); printif(cc->explain, (cc->mask & CC_EXPANDEXPL) ? 'Y' : 'X'); printif(cc->ylist, 'y'); printif(cc->prefix, 'P'); @@ -1644,7 +1660,7 @@ bin_compctl(char *name, char **argv, char *ops, int func) /**/ static int -bin_complist(char *name, char **argv, char *ops, int func) +bin_compgen(char *name, char **argv, char *ops, int func) { Compctl cc; int ret = 0; @@ -1663,7 +1679,7 @@ bin_complist(char *name, char **argv, char *ops, int func) zerrnam(name, "command names illegal", NULL, 0); ret = 1; } else - makecomplistcallptr(cc); + ret = makecomplistcallptr(cc); freecompctl(cc); return ret; @@ -1677,7 +1693,7 @@ bin_compadd(char *name, char **argv, char *ops, int func) char *ipre = NULL, *ppre = NULL, *psuf = NULL, *prpre = NULL; char *pre = NULL, *suf = NULL, *group = NULL, *m = NULL, *rs = NULL; char *ign = NULL, *rf = NULL, *expl = NULL; - int f = 0, a = 0, dm; + int f = 0, a = CAF_MATCH, dm; Cmatcher match = NULL; if (incompfunc != 1) { @@ -1710,7 +1726,7 @@ bin_compadd(char *name, char **argv, char *ops, int func) f |= CMF_NOLIST; break; case 'U': - a |= CAF_MENU; + a &= ~CAF_MATCH; break; case 'P': sp = ⪯ @@ -1749,9 +1765,6 @@ bin_compadd(char *name, char **argv, char *ops, int func) case 'a': a |= CAF_ALT; break; - case 'm': - a |= CAF_MATCH; - break; case 'M': sp = &m; e = "matching specification expected after -%c"; @@ -1805,11 +1818,11 @@ bin_compadd(char *name, char **argv, char *ops, int func) return 1; match = cpcmatcher(match); - addmatchesptr(ipre, ppre, psuf, prpre, pre, suf, group, - rs, rf, ign, f, a, match, expl, argv); + a = addmatchesptr(ipre, ppre, psuf, prpre, pre, suf, group, + rs, rf, ign, f, a, match, expl, argv); freecmatcher(match); - return 0; + return a; } /**/ @@ -1824,34 +1837,54 @@ bin_compcall(char *name, char **argv, char *ops, int func) (ops['D'] ? 0 : CFN_DEFAULT)); } +/* Definitions for the special parameters. Note that these have to match the + * order of the CP_* bits in comp.h */ + #define VAR(X) ((void *) (&(X))) static struct compparam { char *name; int type; void *var; } compparams[] = { + { "words", PM_ARRAY, VAR(compwords) }, { "CURRENT", PM_INTEGER, VAR(compcurrent) }, - { "CONTEXT", PM_SCALAR, VAR(compcontext) }, - { "COMMAND", PM_SCALAR, VAR(compcommand) }, { "PREFIX", PM_SCALAR, VAR(compprefix) }, { "SUFFIX", PM_SCALAR, VAR(compsuffix) }, { "IPREFIX", PM_SCALAR, VAR(compiprefix) }, - { "NMATCHES", PM_INTEGER, VAR(compnmatches) }, - { "MATCHER", PM_INTEGER, VAR(compmatcher) }, + { NULL, 0, NULL }, + + { "nmatches", PM_INTEGER, VAR(compnmatches) }, + { "matcher", PM_INTEGER, VAR(compmatcher) }, + { "matcher_string", PM_SCALAR, VAR(compmatcherstr) }, + { "total_matchers", PM_INTEGER, VAR(compmatchertot) }, + { "context", PM_SCALAR, VAR(compcontext) }, + { "parameter", PM_SCALAR, VAR(compparameter) }, + { "redirect", PM_SCALAR, VAR(compredirect) }, + { "quote", PM_SCALAR, VAR(compquote) }, + { "quoting", PM_SCALAR, VAR(compquoting) }, + { "restore", PM_SCALAR, VAR(comprestore) }, + { "list", PM_SCALAR, VAR(complist) }, + { "insert", PM_SCALAR, VAR(compinsert) }, + { "exact", PM_SCALAR, VAR(compexact) }, + { "exact_string", PM_SCALAR, VAR(compexactstr) }, + { "pattern_match", PM_SCALAR, VAR(comppatmatch) }, { NULL, 0, NULL } }; -/**/ -void makecompparams(void) +#define COMPSTATENAME "compstate" + +static struct compparam * +addcompparams(struct compparam *cp) { - struct compparam *cp; + Param *pp = comppms + (cp - compparams); - for (cp = compparams; cp->name; cp++) { + for (; cp->name; cp++, pp++) { Param pm = createparam(cp->name, cp->type | PM_SPECIAL|PM_REMOVABLE); if (!pm) pm = (Param) paramtab->getnode(paramtab, cp->name); - DPUTS(!pm, "param not set in makecompparams"); + DPUTS(!pm, "param not set in addcompparams"); + *pp = pm; pm->level = locallevel; pm->u.data = cp->var; switch(PM_TYPE(cp->type)) { @@ -1862,18 +1895,115 @@ void makecompparams(void) case PM_INTEGER: pm->sets.ifn = intvarsetfn; pm->gets.ifn = intvargetfn; + pm->ct = 10; + break; + case PM_ARRAY: + pm->sets.afn = arrvarsetfn; + pm->gets.afn = arrvargetfn; break; } pm->unsetfn = compunsetfn; } + return cp; +} + +/**/ +void +makecompparams(void) +{ + struct compparam *cp; + Param cpm; + HashTable tht; + + cp = addcompparams(compparams); + + if (!(cpm = createparam(COMPSTATENAME, PM_SPECIAL|PM_REMOVABLE|PM_HASHED))) + cpm = (Param) paramtab->getnode(paramtab, COMPSTATENAME); + DPUTS(!cpm, "param not set in makecompparams"); + + comppms[cp - compparams] = cpm; + tht = paramtab; + cpm->level = locallevel; + cpm->gets.hfn = get_compstate; + cpm->sets.hfn = set_compstate; + cpm->unsetfn = compunsetfn; + cpm->u.hash = paramtab = newparamtable(17, COMPSTATENAME); + addcompparams(cp + 1); + paramtab = tht; +} + +/**/ +static HashTable +get_compstate(Param pm) +{ + return pm->u.hash; +} + +/**/ +static void +set_compstate(Param pm, HashTable ht) +{ + struct compparam *cp; + Param *pp; + HashNode hn; + int i; + struct value v; + char *str; + + for (i = 0; i < ht->hsize; i++) + for (hn = ht->nodes[i]; hn; hn = hn->next) + for (cp = compparams + CP_REALPARAMS, + pp = comppms + CP_REALPARAMS; cp->name; cp++, pp++) + if (!strcmp(hn->nam, cp->name)) { + v.isarr = v.inv = v.a = 0; + v.b = -1; + v.arr = NULL; + v.pm = (Param) hn; + if (cp->type == PM_INTEGER) + *((long *) cp->var) = getintvalue(&v); + else if ((str = getstrvalue(&v))) { + zsfree(*((char **) cp->var)); + *((char **) cp->var) = ztrdup(str); + } + (*pp)->flags &= ~PM_UNSET; + + break; + } } /**/ static void compunsetfn(Param pm, int exp) { - if (exp) - stdunsetfn(pm, exp); + if (exp) { + if (PM_TYPE(pm->flags) == PM_SCALAR) { + zsfree(*((char **) pm->u.data)); + *((char **) pm->u.data) = ztrdup(""); + } else if (PM_TYPE(pm->flags) == PM_ARRAY) { + freearray(*((char ***) pm->u.data)); + *((char ***) pm->u.data) = zcalloc(sizeof(char *)); + } + pm->flags |= PM_UNSET; + } +} + +/**/ +void +comp_setunset(int set, int unset) +{ + Param *p; + + if (!comppms) + return; + + set &= CP_ALLMASK; + unset &= CP_ALLMASK; + for (p = comppms; set || unset; set >>= 1, unset >>= 1, p++) { + if (set & 1) + (*p)->flags &= ~PM_UNSET; + if (unset & 1) + (*p)->flags |= PM_UNSET; + } } /**/ @@ -1883,29 +2013,51 @@ comp_wrapper(List list, FuncWrap w, char *name) if (incompfunc != 1) return 1; else { - char *octxt, *ocmd, *opre, *osuf, *oipre; + char *orest, *opre, *osuf, *oipre, **owords; long ocur; - + int unset = 0, m, sm; + Param *pp; + + m = CP_WORDS | CP_CURRENT | CP_PREFIX | CP_SUFFIX | + CP_IPREFIX | CP_RESTORE; + for (pp = comppms, sm = 1; m; pp++, m >>= 1, sm <<= 1) { + if ((m & 1) && ((*pp)->flags & PM_UNSET)) + unset |= sm; + } + orest = comprestore; + comprestore = ztrdup("auto"); ocur = compcurrent; - octxt = dupstring(compcontext); - ocmd = dupstring(compcommand); opre = dupstring(compprefix); osuf = dupstring(compsuffix); oipre = dupstring(compiprefix); + HEAPALLOC { + owords = arrdup(compwords); + } LASTALLOC; + runshfunc(list, w, name); - compcurrent = ocur; - zsfree(compcontext); - compcontext = ztrdup(octxt); - zsfree(compcommand); - compcommand = ztrdup(ocmd); - zsfree(compprefix); - compprefix = ztrdup(opre); - zsfree(compsuffix); - compsuffix = ztrdup(osuf); - zsfree(compiprefix); - compiprefix = ztrdup(oipre); + if (comprestore && !strcmp(comprestore, "auto")) { + compcurrent = ocur; + zsfree(compprefix); + compprefix = ztrdup(opre); + zsfree(compsuffix); + compsuffix = ztrdup(osuf); + zsfree(compiprefix); + compiprefix = ztrdup(oipre); + freearray(compwords); + PERMALLOC { + compwords = arrdup(owords); + } LASTALLOC; + comp_setunset(CP_COMPSTATE | + (~unset & (CP_WORDS | CP_CURRENT | CP_PREFIX | + CP_SUFFIX | CP_IPREFIX | CP_RESTORE)), + unset); + } else + comp_setunset(CP_COMPSTATE | (~unset & CP_RESTORE), + (unset & CP_RESTORE)); + zsfree(comprestore); + comprestore = orest; return 0; } @@ -1942,20 +2094,14 @@ comp_check(void) static void restrict_range(int b, int e) { - int i = e - b; + int i = e - b + 1; char **p = (char **) zcalloc((i + 1) * sizeof(char *)), **q, **pp; - for (q = p, pp = pparams + b + 1; i; i--, q++, pp++) + for (q = p, pp = compwords + b; i; i--, q++, pp++) *q = ztrdup(*pp); - zsfree(compcommand); - compcommand = ztrdup(pparams[b]); - freearray(pparams); - pparams = p; - zsfree(compcontext); - if ((compcurrent -= b + 1)) - compcontext = ztrdup("argument"); - else - compcontext = ztrdup("command"); + freearray(compwords); + compwords = p; + compcurrent -= b; } /**/ @@ -1988,7 +2134,7 @@ cond_position(char **a, int id) { if (comp_check()) { int b = cond_val(a, 0), e = (a[1] ? cond_val(a, 1) : b); - int l = arrlen(pparams), t, i = compcurrent - 1; + int l = arrlen(compwords), t, i = compcurrent - 1; if (b > 0) b--; @@ -2018,7 +2164,7 @@ cond_word(char **a, int id) { if (comp_check()) { int o = ((id & 2) ? compcurrent : 0) + cond_val(a, 0); - int l = arrlen(pparams); + int l = arrlen(compwords); char *s; if (o < 0) @@ -2028,7 +2174,7 @@ cond_word(char **a, int id) if (o < 0 || o >= l) return 0; - s = pparams[o]; + s = compwords[o]; return ((id & 1) ? cond_match(a, 1, s) : !strcmp(s, cond_str(a, 1))); } return 0; @@ -2068,7 +2214,7 @@ cond_words(char **a, int id) { if (comp_check()) { int b = cond_val(a, 0), e = (a[1] ? cond_val(a, 1) : -1); - int l = arrlen(pparams); + int l = arrlen(compwords); return (l >= b && l <= e); } @@ -2081,7 +2227,7 @@ cond_range(char **a, int id) { if (comp_check()) { char *s, **p; - int i, l = arrlen(pparams), t = 0, b = 0, e = l - 1; + int i, l = arrlen(compwords), t = 0, b = 0, e = l - 1; Comp c; i = compcurrent - 1; @@ -2095,7 +2241,7 @@ cond_range(char **a, int id) } else s = cond_str(a, 0); - for (i--, p = pparams + i; i >= 0; p--, i--) { + for (i--, p = compwords + i; i >= 0; p--, i--) { if (((id & 1) ? domatch(*p, c, 0) : !strcmp(*p, s))) { b = i + 1; t = 1; @@ -2112,7 +2258,7 @@ cond_range(char **a, int id) } else s = cond_str(a, 1); - for (i++, p = pparams + i; i < l; p++, i++) { + for (i++, p = compwords + i; i < l; p++, i++) { if (((id & 1) ? domatch(*p, c, 0) : !strcmp(*p, s))) { e = i - 1; tt = 1; @@ -2151,7 +2297,7 @@ cond_matcher(char **a, int id) static struct builtin bintab[] = { BUILTIN("compctl", 0, bin_compctl, 0, -1, 0, NULL, NULL), - BUILTIN("complist", 0, bin_complist, 1, -1, 0, NULL, NULL), + BUILTIN("compgen", 0, bin_compgen, 1, -1, 0, NULL, NULL), BUILTIN("compadd", 0, bin_compadd, 0, -1, 0, NULL, NULL), BUILTIN("compcall", 0, bin_compcall, 0, 0, 0, "TD", NULL), }; @@ -2185,6 +2331,7 @@ setup_compctl(Module m) { compctltab->printnode = printcompctlp; makecompparamsptr = makecompparams; + comp_setunsetptr = comp_setunset; return 0; } @@ -2217,6 +2364,7 @@ finish_compctl(Module m) { compctltab->printnode = NULL; makecompparamsptr = NULL; + comp_setunsetptr = NULL; return 0; } diff --git a/Src/Zle/zle_hist.c b/Src/Zle/zle_hist.c index a4b3866e5..2def5f03a 100644 --- a/Src/Zle/zle_hist.c +++ b/Src/Zle/zle_hist.c @@ -653,7 +653,7 @@ get_isrch_spot(int num, int *hlp, int *posp, int *csp, int *lenp, int *dirp, int static void doisearch(int dir) { - char *s, *ibuf = halloc(80), *sbuf = ibuf + FIRST_SEARCH_CHAR; + char *s, *ibuf = zhalloc(80), *sbuf = ibuf + FIRST_SEARCH_CHAR; int sbptr = 0, top_spot = 0, pos, sibuf = 80; int nomatch = 0, skip_line = 0, skip_pos = 0; int odir = dir, sens = zmult == 1 ? 3 : 1; @@ -936,7 +936,7 @@ static int visrchsense; static int getvisrchstr(void) { - char *sbuf = halloc(80); + char *sbuf = zhalloc(80); int sptr = 1, ret = 0, ssbuf = 80; Thingy cmd; char *okeymap = curkeymapname; @@ -1001,7 +1001,7 @@ getvisrchstr(void) } ins: if(sptr == ssbuf - 1) { - char *newbuf = halloc(ssbuf *= 2); + char *newbuf = zhalloc(ssbuf *= 2); strcpy(newbuf, sbuf); statusline = sbuf = newbuf; } diff --git a/Src/Zle/zle_main.c b/Src/Zle/zle_main.c index 277d154a6..97d012f7b 100644 --- a/Src/Zle/zle_main.c +++ b/Src/Zle/zle_main.c @@ -154,10 +154,14 @@ zsetterm(void) # ifdef OXTABS ti.tio.c_oflag &= ~OXTABS; # else +# ifdef XTABS ti.tio.c_oflag &= ~XTABS; +# endif # endif # endif +#ifdef ONLCR ti.tio.c_oflag |= ONLCR; +#endif ti.tio.c_cc[VQUIT] = # ifdef VDISCARD ti.tio.c_cc[VDISCARD] = diff --git a/Src/Zle/zle_misc.c b/Src/Zle/zle_misc.c index ea8874010..1c25cd7eb 100644 --- a/Src/Zle/zle_misc.c +++ b/Src/Zle/zle_misc.c @@ -567,7 +567,7 @@ makequote(char *str, size_t *len) if (*l == '\'') qtct++; *len += 2 + qtct*3; - l = ol = (char *)halloc(*len); + l = ol = (char *)zhalloc(*len); *l++ = '\''; for (; str < end; str++) if (*str == '\'') { @@ -613,7 +613,7 @@ executenamedcommand(char *prmt) char *okeymap = curkeymapname; clearlist = 1; - cmdbuf = halloc(l + NAMLEN + 2); + cmdbuf = zhalloc(l + NAMLEN + 2); strcpy(cmdbuf, prmt); statusline = cmdbuf; selectkeymap("main", 1); @@ -794,7 +794,7 @@ makeparamsuffix(int br, int n) if(br) { suffixlen['#'] = suffixlen['%'] = suffixlen['?'] = n; suffixlen['-'] = suffixlen['+'] = suffixlen['='] = n; - /*{*/ suffixlen['}'] = n; + /*{*/ suffixlen['}'] = suffixlen['/'] = n; } } diff --git a/Src/Zle/zle_params.c b/Src/Zle/zle_params.c index 7e15d3d8b..2a35ac416 100644 --- a/Src/Zle/zle_params.c +++ b/Src/Zle/zle_params.c @@ -67,6 +67,8 @@ static struct zleparam { zleunsetfn, NULL }, { "keys", PM_ARRAY | PM_READONLY, NULL, FN(get_keys), zleunsetfn, NULL }, + { "NUMERIC", PM_INTEGER | PM_READONLY, FN(set_numeric), FN(get_numeric), + zleunsetfn, NULL }, { NULL, 0, NULL, NULL, NULL, NULL } }; @@ -97,6 +99,7 @@ makezleparams(int ro) case PM_INTEGER: pm->sets.ifn = (void (*) _((Param, long))) zp->setfn; pm->gets.ifn = (long (*) _((Param))) zp->getfn; + pm->ct = 10; break; } pm->unsetfn = zp->unsetfn; @@ -225,9 +228,9 @@ get_keys(Param pm) { char **r, **q, *p, *k, c; - r = (char **) halloc((strlen(keybuf) + 1) * sizeof(char *)); + r = (char **) zhalloc((strlen(keybuf) + 1) * sizeof(char *)); for (q = r, p = keybuf; (c = *p); q++, p++) { - k = *q = (char *) halloc(5); + k = *q = (char *) zhalloc(5); if (c & 0x80) { *k++ = 'M'; *k++ = '-'; @@ -244,3 +247,17 @@ get_keys(Param pm) return r; } + +/**/ +static void +set_numeric(Param pm, long x) +{ + zmult = x; +} + +/**/ +static long +get_numeric(Param pm) +{ + return zmult; +} diff --git a/Src/Zle/zle_refresh.c b/Src/Zle/zle_refresh.c index 9e07676e8..b9f39b70b 100644 --- a/Src/Zle/zle_refresh.c +++ b/Src/Zle/zle_refresh.c @@ -266,7 +266,11 @@ zrefresh(void) /* Nov 96: I haven't checked how complete this is. sgtty stuff may or may not work */ +#if defined(SGTABTYPE) oxtabs = ((SGTTYFLAG & SGTABTYPE) == SGTABTYPE); +#else + oxtabs = 0; +#endif cleareol = 0; /* unset */ more_start = more_end = 0; /* unset */ @@ -615,7 +619,7 @@ refreshline(int ln) if (cleareol /* request to clear to end of line */ || !nllen /* no line buffer given */ || (ln == 0 && (put_rpmpt != oput_rpmpt))) { /* prompt changed */ - p1 = halloc(winw + 2); + p1 = zhalloc(winw + 2); if (nllen) strncpy(p1, nl, nllen); memset(p1 + nllen, ' ', winw - nllen); @@ -627,7 +631,7 @@ refreshline(int ln) nl = p1; /* don't keep the padding for prompt line */ nllen = winw; } else if (ollen > nllen) { /* make new line at least as long as old */ - p1 = halloc(ollen + 1); + p1 = zhalloc(ollen + 1); strncpy(p1, nl, nllen); memset(p1 + nllen, ' ', ollen - nllen); p1[ollen] = '\0'; diff --git a/Src/Zle/zle_tricky.c b/Src/Zle/zle_tricky.c index 4b42640e1..f01ffbf1c 100644 --- a/Src/Zle/zle_tricky.c +++ b/Src/Zle/zle_tricky.c @@ -73,9 +73,10 @@ static int wb, we; static int offs; /* These control the type of completion that will be done. They are * - * affected by the choice of ZLE command and by relevant shell options. */ + * affected by the choice of ZLE command and by relevant shell options. * + * usemenu is set to 2 if we have to start automenu. */ -static int usemenu, useglob; +static int usemenu, useglob, useexact, useline, uselist; /* != 0 if we are in the middle of a menu completion */ @@ -125,7 +126,7 @@ static int validlist; /* This flag is non-zero if we are completing a pattern (with globcomplete) */ -static int ispattern; +static int ispattern, haspattern; /* Two patterns used when doing glob-completion. The first one is built * * from the whole word we are completing and the second one from that * @@ -168,12 +169,6 @@ static int addwhat; static char *qword; -/* This is non-zero if we are doing a menu-completion and this is not the * - * first call (e.g. when automenu is set and menu-completion was entered * - * due to this). */ - -static int amenu; - /* The current group of matches. */ static Cmgroup mgroup; @@ -322,7 +317,7 @@ completecall(void) void completeword(void) { - usemenu = isset(MENUCOMPLETE); + usemenu = !!isset(MENUCOMPLETE); useglob = isset(GLOBCOMPLETE); if (c == '\t' && usetab()) selfinsert(); @@ -351,7 +346,7 @@ menucomplete(void) void listchoices(void) { - usemenu = isset(MENUCOMPLETE); + usemenu = !!isset(MENUCOMPLETE); useglob = isset(GLOBCOMPLETE); docomplete(COMP_LIST_COMPLETE); } @@ -371,7 +366,7 @@ deletecharorlist(void) Cmgroup mg = menugrp; Cmatch *mc = menucur; - usemenu = isset(MENUCOMPLETE); + usemenu = !!isset(MENUCOMPLETE); useglob = isset(GLOBCOMPLETE); if (cs != ll) { fixsuffix(); @@ -398,7 +393,7 @@ expandword(void) void expandorcomplete(void) { - usemenu = isset(MENUCOMPLETE); + usemenu = !!isset(MENUCOMPLETE); useglob = isset(GLOBCOMPLETE); if (c == '\t' && usetab()) selfinsert(); @@ -427,7 +422,7 @@ menuexpandorcomplete(void) void listexpand(void) { - usemenu = isset(MENUCOMPLETE); + usemenu = !!isset(MENUCOMPLETE); useglob = isset(GLOBCOMPLETE); docomplete(COMP_LIST_EXPAND); } @@ -492,9 +487,9 @@ acceptandmenucomplete(void) } /* These are flags saying if we are completing in the command * - * position or in a redirection. */ + * position, in a redirection, or in a parameter expansion. */ -static int lincmd, linredir; +static int lincmd, linredir, ispar; /* The string for the redirection operator. */ @@ -513,10 +508,10 @@ static char *varname; static int insubscr; -/* 1 if we are completing in a string */ +/* 1 if we are completing in a quoted string (or inside `...`) */ /**/ -int instring; +int instring, inbackt; /* Convenience macro for calling bslashquote() (formerly quotename()). * * This uses the instring variable above. */ @@ -601,6 +596,87 @@ cmphaswilds(char *str) return 0; } +/* Check if we have to complete a parameter name. */ + +static char * +check_param(char *s, int set) +{ + char *p; + + ispar = 0; + /* Try to find a `$'. */ + for (p = s + offs; p > s && *p != String; p--); + if (*p == String) { + /* Handle $$'s */ + while (p > s && p[-1] == String) + p--; + while (p[1] == String && p[2] == String) + p += 2; + } + if (*p == String && p[1] != Inpar && p[1] != Inbrack) { + /* This is really a parameter expression (not $(...) or $[...]). */ + char *b = p + 1, *e = b; + int n = 0, br = 1; + + if (*b == Inbrace) { + /* If this is a ${...}, ignore the possible (...) flags. */ + b++, br++; + n = skipparens(Inpar, Outpar, &b); + } + + /* Ignore the stuff before the parameter name. */ + for (; *b; b++) + if (*b != '^' && *b != Hat && + *b != '=' && *b != Equals && + *b != '~' && *b != Tilde) + break; + if (*b == '#' || *b == Pound || *b == '+') + b++; + + e = b; + /* Find the end of the name. */ + if (*e == Quest || *e == Star || *e == String || *e == Qstring || + *e == '?' || *e == '*' || *e == '$' || + *e == '-' || *e == '!' || *e == '@') + e++; + else if (idigit(*e)) + while (idigit(*e)) + e++; + else if (iident(*e)) + while (iident(*e) || + (comppatmatch && *comppatmatch && + (*e == Star || *e == Quest))) + e++; + + /* Now make sure that the cursor is inside the name. */ + if (offs <= e - s && offs >= b - s && n <= 0) { + /* It is. */ + /* If we were called from makecomplistflags(), we have to set the + * global variables. */ + if (set) { + if (br >= 2) + mflags |= CMF_PARBR; + + /* Get the prefix (anything up to the character before the name). */ + lpsuf = dupstring(quotename(e, NULL, NULL, NULL)); + *e = '\0'; + lpsl = strlen(lpsuf); + ripre = dupstring(s); + ripre[b - s] = '\0'; + ipre = dupstring(quotename(ripre, NULL, NULL, NULL)); + untokenize(ipre); + } + /* And adjust wb, we, and offs again. */ + offs -= b - s; + wb = cs - offs; + we = wb + e - b; + ispar = (br >= 2 ? 2 : 1); + return b; + } + } + return NULL; +} + /* The main entry point for completion. */ /**/ @@ -625,9 +701,9 @@ docomplete(int lst) /* Check if we have to start a menu-completion (via automenu). */ - if ((amenu = (isset(AUTOMENU) && lastambig && - (!isset(BASHAUTOLIST) || lastambig == 2)))) - usemenu = 1; + if (isset(AUTOMENU) && lastambig && + (!isset(BASHAUTOLIST) || lastambig == 2)) + usemenu = 2; /* Expand history references before starting completion. If anything * * changed, do no more. */ @@ -910,7 +986,7 @@ addx(char **ptmp) (instring && (line[cs] == '"' || line[cs] == '\'')) || (addspace = (comppref && !iblank(line[cs])))) { *ptmp = (char *)line; - line = (unsigned char *)halloc(strlen((char *)line) + 3 + addspace); + line = (unsigned char *)zhalloc(strlen((char *)line) + 3 + addspace); memcpy(line, *ptmp, cs); line[cs] = 'x'; if (addspace) @@ -999,6 +1075,7 @@ get_comp_string(void) else if (*p == '\\' && p[1] && !(k & 1)) p++; instring = (j & 1) ? 2 : (k & 1); + inbackt = (i & 1); addx(&tmp); if (instring) { /* Yes, we are in a string. */ @@ -1010,7 +1087,7 @@ get_comp_string(void) * What?? Why that?? Well, we want to be able to complete * * inside strings. The lexer code gives us no help here, * * so we have to cheat. We remove the quotes, the lexer * - * will than treat the words in the strings normally and we * + * will then treat the words in the strings normally and we * * can complete them. * * This is completely the wrong thing to do, but it's * * occasionally useful, and we can't handle quotes properly * @@ -1551,7 +1628,7 @@ getcline(char *l, int ll, char *w, int wl, int fl) if ((r = freecl)) freecl = r->next; else - r = (Cline) halloc(sizeof(*r)); + r = (Cline) zhalloc(sizeof(*r)); r->next = NULL; r->line = l; @@ -1626,7 +1703,7 @@ add_bmatchers(Cmatcher m) for (; m; m = m->next) { if ((!m->flags && m->wlen > 0 && m->llen > 0) || (m->flags == CMF_RIGHT && m->wlen == -1 && !m->llen)) { - *q = n = (Cmlist) halloc(sizeof(struct cmlist)); + *q = n = (Cmlist) zhalloc(sizeof(struct cmlist)); n->matcher = m; q = &(n->next); } @@ -1796,7 +1873,7 @@ join_strs(int la, char *sa, int lb, char *sb) if (!t) break; } else { - if (rr <= mp->llen) { + if (rr <= 1) { char *or = rs; rs = realloc(rs, (rl += 20)); @@ -1850,7 +1927,7 @@ join_ends(Cline o, Cline n, int *olp, int *nlp) } else { /* Different anchors, see if we can find matching anchors * further down the lists. */ - Cline to, tn; + Cline to, tn = NULL; int t = 0; /* But first build the common prefix. */ @@ -3337,6 +3414,7 @@ match_pfx(char *l, char *w, Cline *nlp, int *lp, Cline *rlp, int *bplp) } } while (ll && lw) { + t = 0; /* First try the matchers. */ for (ms = mstack; ms; ms = ms->next) { for (mp = ms->matcher; mp; mp = mp->next) { @@ -3578,6 +3656,7 @@ match_sfx(char *l, char *w, Cline *nlp, int *lp, int *bslp) } } while (ll && lw) { + t = 0; for (ms = mstack; ms; ms = ms->next) { for (mp = ms->matcher; mp; mp = mp->next) { if (lm == mp) @@ -3774,7 +3853,7 @@ comp_match(char *pfx, char *sfx, char *w, Cline *clp, int qu, int *bpl, int *bsl * in the cline struct in the middle. */ pml = strlen(p); sml = strlen(s); - r = (char *) halloc(pml + sml + last->llen + 1); + r = (char *) zhalloc(pml + sml + last->llen + 1); strcpy(r, p); strncpy(r + pml, last->line, last->llen); strcpy(r + pml + last->llen, s); @@ -3824,7 +3903,7 @@ comp_match(char *pfx, char *sfx, char *w, Cline *clp, int qu, int *bpl, int *bsl static void inststrlen(char *str, int move, int len) { - if (!len) + if (!len || !str) return; if (len == -1) len = strlen(str); @@ -3902,30 +3981,28 @@ instmatch(Cmatch m) * the matches. */ /**/ -void +int addmatches(char *ipre, char *ppre, char *psuf, char *prpre, char *pre, char *suf, char *group, char *rems, char *remf, char *ign, int flags, int aflags, Cmatcher match, char *exp, char **argv) { - char *s, *t, *e, *me, *ms, *lipre = NULL, *lpre, *lsuf, **aign = NULL; - int lpl, lsl, i, pl, sl, test, bpl, bsl, llpl, llsl; - Aminfo ai; + char *s, *t, *e, *me, *ms, *lipre = NULL, *lpre = NULL, *lsuf = NULL; + char **aign = NULL; + int lpl, lsl, i, pl, sl, test, bpl, bsl, llpl = 0, llsl = 0, nm = mnum; + Aminfo ai = NULL; Cline lc = NULL; - LinkList l; + LinkList l = NULL; Cmatch cm; struct cmlist mst; Cmlist oms = mstack; - - /* Use menu-completion (-U)? */ - if ((aflags & CAF_MENU) && isset(AUTOMENU)) - usemenu = 1; + Comp cp = NULL; /* Switch back to the heap that was used when the completion widget * was invoked. */ SWITCHHEAPS(compheap) { HEAPALLOC { if (exp) { - expl = (Cexpl) halloc(sizeof(struct cexpl)); + expl = (Cexpl) zhalloc(sizeof(struct cexpl)); expl->count = expl->fcount = 0; expl->str = dupstring(exp); } else @@ -3954,9 +4031,30 @@ addmatches(char *ipre, char *ppre, char *psuf, char *prpre, char *pre, if (aflags & CAF_MATCH) { lipre = dupstring(compiprefix); lpre = dupstring(compprefix); - llpl = strlen(lpre); lsuf = dupstring(compsuffix); + llpl = strlen(lpre); llsl = strlen(lsuf); + /* Test if there is an existing -P prefix. */ + if (pre && *pre) { + pl = pfxlen(pre, lpre); + llpl -= pl; + lpre += pl; + } + if (comppatmatch && *comppatmatch) { + char *tmp = (char *) zhalloc(2 + llpl + llsl); + + strcpy(tmp, lpre); + tmp[llpl] = 'x'; + strcpy(tmp + llpl + 1, lsuf); + + tokenize(tmp); + remnulargs(tmp); + if (haswilds(tmp)) { + tmp[llpl] = Star; + if ((cp = parsereg(tmp))) + haspattern = 1; + } + } } /* Now duplicate the strings we have from the command line. */ if (ipre) @@ -3973,50 +4071,71 @@ addmatches(char *ipre, char *ppre, char *psuf, char *prpre, char *pre, lsl = strlen(psuf); } else lsl = 0; - if (pre) - pre = dupstring(pre); - if (suf) - suf = dupstring(suf); - if (!prpre && (prpre = ppre)) { - singsub(&prpre); - untokenize(prpre); - } else - prpre = dupstring(prpre); - /* Select the group in which to store the matches. */ - if (group) { - endcmgroup(NULL); - begcmgroup(group, (aflags & CAF_NOSORT)); - if (aflags & CAF_NOSORT) - mgroup->flags |= CGF_NOSORT; - } else { - endcmgroup(NULL); - begcmgroup("default", 0); - } - /* Select the set of matches. */ - if (aflags & CAF_ALT) { - l = fmatches; - ai = fainfo; - } else { - l = matches; - ai = ainfo; + if (aflags & CAF_MATCH) { + s = ppre ? ppre : ""; + if (llpl <= lpl && strpfx(lpre, s)) { + llpl = 0; + lpre = ""; + } else if (llpl > lpl && strpfx(s, lpre)) { + llpl -= lpl; + lpre += lpl; + } else + *argv = NULL; + s = psuf ? psuf : ""; + if (llsl <= lsl && strsfx(lsuf, s)) { + llsl = 0; + lsuf = ""; + } else if (llsl > lsl && strsfx(s, lsuf)) { + lsuf[llsl - lsl] = '\0'; + llsl -= lsl; + } else + *argv = NULL; } - if (remf) { - remf = dupstring(remf); - rems = NULL; - } else if (rems) - rems = dupstring(rems); - /* Build the common -P prefix. */ - if (ai->pprefix) { + if (*argv) { if (pre) - ai->pprefix[pfxlen(ai->pprefix, pre)] = '\0'; - else - ai->pprefix[0] = '\0'; - } else - ai->pprefix = dupstring(pre ? pre : ""); - + pre = dupstring(pre); + if (suf) + suf = dupstring(suf); + if (!prpre && (prpre = ppre)) { + singsub(&prpre); + untokenize(prpre); + } else + prpre = dupstring(prpre); + /* Select the group in which to store the matches. */ + if (group) { + endcmgroup(NULL); + begcmgroup(group, (aflags & CAF_NOSORT)); + if (aflags & CAF_NOSORT) + mgroup->flags |= CGF_NOSORT; + } else { + endcmgroup(NULL); + begcmgroup("default", 0); + } + /* Select the set of matches. */ + if (aflags & CAF_ALT) { + l = fmatches; + ai = fainfo; + } else { + l = matches; + ai = ainfo; + } + if (remf) { + remf = dupstring(remf); + rems = NULL; + } else if (rems) + rems = dupstring(rems); + /* Build the common -P prefix. */ + if (ai->pprefix) { + if (pre) + ai->pprefix[pfxlen(ai->pprefix, pre)] = '\0'; + else + ai->pprefix[0] = '\0'; + } else + ai->pprefix = dupstring(pre ? pre : ""); + } /* Walk through the matches given. */ for (; (s = dupstring(*argv)); argv++) { - sl = strlen(s); + sl = pl = strlen(s); lc = NULL; ms = NULL; bpl = brpl; @@ -4042,19 +4161,26 @@ addmatches(char *ipre, char *ppre, char *psuf, char *prpre, char *pre, } if (aflags & CAF_MATCH) { /* Do the matching. */ - test = (sl >= llpl + llsl && - strpfx(lpre, s) && strsfx(lsuf, s)); - if (!test && mstack && - (ms = comp_match(lpre, lsuf, s, - &lc, (aflags & CAF_QUOTE), - &bpl, &bsl))) - test = 1; - - if (!test) - continue; - pl = sl - llsl; - me = s + sl - llsl; - e = s + llpl; + if (cp) { + if ((test = domatch(s, cp, 0))) + e = me = s + sl; + else + continue; + } else { + test = (sl >= llpl + llsl && + strpfx(lpre, s) && strsfx(lsuf, s)); + if (!test && mstack && + (ms = comp_match(lpre, lsuf, s, + &lc, (aflags & CAF_QUOTE), + &bpl, &bsl))) + test = 1; + + if (!test) + continue; + pl = sl - llsl; + me = s + sl - llsl; + e = s + llpl; + } } else { e = s; me = s + sl; @@ -4072,14 +4198,15 @@ addmatches(char *ipre, char *ppre, char *psuf, char *prpre, char *pre, if (!ms) { if (sl < ai->minlen) ai->minlen = sl; - if (!mstack && ai->firstm && + if (!cp && !mstack && ai->firstm && (i = sfxlen(ai->firstm->str, s)) < ai->suflen) ai->suflen = i; } t = s; if (ppre) t = dyncat(ppre, t); - if (!ms && mstack) { + lc = NULL; + if (!cp && !ms && (mstack || psuf)) { int bl = ((aflags & CAF_MATCH) ? llpl : 0); Cline *clp = &lc, tlc; char *ss = dupstring(s), *ee = me + (ss - s); @@ -4109,7 +4236,7 @@ addmatches(char *ipre, char *ppre, char *psuf, char *prpre, char *pre, clp = &(tlc->next); } *clp = NULL; - } else if (mstack) { + } else if (!cp && mstack) { Cline tlc; if (ppre && *ppre) { @@ -4148,7 +4275,7 @@ addmatches(char *ipre, char *ppre, char *psuf, char *prpre, char *pre, lc = tlc; } else ai->iprefix = ""; - if (!ms && !mstack) { + if (!ms && !mstack && !lc) { if ((aflags & CAF_MATCH) || ai->cpl > pl) ai->cpl = pl; if ((aflags & CAF_MATCH) || ai->csl > lsl) @@ -4164,12 +4291,12 @@ addmatches(char *ipre, char *ppre, char *psuf, char *prpre, char *pre, ai->count++; /* Finally add the match. */ - cm = (Cmatch) halloc(sizeof(struct cmatch)); + cm = (Cmatch) zhalloc(sizeof(struct cmatch)); cm->ppre = ppre; cm->psuf = psuf; cm->prpre = prpre; cm->str = (ms ? ms : dupstring(s)); - cm->ipre = cm->ripre = ipre; + cm->ipre = cm->ripre = (ipre && *ipre ? ipre : NULL); cm->pre = pre; cm->suf = suf; cm->flags = flags; @@ -4179,7 +4306,7 @@ addmatches(char *ipre, char *ppre, char *psuf, char *prpre, char *pre, cm->rems = rems; addlinknode(l, cm); - if (expl) { + if (exp) { if (l == matches) expl->count++; else @@ -4188,12 +4315,24 @@ addmatches(char *ipre, char *ppre, char *psuf, char *prpre, char *pre, if (!ms) { if (!ai->firstm) ai->firstm = cm; - if ((aflags & CAF_MATCH) && !(e - (s + pl))) { - if (!ai->exact) + if (!cp && (aflags & CAF_MATCH) && !(e - (s + pl))) { + if (!ai->exact) { ai->exact = 1; - else { + zsfree(compexactstr); + compexactstr = e = (char *) zalloc(lpl + sl + lsl + 1); + if (ppre) { + strcpy(e, ppre); + e += lpl; + } + strcpy(e, s); + e += sl; + if (psuf) + strcpy(e, psuf); + comp_setunsetptr(CP_EXACTSTR, 0); + } else { ai->exact = 2; cm = NULL; + comp_setunsetptr(0, CP_EXACTSTR); } ai->exactm = cm; } @@ -4208,6 +4347,8 @@ addmatches(char *ipre, char *ppre, char *psuf, char *prpre, char *pre, /* We switched back to the current heap, now restore the stack of * matchers. */ mstack = oms; + + return (mnum == nm); } /* This adds a match to the list of matches. The string to add is given * @@ -4252,6 +4393,7 @@ addmatch(char *s, char *t) if (incompfunc) s = dupstring(s); + e = s + sl; if (!addwhat) { test = 1; } else if (addwhat == -1 || addwhat == -5 || addwhat == -6 || @@ -4318,7 +4460,7 @@ addmatch(char *s, char *t) e += s - t; } if (cc) { - tt = (char *)halloc(lppl + lpsl + sl + 1); + tt = (char *)zhalloc(lppl + lpsl + sl + 1); tt[0] = '\0'; if (lppre) strcpy(tt, lppre); @@ -4353,7 +4495,7 @@ addmatch(char *s, char *t) (((addwhat & CC_DISCMDS) && (hn->flags & DISABLED)) || ((addwhat & CC_EXCMDS) && !(hn->flags & DISABLED)))) || ((addwhat & CC_BINDINGS) && !(hn->flags & DISABLED))))) { - if (sl >= rpl + rsl || mstack) { + if (sl >= rpl + rsl || mstack || cp) { if (cp) { test = domatch(s, patcomp, 0); e = s + sl; @@ -4413,7 +4555,7 @@ addmatch(char *s, char *t) t = s; if (lppre) t = dyncat(lppre, t); - if (!ms && mstack) { + if (!ispattern && !ms && mstack) { Cline *clp = &lc, tlc; char *ss = dupstring(s), *ee = e + (ss - s); @@ -4481,7 +4623,7 @@ addmatch(char *s, char *t) ai->count++; /* Allocate and fill the match structure. */ - cm = (Cmatch) halloc(sizeof(struct cmatch)); + cm = (Cmatch) zhalloc(sizeof(struct cmatch)); if (ispattern) { if (lpsuf && *lpsuf && strsfx(lpsuf, s)) { s[sl - lpsl] = '\0'; @@ -4532,11 +4674,29 @@ addmatch(char *s, char *t) /* Do we have an exact match? More than one? */ if (!ispattern && !(e - (s + pl))) { - if (!ai->exact) + if (!ai->exact) { ai->exact = 1; - else { + if (incompfunc) { + int lpl = (cm->ppre ? strlen(cm->ppre) : 0); + int lsl = (cm->psuf ? strlen(cm->psuf) : 0); + + zsfree(compexactstr); + compexactstr = e = (char *) zalloc(lpl + sl + lsl + 1); + if (cm->ppre) { + strcpy(e, cm->ppre); + e += lpl; + } + strcpy(e, s); + e += sl; + if (cm->psuf) + strcpy(e, cm->psuf); + comp_setunsetptr(CP_EXACTSTR, 0); + } + } else { ai->exact = 2; cm = NULL; + if (incompfunc) + comp_setunsetptr(0, CP_EXACTSTR); } ai->exactm = cm; } @@ -4688,7 +4848,6 @@ dumphashtable(HashTable ht, int what) for (i = 0; i < ht->hsize; i++) for (hn = ht->nodes[i]; hn; hn = hn->next) addmatch(hn->nam, (char *) hn); - } /* ScanFunc used by maketildelist() et al. */ @@ -4797,7 +4956,7 @@ gen_matches_files(int dirs, int execs, int all) strcpy(p + o, psuf); /* Do we have to use globbing? */ - if (ispattern || (ns && isset(GLOBCOMPLETE))) { + if (ispattern || (ns && comppatmatch && *comppatmatch)) { /* Yes, so append a `*' if needed. */ if (ns) { int tl = strlen(p); @@ -4847,6 +5006,15 @@ docompletion(char *s, int lst, int incmd) ainfo = fainfo = NULL; matchers = newlinklist(); + useline = (lst != COMP_LIST_COMPLETE); + useexact = (isset(RECEXACT) && usemenu != 1); + uselist = (useline ? + ((isset(AUTOLIST) && !isset(BASHAUTOLIST)) ? + (isset(LISTAMBIGUOUS) ? 3 : 2) : 0) : 1); + zsfree(comppatmatch); + comppatmatch = ztrdup(useglob ? "yes" : ""); + haspattern = 0; + /* Make sure we have the completion list and compctl. */ if (makecomplist(s, incmd, lst)) { /* Error condition: feeeeeeeeeeeeep(). */ @@ -4854,23 +5022,26 @@ docompletion(char *s, int lst, int incmd) clearlist = 1; goto compend; } - if (lst == COMP_LIST_COMPLETE) + if (!useline && uselist) /* All this and the guy only wants to see the list, sigh. */ showinglist = -2; - else { + else if (useline) { /* We have matches. */ if (nmatches > 1) - /* There are more than one match. */ + /* There is more than one match. */ do_ambiguous(); else if (nmatches == 1) { /* Only one match. */ - while (!amatches->mcount) - amatches = amatches->next; - do_single(amatches->matches[0]); + Cmgroup m = amatches; + + while (!m->mcount) + m = m->next; + do_single(m->matches[0]); invalidatelist(); } - } + } else + invalidatelist(); /* Print the explanation strings if needed. */ if (!showinglist && validlist && nmatches != 1) { @@ -4928,33 +5099,47 @@ callcompfunc(char *s, char *fn) int lv = lastval; if ((list = getshfunc(fn)) != &dummy_list) { - LinkList args = newlinklist(); char **p, *tmp; - int aadd = 0, usea = 1, icf = incompfunc, osc = sfcontext; - - addlinknode(args, fn); - + int set, aadd = 0, usea = 1, icf = incompfunc, osc = sfcontext; + Param *ocpms = comppms; + + comppms = (Param *) zalloc(CP_NUM * sizeof(Param)); + + set = -1 & ~(CP_PARAMETER | CP_REDIRECT | CP_QUOTE | CP_QUOTING | + CP_EXACTSTR | (useglob ? 0 : CP_PATMATCH)); zsfree(compcontext); - zsfree(compcommand); - compcommand = ""; - if (inwhat == IN_MATH) { + zsfree(compparameter); + zsfree(compredirect); + compparameter = compredirect = ""; + if (ispar) + compcontext = (ispar == 2 ? "brace_parameter" : "parameter"); + else if (inwhat == IN_MATH) { if (insubscr) { compcontext = "subscript"; - compcommand = varname ? varname : ""; + if (varname) { + compparameter = varname; + set |= CP_PARAMETER; + } } else compcontext = "math"; usea = 0; - } else if (lincmd) - compcontext = (insubscr ? "subscript" : "command"); - else if (linredir) { + } else if (lincmd) { + if (insubscr) { + compcontext = "subscript"; + set |= CP_PARAMETER; + } else + compcontext = "command"; + } else if (linredir) { compcontext = "redirect"; if (rdstr) - compcommand = rdstr; + compredirect = rdstr; + set |= CP_REDIRECT; } else switch (inwhat) { case IN_ENV: - compcontext = "value"; - compcommand = varname; + compcontext = "array_value"; + compparameter = varname; + set |= CP_PARAMETER; if (!clwpos) { clwpos = 1; zsfree(clwords[1]); @@ -4966,61 +5151,141 @@ callcompfunc(char *s, char *fn) compcontext = "condition"; break; default: - if (cmdstr) { - compcontext = "argument"; - compcommand = cmdstr; - } else { + if (cmdstr) + compcontext = "command"; + else { compcontext = "value"; + set |= CP_PARAMETER; if (clwords[0]) - compcommand = clwords[0]; + compparameter = clwords[0]; + aadd = 1; } - aadd = 1; } compcontext = ztrdup(compcontext); - tmp = quotename(compcommand, NULL, NULL, NULL); - untokenize(tmp); - compcommand = ztrdup(tmp); - if (usea && (!aadd || clwords[0])) - for (p = clwords + aadd; *p; p++) { - tmp = dupstring(*p); - untokenize(tmp); - addlinknode(args, tmp); + if (compwords) + freearray(compwords); + if (usea && (!aadd || clwords[0])) { + char **q; + + PERMALLOC { + q = compwords = (char **) + zalloc((clwnum - aadd + 1) * sizeof(char *)); + for (p = clwords + aadd; *p; p++, q++) { + tmp = dupstring(*p); + untokenize(tmp); + *q = ztrdup(tmp); + } + *q = NULL; + } LASTALLOC; + } else + compwords = (char **) zcalloc(sizeof(char *)); + + compparameter = ztrdup(compparameter); + compredirect = ztrdup(compredirect); + zsfree(compquote); + zsfree(compquoting); + if (instring) { + if (instring == 1) { + compquote = ztrdup("\'"); + compquoting = ztrdup("single"); + } else { + compquote = ztrdup("\""); + compquoting = ztrdup("double"); } + set |= CP_QUOTE | CP_QUOTING; + } else if (inbackt) { + compquote = ztrdup("`"); + compquoting = ztrdup("backtick"); + } else { + compquote = ztrdup(""); + compquoting = ztrdup(""); + } + untokenize(s = dupstring(s)); zsfree(compprefix); zsfree(compsuffix); if (unset(COMPLETEINWORD)) { - tmp = quotename(s, NULL, NULL, NULL); - untokenize(tmp); - compprefix = ztrdup(tmp); + compprefix = ztrdup(s); compsuffix = ztrdup(""); } else { char *ss = s + offs, sav; - - tmp = quotename(s, &ss, NULL, NULL); + sav = *ss; *ss = '\0'; - untokenize(tmp); - compprefix = ztrdup(tmp); + compprefix = ztrdup(s); *ss = sav; - untokenize(ss); compsuffix = ztrdup(ss); } zsfree(compiprefix); compiprefix = ztrdup(""); - compcurrent = (usea ? (clwpos + 1 - aadd) : 1); + compcurrent = (usea ? (clwpos + 1 - aadd) : 0); compnmatches = mnum; + + zsfree(complist); + switch (uselist) { + case 0: complist = ""; set &= ~CP_LIST; break; + case 1: complist = "list"; break; + case 2: complist = "autolist"; break; + case 3: complist = "ambiguous"; break; + } + complist = ztrdup(complist); + zsfree(compinsert); + if (useline) { + switch (usemenu) { + case 0: compinsert = "unambiguous"; break; + case 1: compinsert = "menu"; break; + case 2: compinsert = "automenu"; break; + } + } else { + compinsert = ""; + set &= ~CP_INSERT; + } + compinsert = ztrdup(compinsert); + if (useexact) + compexact = ztrdup("accept"); + else { + compexact = ztrdup(""); + set &= ~CP_EXACT; + } incompfunc = 1; startparamscope(); makecompparamsptr(); + comp_setunsetptr(set, ~set); makezleparams(1); sfcontext = SFC_CWIDGET; NEWHEAPS(compheap) { - doshfunc(fn, list, args, 0, 1); + doshfunc(fn, list, NULL, 0, 1); } OLDHEAPS; sfcontext = osc; endparamscope(); lastcmd = 0; incompfunc = icf; + + if (!complist) + uselist = 0; + else if (!strcmp(complist, "list")) + uselist = 1; + else if (!strcmp(complist, "auto") || !strcmp(complist, "autolist")) + uselist = 2; + else if (!strcmp(complist, "ambig") || !strcmp(complist, "ambiguous")) + uselist = 3; + else + uselist = 0; + if (!compinsert) + useline = 0; + else if (!strcmp(compinsert, "unambig") || + !strcmp(compinsert, "unambiguous")) + useline = 1, usemenu = 0; + else if (!strcmp(compinsert, "menu")) + useline = 1, usemenu = 1; + else if (!strcmp(compinsert, "auto") || + !strcmp(compinsert, "automenu")) + useline = 1, usemenu = 2; + else + useline = usemenu = 0; + useexact = (compexact && !strcmp(compexact, "accept")); + + zfree(comppms, CP_NUM * sizeof(Param)); + comppms = ocpms; } lastval = lv; } @@ -5047,7 +5312,11 @@ makecomplist(char *s, int incmd, int lst) { struct cmlist ms; Cmlist m; - char *os = s; + char *p, *os = s; + + /* Inside $... ? */ + if ((p = check_param(s, 0))) + os = s = p; /* We build a copy of the list of matchers to use to make sure that this * works even if a shell function called from the completion code changes @@ -5055,22 +5324,27 @@ makecomplist(char *s, int incmd, int lst) if ((m = cmatcher)) { Cmlist mm, *mp = &mm; + int n; - for (; m; m = m->next) { - *mp = (Cmlist) halloc(sizeof(struct cmlist)); + for (n = 0; m; m = m->next, n++) { + *mp = (Cmlist) zhalloc(sizeof(struct cmlist)); (*mp)->matcher = m->matcher; (*mp)->next = NULL; + (*mp)->str = dupstring(m->str); mp = &((*mp)->next); addlinknode(matchers, m->matcher); m->matcher->refc++; } m = mm; - } - compmatcher = 1; + compmatcher = 1; + compmatchertot = n; + } else + compmatcher = 0; /* Walk through the global matchers. */ for (;;) { bmatchers = NULL; + zsfree(compmatcherstr); if (m) { ms.next = NULL; ms.matcher = m->matcher; @@ -5080,9 +5354,11 @@ makecomplist(char *s, int incmd, int lst) * when building new parts for the string to insert into the * line. */ add_bmatchers(m->matcher); - } else + compmatcherstr = ztrdup(m->str); + } else { mstack = NULL; - + compmatcherstr = ztrdup(""); + } ainfo = (Aminfo) hcalloc(sizeof(struct aminfo)); fainfo = (Aminfo) hcalloc(sizeof(struct aminfo)); @@ -5139,33 +5415,6 @@ makecomplist(char *s, int incmd, int lst) /* This should probably be moved into tokenize(). */ -/**/ -static char * -ctokenize(char *p) -{ - char *r = p; - int bslash = 0; - - tokenize(p); - - for (p = r; *p; p++) { - if (*p == '\\') - bslash = 1; - else { - if (*p == '$' || *p == '=' || *p == '{' || *p == '}') { - if (bslash) - p[-1] = Bnull; - else - *p = (*p == '$' ? String : - (*p == '=' ? Equals : - (*p == '{' ? Inbrace : Outbrace))); - } - bslash = 0; - } - } - return r; -} - /**/ char * comp_str(int *ipl, int *pl, int untok) @@ -5177,17 +5426,17 @@ comp_str(int *ipl, int *pl, int untok) int lp, ls, lip; if (!untok) { - ctokenize(p); + tokenize(p); remnulargs(p); - ctokenize(s); + tokenize(s); remnulargs(s); - ctokenize(ip); + tokenize(ip); remnulargs(ip); } ls = strlen(s); lip = strlen(ip); lp = strlen(p); - str = halloc(lip + lp + ls + 1); + str = zhalloc(lip + lp + ls + 1); strcpy(str, ip); strcat(str, p); strcat(str, s); @@ -5201,9 +5450,11 @@ comp_str(int *ipl, int *pl, int untok) } /**/ -void +int makecomplistcall(Compctl cc) { + int nm = mnum; + SWITCHHEAPS(compheap) { HEAPALLOC { int ooffs = offs, lip, lp; @@ -5217,6 +5468,8 @@ makecomplistcall(Compctl cc) compnmatches = mnum; } LASTALLOC; } SWITCHBACKHEAPS; + + return (mnum == nm); } /* A simple counter to avoid endless recursion between old and new style * @@ -5243,24 +5496,20 @@ makecomplistctl(int flags) char *os = cmdstr, **ow = clwords, **p, **q; int on = clwnum, op = clwpos; - clwnum = arrlen(pparams) + 1; + clwnum = arrlen(compwords); clwpos = compcurrent - 1; - cmdstr = ztrdup(compcommand); + cmdstr = ztrdup(compwords[0]); clwords = (char **) zalloc((clwnum + 1) * sizeof(char *)); - clwords[0] = ztrdup(cmdstr); - for (p = pparams, q = clwords + 1; *p; p++, q++) { + for (p = compwords, q = clwords; *p; p++, q++) { t = dupstring(*p); - ctokenize(t); + tokenize(t); remnulargs(t); *q = ztrdup(t); } *q = NULL; offs = lip + lp; incompfunc = 2; - ret = makecomplistglobal(str, - (!clwpos && - !strcmp(compcontext, "command")), - COMP_COMPLETE, flags); + ret = makecomplistglobal(str, !clwpos, COMP_COMPLETE, flags); incompfunc = 1; offs = ooffs; compnmatches = mnum; @@ -5499,7 +5748,7 @@ makecomplistext(Compctl occ, char *os, int incmd) Compcond or, cc; Comp comp; int compadd, m = 0, d = 0, t, tt, i, j, a, b; - char *sc, *s, *ss; + char *sc = NULL, *s, *ss; /* This loops over the patterns separated by `-'s. */ for (compc = occ->ext; compc; compc = compc->next) { @@ -5669,7 +5918,7 @@ findnode(LinkList list, void *dat) static void makecomplistflags(Compctl cc, char *s, int incmd, int compadd) { - int t, sf1, sf2, ooffs, um = usemenu, delit, ispar = 0; + int t, sf1, sf2, ooffs, um = usemenu, delit, oaw; char *p, *sd = NULL, *tt, *s1, *s2, *os = dupstring(s); struct cmlist ms; @@ -5678,6 +5927,8 @@ makecomplistflags(Compctl cc, char *s, int incmd, int compadd) if (incompfunc != 1 && findnode(ccstack, cc)) return; + MUSTUSEHEAP("complistflags"); + addlinknode(ccstack, cc); if (incompfunc != 1 && allccs) { @@ -5711,7 +5962,7 @@ makecomplistflags(Compctl cc, char *s, int incmd, int compadd) if (cc->mask2 & CC_NOSORT) mgroup->flags |= CGF_NOSORT; if (cc->explain) { - expl = (Cexpl) halloc(sizeof(struct cexpl)); + expl = (Cexpl) zhalloc(sizeof(struct cexpl)); expl->count = expl->fcount = 0; } else @@ -5781,79 +6032,16 @@ makecomplistflags(Compctl cc, char *s, int incmd, int compadd) s[suffixll - sl] = '\0'; } /* Do we have one of the special characters `~' and `=' at the beginning? */ - if ((ic = *s) != Tilde && ic != Equals) + if (incompfunc || ((ic = *s) != Tilde && ic != Equals)) ic = 0; /* Check if we have to complete a parameter name... */ - - /* Try to find a `$'. */ - for (p = s + offs; p > s && *p != String; p--); - if (*p == String) { - /* Handle $$'s */ - while (p > s && p[-1] == String) - p--; - while (p[1] == String && p[2] == String) - p += 2; - } - if (*p == String && p[1] != Inpar && p[1] != Inbrack) { - /* This is really a parameter expression (not $(...) or $[...]). */ - char *b = p + 1, *e = b; - int n = 0, br = 1; - - if (*b == Inbrace) { - /* If this is a ${...}, ignore the possible (...) flags. */ - b++, br++; - n = skipparens(Inpar, Outpar, &b); - } - - /* Ignore the stuff before the parameter name. */ - for (; *b; b++) - if (*b != '^' && *b != Hat && - *b != '=' && *b != Equals && - *b != '~' && *b != Tilde) - break; - if (*b == '#' || *b == Pound || *b == '+') - b++; - - e = b; - /* Find the end of the name. */ - if (*e == Quest || *e == Star || *e == String || *e == Qstring || - *e == '?' || *e == '*' || *e == '$' || - *e == '-' || *e == '!' || *e == '@') - e++; - else if (idigit(*e)) - while (idigit(*e)) - e++; - else if (iident(*e)) - while (iident(*e) || - (useglob && (*e == Star || *e == Quest))) - e++; - - /* Now make sure that the cursor is inside the name. */ - if (offs <= e - s && offs >= b - s && n <= 0) { - /* It is. */ - if (br >= 2) - mflags |= CMF_PARBR; - - /* Get the prefix (anything up to the character before the name). */ - lpsuf = dupstring(quotename(e, NULL, NULL, NULL)); - *e = '\0'; - lpsl = strlen(lpsuf); - ripre = dupstring(s); - ripre[b - s] = '\0'; - ipre = dupstring(quotename(ripre, NULL, NULL, NULL)); - untokenize(ipre); - ispar = 1; - /* And adjust wb, we, and offs again. */ - offs -= b - s; - wb = cs - offs; - we = wb + e - b; - s = b; - /* And now make sure that we complete parameter names. */ - cc = &cc_dummy; - cc_dummy.refc = 10000; - cc_dummy.mask = CC_PARAMS | CC_ENVVARS; - } + if (!incompfunc && (p = check_param(s, 1))) { + s = p; + /* And now make sure that we complete parameter names. */ + cc = &cc_dummy; + cc_dummy.refc = 10000; + cc_dummy.mask = CC_PARAMS | CC_ENVVARS; } ooffs = offs; /* If we have to ignore the word, do that. */ @@ -5861,12 +6049,13 @@ makecomplistflags(Compctl cc, char *s, int incmd, int compadd) delit = 1; *s = '\0'; offs = 0; - if (isset(AUTOMENU)) usemenu = 1; + if (isset(AUTOMENU)) + usemenu = 1; } /* Compute line prefix/suffix. */ lpl = offs; - lpre = halloc(lpl + 1); + lpre = zhalloc(lpl + 1); memcpy(lpre, s, lpl); lpre[lpl] = '\0'; lsuf = dupstring(s + offs); @@ -5905,6 +6094,7 @@ makecomplistflags(Compctl cc, char *s, int incmd, int compadd) if (!s1) s1 = p; } + rsl = strlen(rsuf); for (s2 = NULL, sf2 = t = 0, p = rsuf; *p && (!t || !sf2); p++) if (itok(*p)) t |= sf2 ? 4 : 2; @@ -5917,7 +6107,7 @@ makecomplistflags(Compctl cc, char *s, int incmd, int compadd) /* But if we were asked not to do glob completion, we never treat the * * thing as a pattern. */ - if (!useglob) + if (!comppatmatch || !*comppatmatch) ispattern = 0; if (ispattern) { @@ -5930,6 +6120,7 @@ makecomplistflags(Compctl cc, char *s, int incmd, int compadd) } else strcpy(p + rpl, rsuf); patcomp = parsereg(p); + haspattern = 1; } if (!patcomp) { untokenize(rpre); @@ -5963,6 +6154,8 @@ makecomplistflags(Compctl cc, char *s, int incmd, int compadd) line[cs] = 0; lppre = dupstring((char *) (line + wb)); line[cs] = save; + if (brbeg && *brbeg) + strcpy(lppre + brpl, lppre + brpl + strlen(brbeg)); if ((p = strrchr(lppre, '/'))) { p[1] = '\0'; lppl = strlen(lppre); @@ -5979,8 +6172,14 @@ makecomplistflags(Compctl cc, char *s, int incmd, int compadd) char save = line[we]; line[we] = 0; - lpsuf = strchr(dupstring((char *) (line + cs)), '/'); + lpsuf = dupstring((char *) (line + cs)); line[we] = save; + if (brend && *brend) { + char *p = lpsuf + brsl - (cs - wb); + + strcpy(p, p + strlen(brend)); + } + lpsuf = strchr(lpsuf, '/'); lpsl = (lpsuf ? strlen(lpsuf) : 0); } else { @@ -5994,7 +6193,7 @@ makecomplistflags(Compctl cc, char *s, int incmd, int compadd) /* And the suffix. */ fsuf = dupstrpfx(rsuf, s2 - rsuf); - if (useglob && (ispattern & 2)) { + if (comppatmatch && *comppatmatch && (ispattern & 2)) { int t2; /* We have to use globbing, so compute the pattern from * @@ -6079,10 +6278,10 @@ makecomplistflags(Compctl cc, char *s, int incmd, int compadd) if ((pp = get_user_var(cc->withd))) { dirs = npp = - (char**) halloc(sizeof(char *)*(arrlen(pp)+1)); + (char**) zhalloc(sizeof(char *)*(arrlen(pp)+1)); while (*pp) { pl = strlen(*pp); - tp = (char *) halloc(strlen(*pp) + tl); + tp = (char *) zhalloc(strlen(*pp) + tl); strcpy(tp, *pp); tp[pl] = '/'; strcpy(tp + pl + 1, ppre); @@ -6098,7 +6297,7 @@ makecomplistflags(Compctl cc, char *s, int incmd, int compadd) char *tp; int pl = strlen(cc->withd); - ta[0] = tp = (char *) halloc(strlen(ppre) + pl + 2); + ta[0] = tp = (char *) zhalloc(strlen(ppre) + pl + 2); strcpy(tp, cc->withd); tp[pl] = '/'; strcpy(tp + pl + 1, ppre); @@ -6270,7 +6469,7 @@ makecomplistflags(Compctl cc, char *s, int incmd, int compadd) if (isset(AUTOCD) && isset(CDABLEVARS)) dumphashtable(paramtab, -4); } - addwhat = (cc->mask & CC_QUOTEFLAG) ? -2 : CC_QUOTEFLAG; + oaw = addwhat = (cc->mask & CC_QUOTEFLAG) ? -2 : CC_QUOTEFLAG; if (cc->mask & CC_NAMED) /* Add named directories. */ @@ -6278,12 +6477,16 @@ makecomplistflags(Compctl cc, char *s, int incmd, int compadd) if (cc->mask & CC_OPTIONS) /* Add option names. */ dumphashtable(optiontab, addwhat); - if (cc->mask & CC_VARS) + if (cc->mask & CC_VARS) { /* And parameter names. */ dumphashtable(paramtab, -9); - if (cc->mask & CC_BINDINGS) + addwhat = oaw; + } + if (cc->mask & CC_BINDINGS) { /* And zle function names... */ dumphashtable(thingytab, CC_BINDINGS); + addwhat = oaw; + } if (cc->keyvar) { /* This adds things given to the compctl -k flag * * (from a parameter or a list of words). */ @@ -6293,54 +6496,53 @@ makecomplistflags(Compctl cc, char *s, int incmd, int compadd) while (*usr) addmatch(*usr++, NULL); } - if (cc->mask & CC_USERS) + if (cc->mask & CC_USERS) { /* Add user names. */ maketildelist(); + addwhat = oaw; + } + if (cc->widget) + callcompfunc(os, cc->widget); if (cc->func) { - if (cc->func[0] == ' ') - /* Temporary hack for access to new style completione. */ - callcompfunc(os, cc->func + 1); - else { - /* This handles the compctl -K flag. */ - List list; - char **r; - int lv = lastval; + /* This handles the compctl -K flag. */ + List list; + char **r; + int lv = lastval; - /* Get the function. */ - if ((list = getshfunc(cc->func)) != &dummy_list) { - /* We have it, so build a argument list. */ - LinkList args = newlinklist(); - int osc = sfcontext; - - addlinknode(args, cc->func); + /* Get the function. */ + if ((list = getshfunc(cc->func)) != &dummy_list) { + /* We have it, so build a argument list. */ + LinkList args = newlinklist(); + int osc = sfcontext; - if (delit) { - p = dupstrpfx(os, ooffs); - untokenize(p); - addlinknode(args, p); - p = dupstring(os + ooffs); - untokenize(p); - addlinknode(args, p); - } else { - addlinknode(args, lpre); - addlinknode(args, lsuf); - } + addlinknode(args, cc->func); - /* This flag allows us to use read -l and -c. */ - if (incompfunc != 1) - incompctlfunc = 1; - sfcontext = SFC_COMPLETE; - /* Call the function. */ - doshfunc(cc->func, list, args, 0, 1); - sfcontext = osc; - incompctlfunc = 0; - /* And get the result from the reply parameter. */ - if ((r = get_user_var("reply"))) - while (*r) - addmatch(*r++, NULL); + if (delit) { + p = dupstrpfx(os, ooffs); + untokenize(p); + addlinknode(args, p); + p = dupstring(os + ooffs); + untokenize(p); + addlinknode(args, p); + } else { + addlinknode(args, lpre); + addlinknode(args, lsuf); } - lastval = lv; + + /* This flag allows us to use read -l and -c. */ + if (incompfunc != 1) + incompctlfunc = 1; + sfcontext = SFC_COMPLETE; + /* Call the function. */ + doshfunc(cc->func, list, args, 0, 1); + sfcontext = osc; + incompctlfunc = 0; + /* And get the result from the reply parameter. */ + if ((r = get_user_var("reply"))) + while (*r) + addmatch(*r++, NULL); } + lastval = lv; } if (cc->mask & (CC_JOBS | CC_RUNNING | CC_STOPPED)) { /* Get job names. */ @@ -6378,7 +6580,7 @@ makecomplistflags(Compctl cc, char *s, int incmd, int compadd) * get the words we have to expand. */ zleparse = 1; lexsave(); - tmpbuf = (char *)halloc(strlen(cc->str) + 5); + tmpbuf = (char *)zhalloc(strlen(cc->str) + 5); sprintf(tmpbuf, "foo %s", cc->str); /* KLUDGE! */ inpush(tmpbuf, 0, NULL); strinbeg(); @@ -6456,9 +6658,12 @@ makecomplistflags(Compctl cc, char *s, int incmd, int compadd) if ((t = cc->mask & CC_BUILTINS)) /* Add builtins. */ dumphashtable(builtintab, t | (cc->mask & (CC_DISCMDS|CC_EXCMDS))); - if ((t = cc->mask & CC_EXTCMDS)) + if ((t = cc->mask & CC_EXTCMDS)) { /* Add external commands */ + if (isset(HASHLISTALL)) + cmdnamtab->filltable(cmdnamtab); dumphashtable(cmdnamtab, t | (cc->mask & (CC_DISCMDS|CC_EXCMDS))); + } if ((t = cc->mask & CC_RESWDS)) /* Add reserved words */ dumphashtable(reswdtab, t | (cc->mask & (CC_DISCMDS|CC_EXCMDS))); @@ -6486,7 +6691,7 @@ makecomplistflags(Compctl cc, char *s, int incmd, int compadd) for (ln = firstnode(matches); ln; ln = nextnode(ln)) { m = (Cmatch) getdata(ln); if (m->ppre) { - char *p = (char *) halloc(strlen(m->ppre) + strlen(m->str) + + char *p = (char *) zhalloc(strlen(m->ppre) + strlen(m->str) + strlen(m->psuf) + 1); sprintf(p, "%s%s%s", m->ppre, m->str, m->psuf); @@ -6654,7 +6859,7 @@ get_user_var(char *nam) if ((val = getsparam(nam))) { arr = (char **)ncalloc(2*sizeof(char *)); - arr[0] = val; + arr[0] = (incompfunc ? dupstring(val) : val); arr[1] = NULL; } return arr; @@ -6763,7 +6968,10 @@ makearray(LinkList l, int s, int *np, int *nlp) if ((*ap)->flags & CMF_NOLIST) nl++; *cp = NULL; - } + } else + for (ap = rp; *ap; ap++) + if ((*ap)->flags & CMF_NOLIST) + nl++; if (np) *np = n; if (nlp) @@ -6795,7 +7003,7 @@ begcmgroup(char *n, int nu) p = p->next; } } - mgroup = (Cmgroup) halloc(sizeof(struct cmgroup)); + mgroup = (Cmgroup) zhalloc(sizeof(struct cmgroup)); mgroup->name = dupstring(n); mgroup->flags = mgroup->lcount = mgroup->mcount = 0; mgroup->matches = NULL; @@ -6858,8 +7066,8 @@ dupmatch(Cmatch m) r->ppre = ztrdup(m->ppre); r->psuf = ztrdup(m->psuf); r->prpre = ztrdup(m->prpre); - r->pre = m->pre; - r->suf = m->suf; + r->pre = ztrdup(m->pre); + r->suf = ztrdup(m->suf); r->flags = m->flags; r->brpl = m->brpl; r->brsl = m->brsl; @@ -6975,6 +7183,8 @@ freematch(Cmatch m) zsfree(m->ripre); zsfree(m->ppre); zsfree(m->psuf); + zsfree(m->pre); + zsfree(m->suf); zsfree(m->prpre); zsfree(m->rems); zsfree(m->remf); @@ -7030,15 +7240,14 @@ freematches(void) static void do_ambiguous(void) { - int p = (usemenu || ispattern), atend = (cs == we); + int p = (usemenu || haspattern), atend = (cs == we); menucmp = 0; /* If we have to insert the first match, call do_single(). This is * * how REC_EXACT takes effect. We effectively turn the ambiguous * * completion into an unambiguous one. */ - if (ainfo && ainfo->exact == 1 && isset(RECEXACT) && !(fromcomp & FC_LINE) && - (usemenu == 0 || unset(AUTOMENU))) { + if (ainfo && ainfo->exact == 1 && useexact && !(fromcomp & FC_LINE)) { do_single(ainfo->exactm); invalidatelist(); return; @@ -7049,7 +7258,7 @@ do_ambiguous(void) * unambiguous prefix. */ lastambig = 1; - if(p) { + if (p) { /* p is set if we are in a position to start using menu completion * * due to one of the menu completion options, or due to the * * menu-complete-word command, or due to using GLOB_COMPLETE which * @@ -7152,7 +7361,7 @@ do_ambiguous(void) * prefix was inserted, return now, bypassing the list-displaying * * code. On the way, invalidate the list and note that we don't * * want to enter an AUTO_MENU imediately. */ - if(isset(LISTAMBIGUOUS) && la) { + if (uselist == 3 && la) { int fc = fromcomp; invalidatelist(); @@ -7165,8 +7374,7 @@ do_ambiguous(void) * if it is needed. */ if (isset(LISTBEEP)) feep(); - if (isset(AUTOLIST) && !isset(BASHAUTOLIST) && !amenu && !showinglist && - smatches >= 2) + if (uselist && usemenu != 2 && !showinglist && smatches >= 2) showinglist = -2; } @@ -7264,7 +7472,7 @@ do_single(Cmatch m) struct stat buf; /* Build the path name. */ - if (ispattern || ic || m->ripre) { + if (haspattern || ic || m->ripre) { int ne = noerrs; noerrs = 1; @@ -7620,14 +7828,14 @@ listmatches(void) char **pp = g->ylist; if ((e = g->expls)) { - if (pnl) { - putc('\n', shout); - pnl = 0; - } while (*e) { if ((*e)->count) { + if (pnl) { + putc('\n', shout); + pnl = 0; + } printfmt((*e)->str, (*e)->count, 1); - putc('\n', shout); + pnl = 1; } e++; } @@ -7670,7 +7878,7 @@ listmatches(void) } } else if (g->lcount) { - int n = g->lcount, nl = (n + ncols - 1) / ncols, nc = nl, i, j, a; + int n = g->lcount, nl = (n + ncols - 1) / ncols, nc = nl, i, j, a = 0; Cmatch *q; if (n && pnl) { @@ -7691,7 +7899,7 @@ listmatches(void) struct stat buf; char *pb; - pb = (char *) halloc((m->prpre ? strlen(m->prpre) : 0) + + pb = (char *) zhalloc((m->prpre ? strlen(m->prpre) : 0) + 3 + strlen(m->str)); sprintf(pb, "%s%s", (m->prpre ? m->prpre : "./"), m->str); diff --git a/Src/Zle/zle_word.c b/Src/Zle/zle_word.c index afd860066..f446d1769 100644 --- a/Src/Zle/zle_word.c +++ b/Src/Zle/zle_word.c @@ -465,7 +465,7 @@ transposewords(void) return; } for (p1 = p2; p1 && iword(line[p1 - 1]); p1--); - pp = temp = (char *)halloc(p4 - p1 + 1); + pp = temp = (char *)zhalloc(p4 - p1 + 1); struncpy(&pp, (char *) line + p3, p4 - p3); struncpy(&pp, (char *) line + p2, p3 - p2); struncpy(&pp, (char *) line + p1, p2 - p1); diff --git a/Src/builtin.c b/Src/builtin.c index fc9b113ca..c042537f4 100644 --- a/Src/builtin.c +++ b/Src/builtin.c @@ -1072,12 +1072,14 @@ fixdir(char *src) *dest = '\0'; return; } - if (dest > d0 + 1 && src[0] == '.' && src[1] == '.' && + if (src[0] == '.' && src[1] == '.' && (src[2] == '\0' || src[2] == '/')) { - /* remove a foo/.. combination */ - for (dest--; dest > d0 + 1 && dest[-1] != '/'; dest--); - if (dest[-1] != '/') - dest--; + if (dest > d0 + 1) { + /* remove a foo/.. combination */ + for (dest--; dest > d0 + 1 && dest[-1] != '/'; dest--); + if (dest[-1] != '/') + dest--; + } src++; while (*++src == '/'); } else if (src[0] == '.' && (src[1] == '/' || src[1] == '\0')) { diff --git a/Src/compat.c b/Src/compat.c index b1bcbc21b..53ab6b7a3 100644 --- a/Src/compat.c +++ b/Src/compat.c @@ -115,7 +115,7 @@ zgetdir(struct dirsav *d) struct stat sbuf; ino_t pino; dev_t pdev; -#ifndef __CYGWIN__ +#if !defined(__CYGWIN__) && !defined(USE_GETCWD) struct dirent *de; DIR *dir; dev_t dev; @@ -123,7 +123,7 @@ zgetdir(struct dirsav *d) int len; #endif - buf = halloc(bufsiz = PATH_MAX); + buf = zhalloc(bufsiz = PATH_MAX); pos = bufsiz - 1; buf[pos] = '\0'; strcpy(nbuf, "../"); @@ -142,7 +142,7 @@ zgetdir(struct dirsav *d) #ifdef HAVE_FCHDIR else #endif -#ifndef __CYGWIN__ +#if !defined(__CYGWIN__) && !defined(USE_GETCWD) holdintr(); for (;;) { @@ -202,7 +202,7 @@ zgetdir(struct dirsav *d) len = strlen(nbuf + 2); pos -= len; while (pos <= 1) { - char *newbuf = halloc(2*bufsiz); + char *newbuf = zhalloc(2*bufsiz); memcpy(newbuf + bufsiz, buf, bufsiz); buf = newbuf; pos += bufsiz; @@ -228,7 +228,7 @@ zgetdir(struct dirsav *d) zchdir(buf + pos + 1); noholdintr(); -#else /* __CYGWIN__ case */ +#else /* __CYGWIN__, USE_GETCWD cases */ if (!getcwd(buf, bufsiz)) { if (d) { diff --git a/Src/glob.c b/Src/glob.c index 47fa63567..738753377 100644 --- a/Src/glob.c +++ b/Src/glob.c @@ -2177,7 +2177,7 @@ get_match_ret(char *s, int b, int e, int fl, char *replstr) if (replstr) { if ((fl & SUB_GLOBAL) && repllist) { /* We are replacing the chunk, just add this to the list */ - Repldata rd = (Repldata) halloc(sizeof(*rd)); + Repldata rd = (Repldata) zhalloc(sizeof(*rd)); rd->b = b; rd->e = e; addlinknode(repllist, rd); @@ -2481,7 +2481,7 @@ getmatch(char **sp, char *pat, int fl, int n, char *replstr) i = rd->e; /* start of next chunk of *sp */ } lleft += l - i; /* final chunk from *sp */ - start = t = halloc(lleft+1); + start = t = zhalloc(lleft+1); i = 0; for (nd = firstnode(repllist); nd; incnode(nd)) { rd = (Repldata) getdata(nd); diff --git a/Src/mem.c b/Src/mem.c index 703920215..ee0f5635f 100644 --- a/Src/mem.c +++ b/Src/mem.c @@ -34,7 +34,7 @@ There are two ways to allocate memory in zsh. The first way is to call zalloc/zcalloc, which call malloc/calloc directly. It is legal to call realloc() or free() on memory allocated this way. - The second way is to call halloc/hcalloc, which allocates memory + The second way is to call zhalloc/hcalloc, which allocates memory from one of the memory pools on the heap stack. Such memory pools will automatically created when the heap allocation routines are called. To be sure that they are freed at appropriate times @@ -55,7 +55,7 @@ it will all be freed when the pool is destroyed. In fact, attempting to free this memory may result in a core dump. The pair of pointers ncalloc and alloc may point to either - zalloc & zcalloc or halloc & hcalloc; permalloc() sets them to the + zalloc & zcalloc or zhalloc & hcalloc; permalloc() sets them to the former, and heapalloc() sets them to the latter. This can be useful. For example, the dupstruct() routine duplicates a syntax tree, allocating the new memory for the tree using alloc(). If you want @@ -78,7 +78,7 @@ /**/ int useheap; -/* Current allocation pointers. ncalloc() is either zalloc() or halloc(); * +/* Current allocation pointers. ncalloc() is either zalloc() or zhalloc(); * * alloc() is either zcalloc() or hcalloc(). */ /**/ @@ -110,7 +110,7 @@ global_heapalloc(void) int luh = useheap; alloc = hcalloc; - ncalloc = halloc; + ncalloc = zhalloc; useheap = 1; return luh; } @@ -262,7 +262,7 @@ popheap(void) /**/ void * -halloc(size_t size) +zhalloc(size_t size) { Heap h; size_t n; @@ -329,7 +329,7 @@ hrealloc(char *p, size_t old, size_t new) if (old == new) return p; if (!old && !p) - return halloc(new); + return zhalloc(new); /* find the heap with p */ @@ -343,7 +343,7 @@ hrealloc(char *p, size_t old, size_t new) if (p + old < arena(h) + h->used) { if (new > old) { - char *ptr = (char *) halloc(new); + char *ptr = (char *) zhalloc(new); memcpy(ptr, p, old); #ifdef ZSH_MEM_DEBUG memset(p, 0xff, old); @@ -380,7 +380,7 @@ hrealloc(char *p, size_t old, size_t new) h->used += new - old; return p; } else { - char *t = halloc(new); + char *t = zhalloc(new); memcpy(t, p, old > new ? new : old); h->used -= old; #ifdef ZSH_MEM_DEBUG @@ -398,7 +398,7 @@ hcalloc(size_t size) { void *ptr; - ptr = halloc(size); + ptr = zhalloc(size); memset(ptr, 0, size); return ptr; } diff --git a/Src/params.c b/Src/params.c index e8182815e..eb50c0b7e 100644 --- a/Src/params.c +++ b/Src/params.c @@ -680,6 +680,7 @@ static long getarg(char **str, int *inv, Value v, int a2, long *w) { int num = 1, word = 0, rev = 0, ind = 0, down = 0, l, i, ishash; + int beg = 0, hasbeg = 0; char *s = *str, *sep = NULL, *t, sav, *d, **ta, **p, *tt; long r = 0; Comp c; @@ -731,6 +732,18 @@ getarg(char **str, int *inv, Value v, int a2, long *w) *t = sav; s = t; break; + case 'b': + hasbeg = 1; + t = get_strarg(++s); + if (!*t) + goto flagerr; + sav = *t; + *t = '\0'; + if ((beg = mathevalarg(s + 1, &d)) > 0) + beg--; + *t = sav; + s = t; + break; case 'p': escapes = 1; break; @@ -767,14 +780,15 @@ getarg(char **str, int *inv, Value v, int a2, long *w) else if (v->isarr & SCANPM_WANTVALS) *inv = 0; else { - if (ind) { - v->isarr |= SCANPM_WANTKEYS; - v->isarr &= ~SCANPM_WANTVALS; - } else if (rev) { - v->isarr |= SCANPM_WANTVALS; + if (v->isarr) { + if (ind) { + v->isarr |= SCANPM_WANTKEYS; + v->isarr &= ~SCANPM_WANTVALS; + } else if (rev) + v->isarr |= SCANPM_WANTVALS; + if (!down && ishash) + v->isarr &= ~SCANPM_MATCHMANY; } - if (!down && ishash) - v->isarr &= ~SCANPM_MATCHMANY; *inv = ind; } @@ -869,6 +883,8 @@ getarg(char **str, int *inv, Value v, int a2, long *w) tokenize(s); if ((c = parsereg(s))) { + int len; + if (v->isarr) { if (ishash) { scancomp = c; @@ -887,28 +903,43 @@ getarg(char **str, int *inv, Value v, int a2, long *w) ta = getarrvalue(v); if (!ta || !*ta) return 0; - if (down) - for (r = -1, p = ta + arrlen(ta) - 1; p >= ta; r--, p--) { - if (domatch(*p, c, 0) && !--num) - return r; - } else - for (r = 1, p = ta; *p; r++, p++) - if (domatch(*p, c, 0) && !--num) - return r; + len = arrlen(ta); + if (beg < 0) + beg += len; + if (beg >= 0 && beg < len) { + if (down) { + if (!hasbeg) + beg = len - 1; + for (r = 1 + beg, p = ta + beg; p >= ta; r--, p--) { + if (domatch(*p, c, 0) && !--num) + return r; + } + } else + for (r = 1 + beg, p = ta + beg; *p; r++, p++) + if (domatch(*p, c, 0) && !--num) + return r; + } } else if (word) { ta = sepsplit(d = s = getstrvalue(v), sep, 1); - if (down) { - for (p = ta + (r = arrlen(ta)) - 1; p >= ta; p--, r--) - if (domatch(*p, c, 0) && !--num) - break; - if (p < ta) - return 0; - } else { - for (r = 1, p = ta; *p; r++, p++) - if (domatch(*p, c, 0) && !--num) - break; - if (!*p) - return 0; + len = arrlen(ta); + if (beg < 0) + beg += len; + if (beg >= 0 && beg < len) { + if (down) { + if (!hasbeg) + beg = len - 1; + for (r = 1 + beg, p = ta + beg; p >= ta; p--, r--) + if (domatch(*p, c, 0) && !--num) + break; + if (p < ta) + return 0; + } else { + for (r = 1 + beg, p = ta + beg; *p; r++, p++) + if (domatch(*p, c, 0) && !--num) + break; + if (!*p) + return 0; + } } if (a2) r++; @@ -924,35 +955,46 @@ getarg(char **str, int *inv, Value v, int a2, long *w) d = getstrvalue(v); if (!d || !*d) return 0; - if (a2) { - if (down) - for (r = -2, t = d + strlen(d) - 1; t >= d; r--, t--) { - sav = *t; - *t = '\0'; - if (domatch(d, c, 0) && !--num) { + len = strlen(d); + if (beg < 0) + beg += len; + if (beg >= 0 && beg < len) { + if (a2) { + if (down) { + if (!hasbeg) + beg = len - 1; + for (r = beg, t = d + beg; t >= d; r--, t--) { + sav = *t; + *t = '\0'; + if (domatch(d, c, 0) && !--num) { + *t = sav; + return r; + } *t = sav; - return r; } - *t = sav; - } else - for (r = 0, t = d; *t; r++, t++) { - sav = *t; - *t = '\0'; - if (domatch(d, c, 0) && !--num) { + } else + for (r = beg, t = d + beg; *t; r++, t++) { + sav = *t; + *t = '\0'; + if (domatch(d, c, 0) && !--num) { + *t = sav; + return r; + } *t = sav; - return r; } - *t = sav; - } - } else { - if (down) - for (r = -1, t = d + strlen(d) - 1; t >= d; r--, t--) { - if (domatch(t, c, 0) && !--num) - return r; - } else - for (r = 1, t = d; *t; r++, t++) - if (domatch(t, c, 0) && !--num) - return r; + } else { + if (down) { + if (!hasbeg) + beg = len - 1; + for (r = beg + 1, t = d + beg; t >= d; r--, t--) { + if (domatch(t, c, 0) && !--num) + return r; + } + } else + for (r = beg + 1, t = d + beg; *t; r++, t++) + if (domatch(t, c, 0) && !--num) + return r; + } } return 0; } @@ -1177,7 +1219,8 @@ getstrvalue(Value v) } LASTALLOC_RETURN s; case PM_INTEGER: - convbase(s = buf, v->pm->gets.ifn(v->pm), v->pm->ct); + convbase(buf, v->pm->gets.ifn(v->pm), v->pm->ct); + s = dupstring(buf); break; case PM_SCALAR: s = v->pm->gets.cfn(v->pm); diff --git a/Src/subst.c b/Src/subst.c index 2e9b84718..6445776d1 100644 --- a/Src/subst.c +++ b/Src/subst.c @@ -529,7 +529,7 @@ dopadding(char *str, int prenum, int postnum, char *preone, char *postone, char if (lr == ls) return str; - r = ret = (char *)halloc(lr + 1); + r = ret = (char *)zhalloc(lr + 1); if (prenum) { if (postnum) { @@ -1831,7 +1831,7 @@ modify(char **str, char **ptr) tc = *tt; *tt = '\0'; nl = al + strlen(t) + strlen(copy); - ptr1 = tmp = (char *)halloc(nl + 1); + ptr1 = tmp = (char *)zhalloc(nl + 1); if (all) for (ptr2 = all; *ptr2;) *ptr1++ = *ptr2++; diff --git a/Src/system.h b/Src/system.h index 650690b51..2babafa7a 100644 --- a/Src/system.h +++ b/Src/system.h @@ -51,7 +51,7 @@ #endif #ifndef HAVE_ALLOCA -# define alloca halloc +# define alloca zhalloc #else # ifdef __GNUC__ # define alloca __builtin_alloca diff --git a/Src/utils.c b/Src/utils.c index 4ff4a91ba..d010df4e0 100644 --- a/Src/utils.c +++ b/Src/utils.c @@ -93,7 +93,7 @@ zerrnam(const char *cmd, const char *fmt, const char *str, int num) case 'l': { char *s; num = metalen(str, num); - s = halloc(num + 1); + s = zhalloc(num + 1); memcpy(s, str, num); s[num] = '\0'; nicezputs(s, stderr); @@ -2807,7 +2807,7 @@ metafy(char *buf, int len, int heap) break; case META_USEHEAP: case META_HEAPDUP: - buf = memcpy(halloc(len + meta + 1), buf, len); + buf = memcpy(zhalloc(len + meta + 1), buf, len); break; case META_STATIC: #ifdef DEBUG @@ -3372,7 +3372,7 @@ getkeystring(char *s, int *len, int fromwhere, int *misc) int meta = 0, control = 0; if (fromwhere != 4) - buf = halloc(strlen(s) + 1); + buf = zhalloc(strlen(s) + 1); else { buf = s; s += 2; diff --git a/Src/zsh.export b/Src/zsh.export index d31e7902e..dcee683f6 100644 --- a/Src/zsh.export +++ b/Src/zsh.export @@ -5,6 +5,8 @@ addconddefs addedx addhashnode addwrapper +arrvargetfn +arrvarsetfn aliastab alloc_stackp appstr @@ -69,6 +71,7 @@ getaparam gethashnode gethashnode2 gethparam +getintvalue getiparam getkeystring getlinknode @@ -82,7 +85,6 @@ global_heapalloc global_permalloc globlist gotwordptr -halloc hasam hashcmd hasher @@ -135,6 +137,7 @@ ncalloc new_heaps newhashtable newlinklist +newparamtable nicechar nicezputs niceztrdup @@ -250,6 +253,7 @@ zexit zfree zgetdir zgetenv +zhalloc zjoin zleactive zleparse diff --git a/acconfig.h b/acconfig.h index 506441635..bcd111c8c 100644 --- a/acconfig.h +++ b/acconfig.h @@ -73,6 +73,9 @@ /* Define to 1 if you have RFS superroot directory. */ #undef HAVE_SUPERROOT +/* Define to 1 if you need to use the native getcwd */ +#undef USE_GETCWD + /* Define to the path of the /dev/fd filesystem */ #undef PATH_DEV_FD diff --git a/config.sub b/config.sub index 7e9735ea7..00bea6e6a 100755 --- a/config.sub +++ b/config.sub @@ -1,6 +1,6 @@ #! /bin/sh # Configuration validation subroutine script, version 1.1. -# Copyright (C) 1991, 92, 93, 94, 95, 1996 Free Software Foundation, Inc. +# Copyright (C) 1991, 92-97, 1998 Free Software Foundation, Inc. # This file is (in principle) common to ALL GNU software. # The presence of a machine in this file suggests that SOME GNU software # can handle that machine. It does not imply ALL GNU software can. @@ -149,19 +149,20 @@ esac case $basic_machine in # Recognize the basic CPU types without company name. # Some are omitted here because they have special meanings below. - tahoe | i860 | m68k | m68000 | m88k | ns32k | arm \ - | arme[lb] | pyramid \ - | tron | a29k | 580 | i960 | h8300 | hppa | hppa1.0 | hppa1.1 \ - | alpha | we32k | ns16k | clipper | i370 | sh \ - | powerpc | powerpcle | 1750a | dsp16xx | mips64 | mipsel \ - | pdp11 | mips64el | mips64orion | mips64orionel \ - | sparc | sparclet | sparclite | sparc64) + tahoe | i860 | m32r | m68k | m68000 | m88k | ns32k | arc | arm \ + | arme[lb] | pyramid | mn10200 | mn10300 | tron | a29k \ + | 580 | i960 | h8300 | hppa | hppa1.0 | hppa1.1 | hppa2.0 \ + | alpha | alphaev5 | alphaev56 | we32k | ns16k | clipper \ + | i370 | sh | powerpc | powerpcle | 1750a | dsp16xx | pdp11 \ + | mips64 | mipsel | mips64el | mips64orion | mips64orionel \ + | mipstx39 | mipstx39el \ + | sparc | sparclet | sparclite | sparc64 | v850) basic_machine=$basic_machine-unknown ;; # We use `pc' rather than `unknown' # because (1) that's what they normally are, and # (2) the word "unknown" tends to confuse beginning users. - i[3456]86) + i[34567]86) basic_machine=$basic_machine-pc ;; # Object if more than one company name word. @@ -170,14 +171,18 @@ case $basic_machine in exit 1 ;; # Recognize the basic CPU types with company name. - vax-* | tahoe-* | i[3456]86-* | i860-* | m68k-* | m68000-* | m88k-* \ - | sparc-* | ns32k-* | fx80-* | arm-* | c[123]* \ - | mips-* | pyramid-* | tron-* | a29k-* | romp-* | rs6000-* | power-* \ - | none-* | 580-* | cray2-* | h8300-* | i960-* | xmp-* | ymp-* \ - | hppa-* | hppa1.0-* | hppa1.1-* | alpha-* | we32k-* | cydra-* | ns16k-* \ - | pn-* | np1-* | xps100-* | clipper-* | orion-* | sparclite-* \ - | pdp11-* | sh-* | powerpc-* | powerpcle-* | sparc64-* | mips64-* | mipsel-* \ - | mips64el-* | mips64orion-* | mips64orionel-* | f301-*) + vax-* | tahoe-* | i[34567]86-* | i860-* | m32r-* | m68k-* | m68000-* \ + | m88k-* | sparc-* | ns32k-* | fx80-* | arc-* | arm-* | c[123]* \ + | mips-* | pyramid-* | tron-* | a29k-* | romp-* | rs6000-* \ + | power-* | none-* | 580-* | cray2-* | h8300-* | i960-* \ + | xmp-* | ymp-* | hppa-* | hppa1.0-* | hppa1.1-* | hppa2.0-* \ + | alpha-* | alphaev5-* | alphaev56-* | we32k-* | cydra-* \ + | ns16k-* | pn-* | np1-* | xps100-* | clipper-* | orion-* \ + | sparclite-* | pdp11-* | sh-* | powerpc-* | powerpcle-* \ + | sparc64-* | mips64-* | mipsel-* \ + | mips64el-* | mips64orion-* | mips64orionel-* \ + | mipstx39-* | mipstx39el-* \ + | f301-*) ;; # Recognize the various machine names and aliases which stand # for a CPU type and a company and sometimes even an OS. @@ -204,9 +209,9 @@ case $basic_machine in amiga | amiga-*) basic_machine=m68k-cbm ;; - amigados) + amigaos | amigados) basic_machine=m68k-cbm - os=-amigados + os=-amigaos ;; amigaunix | amix) basic_machine=m68k-cbm @@ -345,19 +350,19 @@ case $basic_machine in os=-mvs ;; # I'm not sure what "Sysv32" means. Should this be sysv3.2? - i[3456]86v32) + i[34567]86v32) basic_machine=`echo $1 | sed -e 's/86.*/86-pc/'` os=-sysv32 ;; - i[3456]86v4*) + i[34567]86v4*) basic_machine=`echo $1 | sed -e 's/86.*/86-pc/'` os=-sysv4 ;; - i[3456]86v) + i[34567]86v) basic_machine=`echo $1 | sed -e 's/86.*/86-pc/'` os=-sysv ;; - i[3456]86sol2) + i[34567]86sol2) basic_machine=`echo $1 | sed -e 's/86.*/86-pc/'` os=-solaris2 ;; @@ -389,6 +394,14 @@ case $basic_machine in miniframe) basic_machine=m68000-convergent ;; + mipsel*-linux*) + basic_machine=mipsel-unknown + os=-linux-gnu + ;; + mips*-linux*) + basic_machine=mips-unknown + os=-linux-gnu + ;; mips3*-*) basic_machine=`echo $basic_machine | sed -e 's/mips3/mips64/'` ;; @@ -456,25 +469,23 @@ case $basic_machine in pc532 | pc532-*) basic_machine=ns32k-pc532 ;; - pentium | p5) - basic_machine=i586-intel + pentium | p5 | k5 | nexen) + basic_machine=i586-pc + ;; + pentiumpro | p6 | k6 | 6x86) + basic_machine=i686-pc ;; - pentiumpro | p6) - basic_machine=i686-intel + pentiumii | pentium2) + basic_machine=i786-pc ;; - pentium-* | p5-*) + pentium-* | p5-* | k5-* | nexen-*) basic_machine=i586-`echo $basic_machine | sed 's/^[^-]*-//'` ;; - pentiumpro-* | p6-*) + pentiumpro-* | p6-* | k6-* | 6x86-*) basic_machine=i686-`echo $basic_machine | sed 's/^[^-]*-//'` ;; - k5) - # We don't have specific support for AMD's K5 yet, so just call it a Pentium - basic_machine=i586-amd - ;; - nexen) - # We don't have specific support for Nexgen yet, so just call it a Pentium - basic_machine=i586-nexgen + pentiumii-* | pentium2-*) + basic_machine=i786-`echo $basic_machine | sed 's/^[^-]*-//'` ;; pn) basic_machine=pn-gould @@ -558,6 +569,12 @@ case $basic_machine in basic_machine=i386-sequent os=-dynix ;; + tx39) + basic_machine=mipstx39-unknown + ;; + tx39el) + basic_machine=mipstx39el-unknown + ;; tower | tower-32) basic_machine=m68k-ncr ;; @@ -577,7 +594,7 @@ case $basic_machine in basic_machine=vax-dec os=-vms ;; - vpp*|vx|vx-*) + vpp*|vx|vx-*) basic_machine=f301-fujitsu ;; vxworks960) @@ -607,7 +624,11 @@ case $basic_machine in # Here we handle the default manufacturer of certain CPU types. It is in # some cases the only manufacturer, in others, it is the most popular. mips) - basic_machine=mips-mips + if [ x$os = x-linux-gnu ]; then + basic_machine=mips-unknown + else + basic_machine=mips-mips + fi ;; romp) basic_machine=romp-ibm @@ -668,9 +689,12 @@ case $os in -solaris) os=-solaris2 ;; - -unixware* | svr4*) + -svr4*) os=-sysv4 ;; + -unixware*) + os=-sysv4.2uw + ;; -gnu/linux*) os=`echo $os | sed -e 's|gnu/linux|linux-gnu|'` ;; @@ -681,17 +705,21 @@ case $os in -gnu* | -bsd* | -mach* | -minix* | -genix* | -ultrix* | -irix* \ | -*vms* | -sco* | -esix* | -isc* | -aix* | -sunos | -sunos[34]*\ | -hpux* | -unos* | -osf* | -luna* | -dgux* | -solaris* | -sym* \ - | -amigados* | -msdos* | -newsos* | -unicos* | -aof* | -aos* \ + | -amigaos* | -amigados* | -msdos* | -newsos* | -unicos* | -aof* \ + | -aos* \ | -nindy* | -vxsim* | -vxworks* | -ebmon* | -hms* | -mvs* \ | -clix* | -riscos* | -uniplus* | -iris* | -rtu* | -xenix* \ | -hiux* | -386bsd* | -netbsd* | -openbsd* | -freebsd* | -riscix* \ | -lynxos* | -bosx* | -nextstep* | -cxux* | -aout* | -elf* \ | -ptx* | -coff* | -ecoff* | -winnt* | -domain* | -vsta* \ | -udi* | -eabi* | -lites* | -ieee* | -go32* | -aux* \ - | -cygwin32* | -pe* | -psos* | -moss* | -proelf* | -rtems* \ - | -linux* | -uxpv* | -rhapsody* ) + | -cygwin* | -pe* | -psos* | -moss* | -proelf* | -rtems* \ + | -mingw32* | -linux-gnu* | -uxpv* | -beos*) # Remember, each alternative MUST END IN *, to match a version number. ;; + -linux*) + os=`echo $os | sed -e 's|linux|linux-gnu|'` + ;; -sunos5*) os=`echo $os | sed -e 's|sunos5|solaris2|'` ;; @@ -799,6 +827,9 @@ case $basic_machine in sparc-* | *-sun) os=-sunos4.1.1 ;; + *-be) + os=-beos + ;; *-ibm) os=-aix ;; @@ -812,7 +843,7 @@ case $basic_machine in os=-sysv ;; *-cbm) - os=-amigados + os=-amigaos ;; *-dg) os=-dgux diff --git a/configure.in b/configure.in index dd6bfee4b..5cfaec326 100644 --- a/configure.in +++ b/configure.in @@ -618,12 +618,6 @@ zsh_STRUCT_MEMBER([ #endif ], struct direct, d_stat) -dnl --------------- -dnl CHECK FUNCTIONS -dnl --------------- -AC_FUNC_GETPGRP -AC_FUNC_STRCOLL - dnl need to integrate this function dnl AC_FUNC_STRFTIME @@ -633,7 +627,22 @@ AC_CHECK_FUNCS(memcpy memmove \ sigblock sigsetmask sigrelse sighold killpg sigaction getrlimit \ sigprocmask setuid seteuid setreuid setresuid setsid strerror \ nis_list initgroups fchdir cap_get_proc readlink nice \ - getgrgid getgrnam getpwent getpwnam getpwuid) + getgrgid getgrnam getpwent getpwnam getpwuid setpgrp) + +dnl --------------- +dnl CHECK FUNCTIONS +dnl --------------- +if test $ac_cv_func_setpgrp = yes; then + AC_FUNC_GETPGRP +else + dnl If there is no setpgrp, the test for getpgrp(void) will fail + dnl because the program will not compile. However, in that case + dnl we can be reasonably confident we are not dealing with a + dnl Berkeleyesque system, so assume getpgrp does take void. + ac_cv_func_getpgrp_void=yes + AC_DEFINE(GETPGRP_VOID) +fi +AC_FUNC_STRCOLL if test $dynamic = yes; then AC_CHECK_FUNCS(dlopen dlerror dlsym dlclose load loadquery loadbind unload \ @@ -824,6 +833,17 @@ if test $zsh_cv_sys_superroot = yes; then AC_DEFINE(HAVE_SUPERROOT) fi +dnl CHECK FOR SYSTEMS REQUIRING GETCWD +AC_CACHE_CHECK(whether we should use the native getcwd, +zsh_cv_use_getcwd, +[case "${host_cpu}-${host_vendor}-${host_os}" in + *QNX*) zsh_cv_use_getcwd=no ;; + *) zsh_cv_use_getcwd=yes ;; + esac]) +if test $zsh_cv_use_getcwd = yes; then + AC_DEFINE(USE_GETCWD) +fi + dnl ------------- dnl CHECK FOR NIS dnl ------------- diff --git a/patchlist.txt b/patchlist.txt index 0497dee80..3d76dd023 100644 --- a/patchlist.txt +++ b/patchlist.txt @@ -562,3 +562,104 @@ Matt: 5553: under _WIN32, .exe suffix is optional for commands pws: unposted: Functions/Completion moved to Completion; subdirectories Core, Base, Builtins, User, Commands created; Completion/README created. + + pws-11 + +pws: 5557: configure.in for making sure signals really are defined in the +file found. This was in pws-10, but the patch didn't appear on the list +for four days. + +Larry P. Schrof: 5550: last -> previous in history documentation + +Sven: 5560: subscripting fixes in params.c: flags for scalars and +converting integer AA element to string + +pws: 5561: attempted (untested) fix for QNX4 compilation; halloc() is now +zhalloc(). (By private email from probin@qnx.co.uk, it seems the QNX +problems are more considerable with 3.1.5.) + +Sven: 5564, 5577, 5579: massive new completion reworking with $words, +$compstate, etc., etc. + +Sven: 5565, 5576: $NUMERIC gives the numeric argument in a zle widget + +Sven: 5566: $foo[(b..i)] starts searching $foo for for + at + +Sven: 5571: Functions/Builtins/_cd tests if $cdpath is set + +Sven: 5574, 5578: Completion/README notes + +Sven: 5582: _path_files will expand /u/ -> /usr/ even if /u exists if +nothing later on would match otherwise (got that?) + +pws: 5583: post-patch restructuring of _mh, _zftp, _most_recent_file. + +Sven: 5586: addmatch fix (old completion wasn't working) + +Sven: 5588: fix _most_recent_file idiocy + +Sven: 5590: compadd -p, -s and -P fixes + +Sven: 5593: _path_files -w + +Matt: 5596: Makefile dependencies for module compilation + +pws; 5597: Use separate file mymods.conf for your own builtin modules +rather than the automatically generated modules-bltin. + +Sven: 5598: a neater way of handling compadd -p/-P + +Sven: 5599: _comp_parts, _path_files tweaks + +Sven: 5601: compstate[exact_string] and compstate[total_matchers] + +pws: 5602: _tar + +Sven: 5603: compstat[pattern_match] + +Sven: 5604: approximate completion. (this is it. every other shell is out +of the game.) + +Sven: 5605: explanation listing fix + +Sven: 5613: copy scalar variable used for compgen -y + +Bart: 5614: Completion/Base/_match_test works out of the box + +Sven: 5620: fix for completion inside expansible braces + +Sven: 5621: manual for nmatches and matcher + +Sven: 5622: zshcompwid manual: clarifications + +Sven: 5623: -X strings with compadd were mishandled + +Sven: 5624: CCORIG required to be offered original string when correcting +using COMPCORRECT + +pws: 5628: _builtin, _cd, _most_recent_file + +Sven: 5629: approximate correction patches + +Sven: 5631: compilation warnings + +Sven: 5637: mustuseheap check in complistflags + +Sven: 5640: _multi_parts, _path_files, _tar + +Andrej: 5650: more tricks with _configure + +Sven: 5651: widespread completion fixes + +Sven: 5659: globcomplete changes + +Sven: 5662: / following brace parameter + +Sven: 5663: compctl -i _completion_function + +Sven: 5665: return values from completion functions + +Sven: 5666: calling inststrlen() with a null string + +pws: from autoconf 2.13: new config.sub -- cgit 1.4.1