📜 ⬆️ ⬇️

Writing your autocompletions for Shell. Part 2: bash


These articles (I decided that thematically it is better to break into two parts) describe some of the basics of creating auto-completion files for your own program.


Preamble

In the process of developing one of your projects, there was a desire to add also auto-completion files (just don’t ask why). Fortunately, I somehow took it upon myself to write such things, but then I was too lazy to read anything, and did not master it.

Introduction

Bash, in contrast to zsh, requires some kind of bicycle construction for itself with respect to autocompletions. Quickly googling, I didn’t find more or less normal tutorials, so the autocompletion files available in the system for pacman were taken as a basis (sincerely hope that the founding fathers of Arch did not invent many bikes).
')


Consider the example of the same my application. I remind you that the help part for which looks like this:

 proga [ -h | --help ] [ -e ESSID | --essid ESSID ] [ - FILE | --config FILE ] [ -o PROFILE | --open PROFILE ] [ -t NUM | --tab NUM ] [ --set-opts OPTIONS ] 

List of flags:


File structure

Here all variables must return an array. There are no special formats here. We first describe the flags, then all the other variables. I remind you (since I’m not going to give functions in more detail below) that _proga_profiles() , unlike other variables, should return the current array:

 # variables _proga_arglist=() _proga_settings=() _proga_tabs=() _proga_profiles() {} 

Then come the main functions that will be called for autocompletion for a particular command. In my case, the command is one, and the function is one:

 # work block _proga() {} 

Then, again, without making a separate function, we make the “function-command” correspondence:

 complete -F _proga proga 


Flags

As mentioned above, there is no special format here, the available flags are located simply in an array:

 _proga_arglist=( '-h' '--help' '-e' '--essid' '-c' '--config' '-o' '--open' '-t' '--tab' '--set-opts' ) 


Variable arrays

I will provide only a function that in zsh looked like this:

 _proga_profiles() { print $(find /some/path -maxdepth 1 -type f -printf "%f\n") } 

In bash this does not work, I had to change a little bit:

 _proga_profiles() { echo $(find /some/path -maxdepth 1 -type f -printf "%f\n") } 


Body function

For autocompletion in bash, the variable COMPREPLY is responsible. To track the current state, call the _get_comp_words_by_ref function with the cur (current option) and prev (previous, the actual state) parameters. Well, you need a few points on which to collapse in a certain part of the case (variables want* ). compgen used to generate auto-completion. After the -W flag he is given a list of words. (There is also a -F flag that calls a function, but in addition to me, it also produces a vorning.) The last argument is the current line, to which you need to generate auto-completion.

Thus, our function looks like this:

 _proga() { COMPREPLY=() wantfiles='-@(c|-config)' wantprofiles='-@(o|-open|s|-select)' wantsettings='-@(-set-opts)' wanttabs='-@(t|-tab)' _get_comp_words_by_ref cur prev if [[ $prev = $wantstring ]]; then #   ,    COMPREPLY=() elif [[ $prev = $wantfiles ]]; then #     _filedir elif [[ $prev = $wantprofiles ]]; then #    COMPREPLY=($(compgen -W '${_proga_profiles[@]}' -- "$cur")) elif [[ $prev = $wanttabs ]]; then #    COMPREPLY=($(compgen -W '${_proga_tabs[@]}' -- "$cur")) elif [[ $prev = $wantsettings ]]; then #    # -S   ,      =( COMPREPLY=($(compgen -S ',' -W '${_proga_settings[@]}' -- "$cur")) else #    COMPREPLY=($(compgen -W '${_proga_arglist[@]}' -- "$cur")) fi true } 


Conclusion


The file is stored in the /usr/share/bash-completion/completions/ with an arbitrary name. The sample file can be fully found in my repository .

Source: https://habr.com/ru/post/230425/


All Articles