In A Nutshell

Carapace is a shell completion library (carapace-sh/carapace) as well as a binary containing a collection of shell completers (carapace-sh/carapace-bin). It works across multiple operating systems and multiple POSIX and non-POSIX shells.

Getting Started

Refer to Install and Setup to get it up and running on your system.

You can use any shell you want, but it is highly recommended to give Elvish a try. Not only shows it best what Carapace can do. It is pretty awesome anyway.

LinkDescription
carapace.shwebsite with examples
Documentation
carapace-sh.github.io/carapacedocumentation of the library
carapace-sh.github.io/carapace-bindocumentation of the binary
carapace-sh.github.io/carapace-specdocumentation of the spec
carapace-sh.github.io/carapace-pixipicture book introduction
Core Projects
carapacelibrary
carapace-binbinary
carapace-bridgecompletion bridge for various frameworks
carapace-pflagflag parser for non-posix variants
carapace-shlexlexer for complex single string arguments
carapace-specYAML spec for custom completions
Scraper
carapace-spec-clapspec generation for clap-rs/clap
carapace-spec-kingpinspec generation for alecthomas/kingpin
carapace-spec-kongspec generation for alecthomas/kong
carapace-spec-manspec generation for manpages
carapace-spec-urfaveclispec generation for urfave/cli

Porcelain Shop

Shell completion is hard. Really hard. And there are all sorts of traps that make you break things unknowingly.

How it works

A function gets passed the current command line up to the cursor position split into words.

command --flag1 positionalArg1 "positionalArg2 with space" <TAB>
# ['command', '--flag1', 'positionalArg1', 'positionalArg2 with space', '']

It then returns possible values to replace the current word with.

posArg3
positionalArg3

The Native Approach

Here, the logic to generate the possible values is done in a native shell script. But writing these isn't easy and tends to become complicated quickly. Few shells even provide a decent framework for it. So everyone ends up making the same mistakes. Over and over again.

Have a look at the script powering your git completion. It is as impressive as it is scary.

The Generator Approach

Since writing them is so hard some argument parsers generate them. This avoids common mistakes and keeps the script in sync with the application. It is however still bound to the limits of the shell. Writing a good generator is even harder than writing a completion script. So there are inconsistencies between shells. If they are supported at all.

The Combined Approach

Here, a part of the logic is delegated to the application. It handles complex value generation. Like retrieving data from a service. Then returns these to the shell script. But this still relies on shell functions and suffers from the same issues as above.

The Detached Approach

Now let's take this one step further. By not relying on the shell we can reduce the completion script to a minimum using a clear interface. All it does is pass information between the shell and the application. This poses some challenges as well of course. But it ensures consistency between shells. And enables highly advanced features.

Hulk BASH!

Carapace supports all major shells. It does not rely on shell-specific functions and even has its own custom file completion. This way it can provide features that not only are consistent across shells. But exceed what they natively provide.

Bash

Take Bash for example. What a nasty little bugger. By default Bash has no support for descriptions. But with some trickery, these can be added.

80x12@0:3

Then there are more complicated topics. Like Wordbreaks, where you must return a substring of the value to be inserted. And Redirects, which are passed unfiltered to the completion function.

Carapace had to resort to its Lexer to handle these correctly.

You really don't want to write completions for Bash. I went all green on this one.

Fish

Fish is a bit more advanced and has a modal completion menu with descriptions.

It also takes care of correctly escaping special characters in the values. And provides a basic framework for creating completion scripts.

But replicating a complex argument structure isn't easy and subcommand determination is rather optimistic.

function __fish_seen_subcommand_from
    set -l cmd (commandline -pxc)
    set -e cmd[1]
    for i in $cmd
        if contains -- $i $argv
            return 0
        end
    end
    return 1
end

Carapace relies on the work done in spf13/cobra. It is a widely adopted argument parser that does this without guesswork.

Zsh

Between shells, Zsh so far has the most sophisticated framework for writing completions.

But it might be a bit too complex. Learning it takes some effort and there are limitations and traps as well. Coloring for example is done using complicated and slow regex matching. It is thus mostly used for file completion (LS_COLORS) and rarely seen in custom scripts.

80x12@0:11

Carapace adopted Styles from Elvish. A human-readable abstraction of ANSI Escape Sequences.

See Puking Rainbows for how this works in detail.

Pandoras Box

Arguments passed to an application are positional. This means they have a specific order in which they appear. But some can be logically declared as Flags. How this is done, however, is entirely up to the author.

POSIX

A commonly used convention where longhands have a -- and shorthands a - prefix. They may appear interspersed with positional arguments and some are repeatable. Shorthands can also be chained.

80x12@0:38

Non-POSIX

Then there are other approaches that in most cases arguably aren't a good idea.

Like shorthands with more than one character which prevents chaining. Or the abuse of flags as subcommands. And non-interspersed mode, which may be easier to parse, but limits UX. Some even mix different formats.

80x12@0:18

Carapace forked pflag to support these. But avoid them if you can.

Dash

The -- argument is a special case and disables flag parsing for arguments following it. However, how it is handled differs between applications. Many simply continue the positional arguments. But some, like gh repo clone, use it for something else.

80x12@0:22

Overly Attached Argument

Flags can also take an argument. And there are multiple variants to this.

POSIX

Flags that require an argument consume the one next on the command line. But it can also be attached directly to the name with a = delimiter. And for shorthands, the delimiter can even be left out. Flags that take an optional argument do so only in the attached version.

80x12@0:18

Not all commands support each of these variants.

Non-POSIX

There are also some less recommended variants.

Like Flags consuming multiple arguments. Or using a different delimiter than =.

80x12@0:9

Lights, Camera, Action!

An Action defines how a position is completed in Carapace.

It consists of either the static values to be inserted. Or a function to generate them. Also, some metadata.

Reusable

An Action is reusable. It can be prefixed, filtered, styled, converted to a list, and even cached.

Take the repository completion for example. It consists of ActionOwners and ActionRepositories combined in various ways. Originally written for gh, it is also used in git, go, and other commands.

80x12@0:9

Contextual

An Action is invoked with Context.

This enables a modified behavior based on work directory, environment variables, or positional arguments.

80x12@0:12

Modular

Multiple Actions can be invoked concurrently and merged into one.

Like tig, which accepts subcommands, files, and git references. Each of these is a separate Action.

80x12@0:5

Group Therapy

Values can not only be styled, they can also be tagged. The former may signify the state of a value, and the latter classifies it.

Implicit

Subcommands are implicitly tagged and styled based on their group.

80x12@0:3

Explicit

Other values can be tagged explicitly.

80x12@0:3

Spec-tacular Citizen

Simple completions can be created using YAML Specs. They are first-class citizens in Carapace and behave similarly to the internal completers.

Basic

Flags are defined as a map of name and description. And Completions using an array of Values and Macros.

80x12@0:10

Macro

With a little regex and reflection magic Actions are exposed as Macros. There are Core, Modifier, and Custom Macros.

80x12@0:10

Envsubst

Contextual completion is possible using variable substitution.

80x12@0:10

Plugin

Specs can also be embedded as subcommands for plugin completion.

80x12@0:20

Running Man

Specs containing a run field can be executed using Shims.

Alias

Alias bridges a command while retaining the argument completion.

80x12@0:6

Script

Scripts are executed with sh on Unix systems and pwsh on Windows.

80x12@0:6

Subcommand

Combined with subcommands a reduced set of complex commands can be created.

80x12@0:10

Greenwashing

Carapace completes environment variables with get-env, set-env, and unset-env.

Complex

Be it log levels for CARGO_LOG, repositories for GH_REPO, or a command with arguments for GIT_PAGER.

80x12@0:7

Custom

Or custom variables that can use the same Macros as in Specs.

80x12@0:62

Conditional

With Conditions, they can be shown only when they matter.

80x12@0:46.5

Wiretap

Carapace can tap into other completion sources and bridge them.

Command

Commands using the combined or detached approach can simply be invoked.

80x12@0:6

Shell

Shells are a bit trickier and may require nasty scripting.

80x12@0:16

Embed

Carapace invokes itself for continuous embedding.

80x12@0:19.5

Explicit

Bridges can be registered using Specs. There is also a config alternative for convenience.

80x12@0:10

Implicit

Other completion sources can be configured for an implicit fallback.

80x12@0:11.5

Sandcastle

Not sure what to play with? Here are some ideas.

git clone {{REPO}}
git checkout {{REF}} {{DIFF_FILE}}
git show {{REF}}
git show REF~{{RELATIVE_REF}}
git show REF~RELATIVE_REF~{{RELATIVE_REF}}
git show REF~RELATIVE_REF~RELATIVE_REF:{{REF_FILE}}
git log {{REF}}
git -C {{FOLDER}} log {{REF}}
git add {{MODIFIED_FILE}}
gh repo clone {{REPO}} -- --branch {{BRANCH}}
gh issue list --repo {{REPOS}} --label {{LABEL}}
gh browse --repo {{REPO}} --branch {{BRANCH}} /{{FILE}}
gh api --method {{METHOD}} {{API_PATH}}
gh alias set NAME {{COMMAND}}
gh issue view {{ISSUE}}
set-env GH_REPO {{REPO}}
gh issue view {{ISSUE}}
unset-env {{ENV}}