26

I'm trying to write a small command launcher application, and would like to use bash's tab completions in my own completion system. I've been able to get a list of completions for general commands using compgen -abck.
However, I would also like to get completions for specific commands: for instance, the input git p should display completion for git's commands.

Is there any way I can use compgen to do this? If not, are there any other ways I can get a list of completions programmatically?

[EDIT: To clarify, I'm not trying to provide completion to bash - my app is a GUI command launcher. I'd simply like to use bash's existing completions in my own app.]

Tom Zych
  • 13,329
  • 9
  • 36
  • 53
Donald Harvey
  • 917
  • 8
  • 23
  • I hacked up this script a while back which gives you pretty accurate [Man-page Bash Completion](http://blog.dblevins.com/2010/03/man-page-based-bash-completion.html) I know other people have done similar things with parsing `--help` option output. – David Blevins Sep 03 '10 at 19:25
  • Great script, but not quite what I'm trying to achieve. Thanks anyway for linking to it though. – Donald Harvey Sep 03 '10 at 22:51

4 Answers4

16

I don't really know how it works, but the awesome window manager uses the following Lua code for getting access to bash completion's result:

https://github.com/awesomeWM/awesome/blob/master/lib/awful/completion.lua#L119

  1. Via complete -p we find complete -o bashdefault -o default -o nospace -F _git git. We remember "_git" for later.
  2. The length of "git l" is 5, so we set COMP_COUNT=6. We are completing the first argument to "git", so COMP_CWORD=1.

All together we use the following script:

__print_completions() {
    printf '%s\n' "${COMPREPLY[@]}"
}

# load bash-completion functions
source /etc/bash_completion

# load git's completion function
_completion_loader git

COMP_WORDS=(git l)
COMP_LINE='git l'
COMP_POINT=6
COMP_CWORD=1
_git
__print_completions

Output: "log"

Six
  • 5,122
  • 3
  • 29
  • 38
Uli Schlachter
  • 9,337
  • 1
  • 23
  • 39
  • The code appears to do pretty much exactly what I want to do with my app. I'll need to port it to regular Bash, but it's still very helpful. Thanks a lot! – Donald Harvey Sep 03 '10 at 23:11
  • I did some testing and this is what is run to complete "git l": /usr/bin/env bash -c 'source /etc/bash_completion; __print_completions() { for ((i=0;i<${#COMPREPLY[*]};i++)); do echo ${COMPREPLY[i]}; done }; COMP_WORDS=(git l); COMP_LINE="git l"; COMP_COUNT=6; COMP_CWORD=1; _git; __print_completions' – Uli Schlachter Sep 04 '10 at 08:52
  • "_git" is found via "complete -p" which prints "complete -o bashdefault -o default -o nospace -F _git git". So if the first word is "git", call "_git". COMP_COUNT is the length of the string so far plus one. COMP_CWORD is the word to complete (first one is index 0). – Uli Schlachter Sep 04 '10 at 08:54
  • Thanks, this'll be perfect. I was thinking of answering the question myself to provide the Bash code and abstract way of doing this, but you've done it for me :P. Anyway, I've awarded you the bounty - thanks again for your help! – Donald Harvey Sep 04 '10 at 09:45
  • 2
    Hey great! Thanks for working this out. Note that for the sake for readability/convenience, you can replace the `for ((..;..;..))` statement with `for reply in "${COMP_REPLY[@]}"` (and then `echo "$reply"` inside the loop). Also: `i` in your example, or `reply` in my proposal, should be declared as `local` to avoid clobbering identically named globals. – intuited Apr 17 '11 at 22:18
  • 3
    FYI Bash now uses dynamic completion loading, which requires the use of `_completion_loader git` to load git's completion function `_git`. Also I was unable to find any reference to `COMP_COUNT`. The correct var is `COMP_POINT`. Note, `COMP_POINT` is not used directly in completion scripts, but is used indirectly via commonly-used helper functions in */usr/share/bash-completion/bash_completion*. – Six Nov 29 '15 at 14:19
  • Not working for me. Does it have to do with the script being non-interactive? My completion turns out to be `_minimal` when I run `_completion_loader`. – Mihai Danila Dec 08 '16 at 05:16
2

Check in the /etc/bash_completion.d/ directory. This is where the different command completion scripts stay.

Daniel
  • 26,899
  • 12
  • 60
  • 88
  • 1
    I have had a poke around in `/etc/bash_completion.d/`, but haven't yet worked out an easy way to get the completions contained within yet very easily. (I'm using Python to access the completions, making things slightly more complicated.) I was hoping there might be a simpler way of accessing command-specific completions. – Donald Harvey Aug 28 '10 at 18:40
1

Quite an old question, but in the mean time I've implemented a script that handles this to reuse completions with ZSH

Treviño
  • 2,999
  • 3
  • 28
  • 23
-1

Here a simple but working example in bash :

function foo_completion()
{
    local currentWord=${COMP_WORDS[COMP_CWORD]}
    local completionList=""

    case "${COMP_CWORD}" in
        "1")
            completionList="command1 command2 command3";
            ;;
        "2")
            completionList="param1 param2 param3";
            ;;
    esac

    COMPREPLY=( $( compgen -W "${completionList}" -- ${currentWord} ) )
}

complete -F foo_completion foo

With this kind of code, you will get commandN completed when you type "foo c" + tab and paramN completed when you type "foo command1 p" + tab

You can compute the completion list from the command help.

my2c

neuro
  • 14,948
  • 3
  • 36
  • 59