I am writing a bash tab completion file for a utility that some times requires full URLs on the form: protocol://host:port
. This contains two colons, which have proven to be problematic for tab completion. This is because the colons are treated as word breaks. I have read that I should not change COMP_WORDBREAKS
directly, so I want to use the _get_comp_words_by_ref
and __ltrim_colon_completions
as suggested here: How to reset COMP_WORDBREAKS without effecting other completion script?
This works for a single colon, but the second colon causes a small problem as demonstrated in this minimal example:
This example shows the problem. It occurs for any number of colons in the suggestions.
[root@2e3e8853cc0c /]# cat /etc/bash_completion.d/foo
_foo()
{
local cur
COMPREPLY=()
_get_comp_words_by_ref -n : -c cur
COMPREPLY=( $(compgen -W "http://host:1234/aaa http://host:1234/bbb http://host:1234/ccc" -- ${cur}) )
__ltrim_colon_completions "$cur"
return 0
}
complete -F _foo foo
Hitting tab after foo
successfully completes the common part. Hitting tab twice after that, yields the following suggestions:
[root@2e3e8853cc0c /]# foo http://host:1234/
1234/aaa 1234/bbb 1234/ccc
The desired result is ofcourse:
[root@2e3e8853cc0c /]# foo http://host:1234/
http://host:1234/aaa http://host:1234/bbb http://host:1234/ccc
After that, hitting a, b, or c plus tab works as expected, it completes the full URL.
Any suggestions to how I can produce the right output? Do I need to manually change the COMPREPLY
variable, or am I just using the functions wrong?
I came up with a solution based on one trick I'm always using. Hope it would help.
_bar()
{
local CUR=$2
local cur
local -a compreply=()
local -a urls=(ftp://gnu.org \
http://host1:1234/aaa \
http://host2:1234/bbb \
http://host2:1234/ccc)
_get_comp_words_by_ref -n : -c cur
compreply=( $(compgen -W "${urls[*]}" -- "$cur") )
COMPREPLY=( "${compreply[@]}" )
__ltrim_colon_completions "$cur"
if [[ ${#COMPREPLY[@]} -gt 1 ]]; then
local common_prefix
common_prefix=$( printf '%s\n' "${COMPREPLY[@]}" \
| sed '$q;N;s/^\(.*\).*\n\1.*$/\1/;h;G;D' )
if [[ $common_prefix == "$CUR" ]]; then
COMPREPLY=( "${compreply[@]}" " " )
fi
fi
return 0
}
complete -F _bar bar
Following is what it would look like (tested with Bash 4.3.33
):
[STEP 101] $ bar <TAB><TAB>
http://host1:1234/aaa http://host2:1234/ccc
ftp://gnu.org http://host2:1234/bbb
[STEP 101] $ bar f<TAB>
[STEP 101] $ bar ftp://gnu.org␣
[STEP 101] $ bar ftp://gnu.org <ENTER>
bash: bar: command not found
[STEP 102] $ bar h<TAB>
[STEP 102] $ bar http://host
[STEP 102] $ bar http://host<TAB><TAB>
http://host2:1234/bbb
http://host1:1234/aaa http://host2:1234/ccc
[STEP 102] $ bar http://host2<TAB>
[STEP 102] $ bar http://host2:1234/
[STEP 102] $ bar http://host2:1234/<TAB><TAB>
http://host2:1234/bbb http://host2:1234/ccc
[STEP 102] $ bar http://host2:1234/b<TAB>
[STEP 102] $ bar http://host2:1234/bbb␣
[STEP 102] $ bar http://host2:1234/bbb <ENTER>
bash: bar: command not found
[STEP 103] $
And actually the problem is not specific about two or more colons. One colon has the similar problem too.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With