How to reset COMP_WORDBREAKS without affecting other completion script?
Asked Answered
J

1

26

There is something confuse me when I implement a bash auto-completion function which I'll put it in /etc/bash_completion.d/

In order to achieve some feature, I want to remove the word break characters colon (:) from variable $COMP_WORDBREAKS and add a slash (/) at begin of $COMP_WORDBREAKS.

COMP_WORDBREAKS=" /'><=;|&("
_mytool()
{
    local cur=${COMP_WORDS[COMP_CWORD]}
    compopt -o nospace

    # my implement here

    COMPREPLY=( $(compgen ..........my_implement......... -- $cur) )
}
complete -F _mytool mytool

However, I can't reset COMP_WORDBREAKS directly because the value is shared with other completion scripts. By the time the completion function gets called, variable COMP_WORDS array has already been populated, so locally changes COMP_WORDBREAKS have no effect.

Is there any solution for changing COMP_WORDBREAKS in one completion script and no effect to other script?

$ echo $BASH_VERSION
4.2.10(1)-release
Jeffersonjeffery answered 10/5, 2012 at 6:40 Comment(0)
C
29

Modifying $COMP_WORDBREAKS in your completion script is not the recommended way (as it is a global variable and it could affect the behavior of other completion scripts - for example ssh).

However, bash completion offers some helper methods which you can use to achieve your goal.

The recommended way to handle non-word-breaking characters in completion words is by using the two helper methods:

  • _get_comp_words_by_ref with the -n EXCLUDE option
    • gets the word-to-complete without considering the characters in EXCLUDE as word breaks
  • __ltrim_colon_completions

So, here is a basic example of how to a handle a colon (:) in completion words:

_mytool()
{
    local cur
    _get_comp_words_by_ref -n : cur

    # my implementation here

    COMPREPLY=( $(compgen ..........my_implement......... -- $cur) )

    __ltrim_colon_completions "$cur"
}
complete -F _mytool mytool

As a final tip, the helper methods are located in /etc/bash_completion. Take a look inside to read a detailed description of each method and to discover more helper methods.

Chatman answered 19/9, 2012 at 13:13 Comment(10)
Thank you so much, this was really useful for my rake task completions in Ruby on Rails! Also, thanks for pointing out section E13 in the docs.Emigrant
this only worked properly, when I put this line cur="${COMP_WORDS[COMP_CWORD]}" before _get_comp_words_by_ref -n : cur also good to know, if you use the prev too, you can add it at the end _get_comp_words_by_ref -n : cur prevWb
When I have ambiguous completions and hit tab twice I get incorrect suggestions based on what I have typed when I use this solution. See #28479716Megilp
Content of /etc/bash_completion tells in the heading comment for __ltrim_colon_completions: "The preferred solution is to remove the colon (:) from COMP_WORDBREAKS in your .bashrc"Baptistry
How does ssh's bash completion break, if COMP_WORDBREAKS is trimed? I suppose ssh's autocompletion could be fixed to work in both cases.Baptistry
With the solution, completion works somewhat differently: Prefix ending with : is trimmed off from shown completions.Baptistry
Instead of using _get_comp_words_by_ref you could use _init_completion -n :, but you have to declare more local variables then.Baptistry
to add to @Baptistry local cur prev words cword then _init_completion -n : and you get a COMP_WORDS array in words without the colon breaking wordsTver
_init_completion is nicer, but it still requires __ltrim_colon_completions (otherwise the completion includes extra text)Copyedit
FWIW, these functions appear to be getting deprecated. Documentation is on an old commit, located here: github.com/scop/bash-completion/blob/…Vinylidene

© 2022 - 2024 — McMap. All rights reserved.