From 7467abb482824650913636340844919be4bcf212 Mon Sep 17 00:00:00 2001 From: Marlon Richert Date: Sun, 1 Aug 2021 21:40:01 +0300 Subject: [PATCH] Make _expand handle aliases This deprecates _expand_alias's use as a completer. --- Completion/Base/Completer/_expand | 74 ++++++++++++++++++++++++- Completion/Base/Completer/_expand_alias | 70 +++-------------------- Doc/Zsh/compsys.yo | 62 +++++++++------------ Test/Y01completion.ztst | 16 +++++- 4 files changed, 120 insertions(+), 102 deletions(-) diff --git a/Completion/Base/Completer/_expand b/Completion/Base/Completer/_expand index 86b4ac6e4..7a24f8aa1 100644 --- a/Completion/Base/Completer/_expand +++ b/Completion/Base/Completer/_expand @@ -11,11 +11,12 @@ setopt localoptions nonomatch [[ _matcher_num -gt 1 ]] && return 1 -local exp word sort expr expl subd pref suf=" " force opt asp tmp opre pre epre -local continue=0 +local -a exp subd tmpa match mbegin mend +local -i continue=0 +local word sort expl pref suf=' ' force opt asp tmp opre pre epre (( $# )) && - while getopts gsco opt; do + while getopts agsco opt; do force="$force$opt" done @@ -25,6 +26,73 @@ else word="$IPREFIX$PREFIX$SUFFIX$ISUFFIX" fi +# Alias expansion: +() { + + if { (( CURRENT == 1 )) && zstyle -T ":completion:${curcontext}:" regular } || + zstyle -t ":completion:${curcontext}:" regular always; then + exp=( $aliases[$word] ) + if [[ -n "$exp" ]]; then + # If the first shell word in the expansion is the same as the alias, then + # escape it, so it doesn't get re-expanded on execution. + [[ "${${(z)exp}[1]}" = "$word" ]] && + exp=( "${(S)exp/#(#b)(*)$word/$match[1]\\$word}" ) + return 0 + fi + fi + + if zstyle -T ":completion:${curcontext}:" global; then + exp=( $galiases[$word] ) + if [[ -n "$exp" ]]; then + # Escape all occurences of the global alias in its expansion, so these + # don't get re-expanded on execution. + tmp="$exp" + tmpa=( ${(z)tmp} ) + exp=() + while (( ${#tmpa[@]} )); do + exp[1]+="${(M)tmp#*$tmpa[1]}" + tmp="${tmp#*$tmpa[1]}" + [[ "$tmpa[1]" == "$word" ]] && + exp[1]="${exp/%$word/\\$word}" + shift tmpa + done + exp[1]+="$tmp" + tmp= + return 0 + fi + fi + + if zstyle -t ":completion:${curcontext}:" disabled; then + exp=( $dis_aliases[$word] ) + [[ -n "$exp" ]] && + return + fi + + if zstyle -T ":completion:${curcontext}:" global && + zstyle -t ":completion:${curcontext}:" disabled; then + exp=( $dis_galiases[$word] ) + [[ -n "$exp" ]] && + return + fi + + return 1 + +} && { + zstyle -T ":completion:${curcontext}:" add-space true yes on 1 && + tmpa=( -S ' ' ) + _description expansions expl expansions "o:$word" + + if compadd "$expl[@]" -UQ $tmpa[@] -- $exp; then + ! zstyle -t ":completion:${curcontext}:" accept-exact continue + return + fi + +} + +# If we've been called with `-a`, then don't expand anything else than aliases. +[[ "$force" = *a* ]] && + return 1 + [[ "$word" = *\$(|\{[^\}]#) || ( "$word" = *\$[a-zA-Z0-9_]## && $+parameters[${word##*\$}] -eq 0 ) ]] && return 1 diff --git a/Completion/Base/Completer/_expand_alias b/Completion/Base/Completer/_expand_alias index 8240e4162..c588dfadb 100644 --- a/Completion/Base/Completer/_expand_alias +++ b/Completion/Base/Completer/_expand_alias @@ -1,67 +1,15 @@ -#compdef -K _expand_alias complete-word \C-xa +#compdef -K _expand_alias complete-word \C-Xa -local word expl tmp pre sel what -local -a tmpa suf - -eval "$_comp_setup" - -if [[ -n $funcstack[2] ]]; then - if [[ "$funcstack[2]" = _prefix ]]; then - word="$IPREFIX$PREFIX$SUFFIX" - else - word="$IPREFIX$PREFIX$SUFFIX$ISUFFIX" - fi - pre=() +if (( ${funcstack[(I)_main_complete]} )); then + compstate[to_end]=match + _main_complete _expand_alias else - local curcontext="$curcontext" - if [[ -z "$curcontext" ]]; then - curcontext="expand-alias-word:::" - else - curcontext="expand-alias-word:${curcontext#*:}" + if _expand -a; then + compstate[insert]=1 + return fi - word="$IPREFIX$PREFIX$SUFFIX$ISUFFIX" - pre=(_main_complete - aliases) -fi - -zstyle -s ":completion:${curcontext}:" regular tmp || tmp=yes -case $tmp in -always) sel=r;; -yes|1|true|on) [[ CURRENT -eq 1 ]] && sel=r;; -esac -zstyle -T ":completion:${curcontext}:" global && sel="g$sel" -zstyle -t ":completion:${curcontext}:" disabled && sel="${sel}${(U)sel}" - -tmp= -[[ $sel = *r* ]] && tmp=$aliases[$word] -[[ -z $tmp && $sel = *g* ]] && tmp=$galiases[$word] -[[ -z $tmp && $sel = *R* ]] && tmp=$dis_aliases[$word] -[[ -z $tmp && $sel = *G* ]] && tmp=$dis_galiases[$word] - -if [[ -n $tmp ]]; then - # We used to remove the quoting from the value in the parameter. - # That was probably just an oversight: an alias is always replaced - # literally. - tmp=${tmp%%[[:blank:]]##} - if [[ $tmp[1] = [[:alnum:]_] ]]; then - tmpa=(${(z)tmp}) - if [[ $tmpa[1] = $word && $tmp = $aliases[$word] ]]; then - # This is an active regular alias and the first word in the result - # is the same as what was on the line already. Quote it so - # that it doesn't get reexanded on execution. - # - # Strictly we also need to check if the original word matches - # a later word in the expansion and the previous words are - # all aliases where the expansion ends in " ", but I'm - # too lazy. - tmp="\\$tmp" - fi - fi - zstyle -T ":completion:${curcontext}:" add-space || suf=( -S '' ) - $pre _wanted aliases expl alias compadd -UQ "$suf[@]" -- ${tmp%%[[:blank:]]##} -elif (( $#pre )) && zstyle -t ":completion:${curcontext}:" complete; then - $pre _aliases -s "$sel" -S '' -else - return 1 + zstyle -t ":completion:${curcontext}:" complete && + _main_complete - expand-alias _aliases fi diff --git a/Doc/Zsh/compsys.yo b/Doc/Zsh/compsys.yo index 89b918d60..88a368608 100644 --- a/Doc/Zsh/compsys.yo +++ b/Doc/Zsh/compsys.yo @@ -1179,10 +1179,10 @@ style (see below) to `false'. ) kindex(add-space, completion style) item(tt(add-space))( -This style is used by the tt(_expand) completer. If it is `true' (the -default), a space will be inserted after all words resulting from the -expansion, or a slash in the case of directory names. If the value -is `tt(file)', the completer will only add a space +This style is used by the tt(_expand) completer and the tt(_expand_alias) +bindable command. If it is `true' (the default), a space will be inserted +after all words resulting from the expansion, or a slash in the case of +directory names. If the value is `tt(file)', the completer will only add a space to names of existing files. Either a boolean `true' or the value `tt(file)' may be combined with `tt(subst)', in which case the completer will not add a space to words generated from the expansion of a @@ -1295,10 +1295,9 @@ the two strings `tt(start)' and `tt(stop)'. ) kindex(complete, completion style) item(tt(complete))( -This is used by the tt(_expand_alias) function when invoked as a -bindable command. If set to `true' and the word on the command -line is not the name of an alias, matching alias names will be -completed. +When the tt(_expand_alias) bindable command is invoked, if tt(complete) is set +to `true' and the word on the command line is not the name of an alias, +matching alias names will be completed. ) kindex(complete-options, completion style) item(tt(complete-options))( @@ -1362,8 +1361,8 @@ may be empty to force a delimiter to be typed. ) kindex(disabled, completion style) item(tt(disabled))( -If this is set to `true', the tt(_expand_alias) completer and bindable -command will try to expand disabled aliases, too. The default is +If this is set to `true', the tt(_expand) completer and the tt(_expand_alias) +bindable command will try to expand disabled aliases, too. The default is `false'. ) kindex(domains, completion style) @@ -1656,8 +1655,8 @@ style) or else the original string from the line. ) kindex(global, completion style) item(tt(global))( -If this is set to `true' (the default), the tt(_expand_alias) -completer and bindable command will try to expand global aliases. +If this is set to `true' (the default), the tt(_expand) completer and the +tt(_expand_alias) bindable command will try to expand global aliases. ) kindex(group-name, completion style) item(tt(group-name))( @@ -2480,11 +2479,11 @@ tt(zle_tr) can be completed to tt(Zle/zle_tricky.c). ) kindex(regular, completion style) item(tt(regular))( -This style is used by the tt(_expand_alias) completer and bindable -command. If set to `true' (the default), regular aliases will be -expanded but only in command position. If it is set to `false', -regular aliases will never be expanded. If it is set to `tt(always)', -regular aliases will be expanded even if not in command position. +This style is used by the tt(_expand) completer and the tt(_expand_alias) +bindable command. If set to `true' (the default), regular aliases will be +expanded but only in command position. If it is set to `false', regular +aliases will never be expanded. If it is set to `tt(always)', regular aliases +will be expanded even if not in command position. ) kindex(rehash, completion style) item(tt(rehash))( @@ -3173,17 +3172,8 @@ tt(glob) and tt(subst-globs-only) styles. It is also possible to call tt(_expand) as a function, in which case the different modes may be selected with options: tt(-s) for -tt(substitute), tt(-g) for tt(glob) and tt(-o) for tt(subst-globs-only). -) -findex(_expand_alias) -item(tt(_expand_alias))( -If the word the cursor is on is an alias, it is expanded and no other -completers are called. The types of aliases which are to be expanded can -be controlled with the styles tt(regular), tt(global) and tt(disabled). - -This function is also a bindable command, see -ifzman(the section `Bindable Commands' below)\ -ifnzman(noderef(Bindable Commands)). +tt(substitute), tt(-g) for tt(glob) and tt(-o) for tt(subst-globs-only). +Alternatively, if called with tt(-a), tt(_expand) will do alias expansion only. ) findex(_extensions) item(tt(_extensions))( @@ -3406,17 +3396,15 @@ then calls the tt(_correct) completer. ) findex(_expand_alias (^Xa)) item(tt(_expand_alias) (tt(^Xa)))( -This function can be used as a completer and as a bindable command. -It expands the word the cursor is on if it is an alias. The types of -alias expanded can be controlled with the styles tt(regular), tt(global) +This function expands the word the cursor is on if it is an alias. The types +of alias expanded can be controlled with the styles tt(regular), tt(global) and tt(disabled). -When used as a bindable command there is one additional feature that -can be selected by setting the tt(complete) style to `true'. In this -case, if the word is not the name of an alias, tt(_expand_alias) tries -to complete the word to a full alias name without expanding it. It -leaves the cursor directly after the completed word so that invoking -tt(_expand_alias) once more will expand the now-complete alias name. +Additionally, if the tt(complete) style is set to `true' and the word is not +the name of an alias, then tt(_expand_alias) tries to complete the word to a +full alias name without expanding it. It leaves the cursor directly after the +completed word so that invoking tt(_expand_alias) once more will expand the +now-complete alias name. ) findex(_expand_word (^Xe)) item(tt(_expand_word) (tt(^Xe)))( diff --git a/Test/Y01completion.ztst b/Test/Y01completion.ztst index 882a0adc4..ed7f6738d 100644 --- a/Test/Y01completion.ztst +++ b/Test/Y01completion.ztst @@ -44,8 +44,22 @@ >line: {: dir1/}{} >line: {: dir2/}{} + comptesteval "alias \*=' * * \$\$ tst'" + comptesteval "alias -g '\$\$'=' * \$\$ \$\$ tst'" + comptest $' *\C-D' +0:_expand substitutes regular aliases and escapes them, if necessary +>DESCRIPTION:{expansions} +>NO:{ \* * $$ tst} + + comptest $': $$\C-D' +0:_expand can substitutes global aliases and escapes them, if necessary +>DESCRIPTION:{expansions} +>NO:{ * \$$ \$$ tst} + + comptesteval "zstyle '*' regular no" + comptesteval "zstyle '*' global no" comptest $': *\t\t\t\t\t\t' -0:_expand shows file types +0:_expand shows file types (and does not substitute aliases, when this is disabled) >line: {: dir1/}{} >DESCRIPTION:{expansions} >DI:{dir1} -- 2.30.1 (Apple Git-130)