What’s next for bash, completion-wise?

Trying out completion feature in several other shells which I don’t use daily–including zsh, tcsh, and fish–I can’t help but comparing them with bash.

IMHO, the last major feature in completion in bash happens in 2009-2010, when bash 4.1 introduces -D option for the “complete” command. This enables fallback/catch-all mechanism like already found in other shells like fish and zsh. When a user requests completion for a command that does not yet have a completion definition, the hook function specified in “complete -D” can execute and find a completion definition somewhere. And the completion can be activated right there and then instead of having to wait for the next command (or after the user logs out and logs in again). A major convenience as completion can be activated or deactivated instantly.

The subsequent major bash versions don’t introduce anything ground-breaking in terms of completion: 4.2 allows us to configure the number of columns used when displaying completion (nice, but not an additional core functionality) and case-map to treat underscore and dash as the same (really convenient, but we can do that ourselves if we want using function or external command backend). 4.3 introduces “-o noquote” and 4.4 introduces “-o nosort” which are just minor.

Completion description. As many bash users who have tasted fish and zsh would agree, I think bash really needs to add the feature of showing description/help text next to each completion answer. This is a major boost for CLI usability. For example, user can see or be reminded of what each command option does instead of having to “man” or open a browser to Google for it.

Menu select. The other popular feature is “menu select” like in zsh (not to be confused with the already existing option “menu-completion” in bash), where after the user presses Tab and is presented with the list of completions, she can use arrow keys to select the completion she wants instead of typing. This is nice but of lesser impact compared to the previous item. A seasoned CLI user would prefer and can complete faster using typing anyway. What I think would be really nifty is incremental matching, where the list of completions is reduced or expanded as the user types. So for example you press “deluser t” and get presented with a list of 30 usernames starting with “t”. You can now type more letters to match fewer of those names until you get the one you want. The list displayed interactively shrinks or reexpands to show only the matching items. The exact detail of how this would work can be tuned to be as comfortable and powerful as possible. What I described just now is actually just a UI (TUI?) improvement of the functionality already present, as when we use tab completion we often do just that, albeit without the interactive list being displayed automatically (we still need to press Tab whenever we want to get the list of completions).

Colors. Fish utilizes colors a lot, for good purpose. For example if you type “ls -” in fish you’ll get a much nicer output compared to in bash. This lets you scan the list faster. It would be nice if we can show colors more in the list of completion in bash.


Adding support for fish, zsh, tcsh in shcompgen

I’ve recently added support for the other three shells (fish, zsh, tcsh) in shcompgen. shcompgen is basically a utility to write those shell commands “complete -C foo foo” or “complete -c foo -l longopt1 –description ‘Add a thing to foo'” for you. It recognizes scripts written using Getopt::Long::Complete, Perinci::CmdLine, and a few others so that you can enable shell tab completion for your scripts.

fish. Enabling tab completion for a command in fish is relatively simple. For each short/long option of a command, you can define a separate “complete” command, e.g.:

complete -c man -s k --description "Show apropos information"
complete -rc man -s C --description "Configuration file"
complete -xc man -a 1 --description "Program section"
complete -xc man -a 2 --description "Syscall section"
complete -xc man -a 3 --description "Library section"

Doing this has the advantage of fish knowing about the each program option and its description, so you can get a prettier/more informative completion. It is not possible to just say like in bash “complete -F somefunc cmd; # delegate completion to a function” or “complete -C somecmd cmd ; # delegate completion to an external command”. It’s also possible to just delegate to the program entirely a la bash’s “complete -C”:

complete -c somecmd -a '(begin; set -lx COMP_SHELL fish; set -lx COMP_LINE (commandline); set -lx COMP_POINT (commandline -C); shcompgen; end)'

zsh. Completion in zsh is complex and complicated with lots and lots of options, if not featureful. You can, in theory, use “complete” or “compgen” command like in bash because zsh has “bashcompinit” that (partially) simulates those two bash commands. This enables you to reuse your bash completion definitions in zsh. I tried to do that but didn’t succeed though.

#compdef pmman
autoload bashcompinit
# this is bash-style
complete -C pmman pmman

The commands I type will sometimes complete, but at other times won’t. So I use “compadd” instead, which is the standard way to add completion results in zsh. For example:

#compdef pmman
_pmman() {
_pmman "$@"

tcsh. tcsh lacks a fallback or autoload mechanism (like “complete -D” in bash or similar mechanism in fish and zsh), so activating or deactivating completion for a command requires you to explicitly re-source a definition script or logout + login again.

Tab completion now works in zsh, fish, and tcsh but since I don’t use those shells daily and am not familiar enough with them, there are still known issues (documented in the shcompgen’s POD) like with escaping of special characters like whitespace. I hope that Perl programmers that use one of those shells can give inputs on how to resolve the issues.