-
Notifications
You must be signed in to change notification settings - Fork 2.3k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Improve array handling in alias completion #2293
base: master
Are you sure you want to change the base?
Improve array handling in alias completion #2293
Conversation
The old approach would cause the alias_arg_words array to be incorrectly converted to a string leading to a command like git branch -D being converted into ('git' 'branch -D') which was incorrect. The new approach keeps each argument separate leading to ('git' 'branch' '-D') which produces correct completion.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
is it necessary to go through this extra printf? I would think just switching [*] to [@] might have worked too? please try to do this a bit cleaner maybe, or at least make like 84 use a local var and calculate it down by the other line. the distance between the two doesn't make sense to me, unless I missed something.
@seefood The For example:
That outputs
Notice that the I can definitely look into cleaning up how this is done though! |
The CI failure does not look like it is related to my changes. I'm seeing commits in master that have the same issues where some tests appears to not be running. |
@@ -89,7 +93,7 @@ function _bash-it-component-completion-callback-on-init-aliases() { | |||
prec_word=\${prec_word#* } | |||
fi | |||
(( COMP_CWORD += ${#alias_arg_words[@]} )) | |||
COMP_WORDS=(\"$alias_cmd\" \"${alias_arg_words[*]}\" \"\${COMP_WORDS[@]:1}\") | |||
COMP_WORDS=(\"$alias_cmd\" $(printf "'%s' " "${alias_arg_words[@]}") \"\${COMP_WORDS[@]:1}\") |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This still fails when alias_arg_words[@]
contains '
. You can use %q
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Did this in 15ec29d
Good call. Using %q
does correctly escape things better.
I also had to switch to wrapping the %q
output in double quotes rather than single quotes, which should be fine since everything is escaped now. If an alias contained single quotes, like the bash-it reload_completion
alias does, this would produce invalid output. That is due to the complexity of escaping single quotes in single quotes and due to how that works, I believe it is impossible to make a single array entry that contains single quotes and is wrapped in single quotes.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I also had to switch to wrapping the
%q
output in double quotes rather than single quotes, which should be fine since everything is escaped now.
No, it doesn't work. %q
already quotes everything needed. If you further quote it within '...'
or "..."
, the special characters for quoting is quoted and then remain in the final results.
$ a=('a b c')
$ eval "b=($(printf "\"%q\" " "${a[@]}"))"
$ declare -p a b
declare -a a=([0]="a b c")
declare -a b=([0]="a\\ b\\ c")
You should use %q
(but not "%q"
).
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
You are correct. My concern had been about a case like
myArray=("one two")
printf "%q " "${myArray[@]}"
That the print would produce one two
when it needed to be "one two"
. What %q
actually does in a case like that is it escapes the space, which I didn't even think was possible, to produce one\ two
which works just fine.
I removed the quotes in 3e9a033, thanks for teaching me something new!
This correctly quotes and escapes characters to be shell safe. This also requires wrapping the result in rather than '' to avoid problems with escaping single quotes.
@@ -87,9 +91,9 @@ function _bash-it-component-completion-callback-on-init-aliases() { | |||
if [[ \$COMP_LINE == \"\$prec_word \$compl_word\" ]]; then | |||
prec_word='$alias_cmd $alias_args' | |||
prec_word=\${prec_word#* } | |||
fi | |||
fi: |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
sorry, but this seems like a typo. I don't recognise this syntax nor could I make it work in a local test...
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yep, definitely a typo. Removed in ec9d229
This causes incorrect escaping of characters. %q handles all cases that need to be handled including mulitple words in one array entry
Description
I was seeing issues where certain aliases do not complete as expected.
For example, my
alias gbD='git branch -D'
alias should provide completions to local branches only, and it does when run without an alias. However when running completion on the alias, I get all the branches which appears to be the git default completion response.I tracked this down to an issue where an array was being incorrectly handled. The old handling caused this result,
COMP_WORDS=[‘git’, ‘branch -D’, 'ma']
(length 3) wherebranch
and-D
were combined into a single entry. This produces the incorrect behavior. By changing the array to string handling to better maintain individual arguments the new result isCOMP_WORDS=[‘git’, ‘branch’ ,‘-D’, 'ma']
(length 4) which correctly keepsbranch
and-D
apart.Motivation and Context
This improves alias completions to act more correctly.
How Has This Been Tested?
I have been unable to create a unit test that is able to call the alias completion function. I have tested this manually on my machine and it works as expected.
An easy way to manually test this is to add the
alias biea='bash-it enable alias'
and load bash-it with the bash-it completion enabled. Without my fix the complete for this alias are the base level bash-it commands such as doctor, version etc. With my change the output is the aliases that can be enabled as would be expected.Screenshots (if appropriate):
N/A
Types of changes
Checklist:
clean_files.txt
and formatted it usinglint_clean_files.sh
.