Open bartekpacia opened 6 months ago
Note:
To easily debug shell completion, just source it. For example:
$ . ~/.config/.dart-cli-completion/myapp.zsh
The above makes shell completions for myapp
immediately available in the current shell.
I wish there was a way for a binary to print completions:
$ . <(myapp print-completion zsh)
instead of having to write them to a file first with:
$ myapp install-completion-files
Intro
In this issue I will explain how to automatically provide your CLI app's shell completions to your users in a seamless way.
I've been recently investigating how shell completion works, and various approaches to it. I decided to write my findings down to share knowledge with others, and to (hopefully) improve this package's documentation and functionality so that we can improve how shell completions are distributed for Dart CLI apps.
Intended audience: authors of CLI tools written in Dart that depend on
cli_completion
packageDescription
That's how the original zsh completion script provided by this package looks like this. Let's assume our CLI app name is
foobar
and that we calledfoobar install-completion-files
, which generates the following zsh shell completion script in~/.config/.dart-cli-completion/foobar.zsh
:Original zsh completion file for "foobar"
``` if type compdef &>/dev/null; then _foobar_completion () { local reply local si=$IFS IFS=$' ' reply=($(COMP_CWORD="$((CURRENT-1))" COMP_LINE="$BUFFER" COMP_POINT="$CURSOR" foobar completion -- "${words[@]}")) IFS=$si if [[ -z "$reply" ]]; then _path_files else _describe 'values' reply fi } compdef _foobar_completion foobar fi ```I modified the script above a bit to be a "standard" zsh completion script, that is:
#compdef <program_name>
at the top ->#compdef foobar
_<program_name>
->_foobar
Modified zsh completion file for "foobar"
```zsh #compdef foobar local reply local si=$IFS IFS=$' ' reply=($(COMP_CWORD="$((CURRENT-1))" COMP_LINE="$BUFFER" COMP_POINT="$CURSOR" foobar completion -- "${words[@]}")) IFS=$si if [[ -z "$reply" ]]; then _path_files else _describe 'values' reply fi ```Now I put that script to
zsh
's conventional location for shell completion scripts - in case of my macOS, it's/opt/homebrew/share/zsh/site-functions
:Restart
zsh
by runningexec zsh
and voilà, the completion forfoobar
should work now!If it does not, make sure you're adding
opt/homebrew/share/zsh/site-function
to your$FPATH
- see relevant docs.Distribution
With the above in mind, I can easily write e.g. a Homebrew formula for my CLI tool, and inside that formula put shell completion installation files:
Note that this automatic setup of completion files is only possible when your CLI app is installed through a proper package manager, like Homebrew or Pacman. If it is installed with
dart pub global activate
, the approach I described here won't work, becausedart pub global activate
only compiles the Dart source code to a JIT executable, and doesn't have any way of also copying files – which is required for automatical installation of shell completion.But even if you prefer to install your Dart CLI app with
dart pub global activate
, you can distribute the completion scripts in different way – e.g. as an oh-my-zsh plugin – or you can just provide the completion script and tell your users "hey, install it at this-and-that path". I think it's much better than appending some code to~/.zshrc
or~/.bashrc
.