Accessing bash completions for specific commands programmatically
Asked Answered
G

3

28

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.]

Grenoble answered 19/8, 2010 at 10:41 Comment(2)
I hacked up this script a while back which gives you pretty accurate Man-page Bash Completion I know other people have done similar things with parsing --help option output.Daph
Great script, but not quite what I'm trying to achieve. Thanks anyway for linking to it though.Grenoble
V
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"

Vladimar answered 3/9, 2010 at 22:52 Comment(7)
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!Grenoble
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'Vladimar
"_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).Vladimar
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!Grenoble
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.Hoop
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.Gingivitis
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.Rodgerrodgers
T
2

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

Trangtranquada answered 22/8, 2010 at 16:19 Comment(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.Grenoble
C
1

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

Candide answered 16/12, 2020 at 0:53 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.