New feature in ralsina/docopt.cr -- Automatic shell completion

TL; DR: docopt lets you describe your program’s CLI by writing the help and then parsing it into a usable data structure.

This new feature for ralsina/docopt.cr a fork of the original docopt.cr gives you smart shell completion.

At least for bash, other shells to come.

Quoting the README:

Shell Completion Generation

docopt.cr can generate shell completion scripts for bash (other shells to come)
so that when you TAB while writing a command it will show you the possible
options.

The code to create a bash completion looks like this for the classic
naval_fate example:

    bash_completion = Docopt.bash_completion("naval_fate", doc)

This will give you a reasonable bash completion. To make this available to the user
you could have something like a naval_fate --completion in your usage instructions
and either tell the user to put this in their .bashrc:

    naval_fate --completion >> ~/.bashrc

Or write it to a file and put it in /etc/bash_completion.d/:

    naval_fate --completion > /etc/bash_completion.d/naval_fate

Custom Completions

Usually the suggestions provided by the completions are limited to
flags options and files, which may not be the right thing.

Suppose you want the naval_fate ship new command to be completed with
just the names from a list of famous ships. You can do that using the
custom_completions argument:

    bash_completion = Docopt.bash_completion(
      "naval_fate", 
      doc, 
      {"naval_fate_ship_new" => %("Titanic 'Queen Mary' 'USS Enterprise')}
    )

The key is the name of the command and any subcommands, joined by
_ (underscore). In this case, the command is naval_fate ship new.

The completion should be provided as a list of space-separated strings,
and if any of them contain spaces, they should be single-quoted.

It can be made more dynamic by using instead the output of a command.
For example, if the command naval_fate ship list existed, we could do this
using bash ability to run commands inside other commands:

    bash_completion = Docopt.bash_completion(
      "naval_fate", 
      doc, 
      {"naval_fate_ship_new" => "$(naval_fate ship list)"}
    )

And the completion for naval_fate ship new would be the output of
naval_fate ship list.

1 Like