Zsh Mailing List Archive
Messages sorted by:
Reverse Date,
Date,
Thread,
Author
[PATCH] Make _expand handle aliases (was Re: [PATCH] Make _expand_alias more usable as a completer)
On Wed, Jul 28, 2021 at 6:23 AM Bart Schaefer <schaefer@xxxxxxxxxxxxxxxx> wrote:
>
> I think it's actually a bit weird to allow _expand_alias to work as a
> completer at all, because the completion system generally functions
> very badly when the matches do not consist of single words, and
> aliases don't usually have one-word replacements. As soon as you
> introduce something that contains spaces, completion gets very
> confused (unless you force it directly into menu completion or
> selection); if (otherwise) you attempt to press TAB twice to enter
> menu completion, it'll instead start a new completion based on the
> word after the rightmost space that is still to the left of the
> cursor. This is especially true when using compadd -U.
>
> I suspect this may be where Oliver's tests and Marlon's attempt to
> reproduce, went astray from one another. In any case, I'm fairly sure
> this is the reason that _expand_alias (before the patch) does not
> allow other completers to run, and similarly it's why the user is
> admonished to place _expand before _complete in the zstyle.
>
> Looking independently at the two questions, my feeling is I'd avoid
> the patch as-is, but it wouldn't be unreasonable for _expand to handle
> aliases (under control of a zstyle).
Alright, here's a new patch, which moves the alias expansion code from
_expand_alias to _expand (and refactors it) and deprecates
_expand_alias's use as a completer. I also updated the documentation
and added tests.
Note that I reused the zstyle names from _expand_alias in _alias. I
think their names are less than optimal in _expand, but renaming them
would break people's existing zstyle config for _expand_alias.
From 7467abb482824650913636340844919be4bcf212 Mon Sep 17 00:00:00 2001
From: Marlon Richert <marlonrichert@xxxxxxxxxxxxxxxxxxxxxxxx>
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<TAB>) 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)
Messages sorted by:
Reverse Date,
Date,
Thread,
Author