mix_completions, a mix task that allows you to add shell completions for
mix_completions supports completions for
fish already had community contributions adding completions for
mix: fish completions
How it works
mix_completions adds three tasks to work with shell completions:
mix complete caches the available completions from
mix help. If
mix complete detects a
mix.exs file, it will cache these completions in the project in
.mix_complete.cache. Otherwise it will store the cache in
This means that you can have a separate set of completions for a project with custom tasks than what is generally available to mix globally.
mix complete.bash will refresh the cache a la
mix complete, and outputs bash that when sourced enables shell completions for
mix complete.zsh, like its
bash counterpart, refreshes the cache and generates output that can be loaded by
zsh. Instructions on where to put this output can be found in the README.
Why Cache Completions
With shell completions there seem to be two ways of sourcing the completions:
Ask the program for the completions available. This is the approach that cobra and click take. The shell completions they output are simply a parser for completions output by the program itself.
Caching completions outside of the program. This is the approach that tools like completely take. Saving the completions in plain text or directly in the shell output.
I chose to use option 2, because Elixir has a non-trivial startup time. Recently work has reduced the startup time of the BEAM for Elixir, but
mix still takes a few seconds to run on my machine. Instead of waiting multiple seconds for completions to come back, I chose to cache the completions in a TSV that can parsed and handled by the shell completions directly.
Where to store the cache?
This project led me to learn about the XDG Base Directory Specification. I’ve known about these environment variables for a while, but I didn’t know how to use them as a software author.
The XDG specification gives guidance on where to put configuration or cache files on unix systems. The recommendations were simple to use:
XDG_CACHE_HOME is configurable by a user, and defaults to
$HOME/.local/cache if unset.
I can either put my cache as a file in that directory or create a subdirectory if I have multiple cached things to store.
mix_completions only stores one TSV for its cache, so it’s stored directly in the
Finding all the tasks
Initially, when I wanted to find all of the available mix tasks,
System.shell to call
mix help and then processed the output with
This got the job done, but felt fragile.
While explaining this to a friend, they pointed out that
mix help --names does this work for me.Thanks Jeff! Though I did have to filter
iex from the list, and I was still invoking
Then I realized that if
mix had an option for this, it must know how to find (and print) all of the available tasks. Now,
mix_completions uses vendored versions of the same functions that
mix help uses. This proved to be useful when I switched from a simple list of tasks to a tab-separated values file of both tasks and their shortsdocs, since
Mix.Task provides helpers to fetch things like a task’s shortdoc.
Since I chose to work in a project agnostic way, I have no way of knowing what arguments and flag are available for subcommands. Thus I chose to only provide completions for available tasks, since I can ask
mix for these directly. The
fish community completions provide more granularity, at the cost of pre-assuming which tasks you have available.
I chose to use caching over hard-coding so that you can detect new tasks and add completions for them, if only at the surface level.
Try It Now
If you would like to try
mix archive.install hex mix_completions
Instructions on how to source the completions for your chosen shell are in the README.
Please report any issues you find. :)