💪Autocomplete

Overview

Fig defines a standard schema for building autocomplete for CLI tools. This schema is called a completion spec. Fig takes a user's input in the terminal, maps it to the relevant completion spec, and renders suggestions accordingly.

The below is an example of a simple completion spec. Think of it as a big tree that maps out a CLI tool.

var completionSpec = { // Command Object
    name: "git",
    description: "the stupid content tracker",
    subcommands: [ // Array of Command Objects
        {
            name: "commit",
            description: "Record changes to the repository",
            options: [ ... ] 
        },
        { ... }
    ],
    options: [ // Array of Option Objects
        {
            name: "--version",
            description: "Print git's current version"
        },
        { ... }
    ]
    args: [ ... ], // Array of Arg Objects
    additionalSuggestions: [ ... ] // Array of Suggestion Objects
}

Git Repo

Personally, I learn best by looking at examples. I suggest looking at some of the completion specs for commands you know well. You should be able to pick up the format pretty quickly.

Git Repo: withfig/autocomplete Git Repo URL: https://github.com/withfig/autocomplete/tree/master/specs

Contributing

We ❤️contributors. Autocomplete is a community driven effort. Just fork the repo, make changes, and submit a pull request.

If you have any questions, please email us: hello@withfig.com or join our slack. We are very responsive

Note: A completion spec is a javascript object. Therefore, it must always begin with var completionSpec =

Getting Started

Fig takes a user's terminal input, splits it into an abstract syntax tree (AST), maps this AST to the completion-spec, works out the range of possibilities of what the user could input next (these possibilities are called suggestions), and renders the suggestions to the user.

This is a lot of steps. The only thing you need to worry about is making a good completion spec.

Fig's completion specs serve two purposes. They

1. Define a CLI tool in a structured tree-like representation. Mapping a user's Terminal input to this defined tree structure gives us the context on the user's input. This lets us accurately generate suggestions.

e.g. we will generate very different suggestions if a user types git versus git commit -

2. Contain Content Completion specs provide content (like descriptions, icons etc) for the suggestions that are rendered to the user. If instructions on how to generate suggestions (like get all the files in this specific folder)

i.e. your description of the -m option in git commit -m is what will displayed to the user!

Defining the CLI Structure (and Quick Summary of How CLI Tools work)

It is important to understand these concepts to successfully build a completion spec.

CLI Tool / Program A CLI tool is essentially a mini program. These program take a list of strings as input (usually separated by spaces). The strings can be subcommands, options, or arguments

Examples of CLI tools / Programs are git, cd, echo, ls, cat, docker, npm

Subcommands A subcommand is like another program / CLI tool, nested beneath the original program. Examples of subcommands are git commit, git add, git push, docker build, npm install etc.

Like CLI tools, subcommands can then have their own subcommands, options, and arguments.

Options Options are special strings with dashes (single or double). They add extra information to a CLI tool and are parsed specially by the CLI tool.

Some options take arguments

e.g. git commit -m "my message" : -m is the option and it takes the argument "my message"

Other options don't take arguments. These are known as boolean options or flags

e.g. git --version, heroku apps --json, npm --global, ls -l

Argument Finally, an argument is like a user input. Each CLI tool has its own rules about what arguments it takes.

CLI tools, subcommands, and options can all take arguments. They can take 0 arguments, 1 argument, 2 arguments, ... n arguments, or infinite arguments. Note: A command / option that takes infinite arguments is called variadic.

examples git commit -m "my message" -> -m takes one input which is a string

git add index.html app.js -> takes infinite arguments, but the user only input two

BONUS: Man Pages

The synopsis section of man pages (try running man git in your terminal) gives a good mapping of a CLI tool's structure. Some hints:

  • Square brackets indicate subcommands/options/arguments are optional

  • Angle brackets indicate subcommands/options/arguments are mandatory

Fig is working on a parser that converts the synopsis section into an autocomplete spec. If you know of an open source tool OR want to contribute, let us know: hello@withfig.com

Objects You Need to Know to Build Completion Specs

Note: If you haven't already, read / skim the above section so you understand how CLI tools work. The objects below are based on this.

There are 4 objects you need to understand to successfully build a completion spec.

  • Suggestion Object - objects generated by a completion spec. What Fig uses to render suggestions to the user

  • Command Object - defines a CLI tool / subcommand

  • Option Object - defines the options a CLI tool / subcommand takes

  • Arg Object - defines the inputs / arguments a CLI tool / subcommand / option takes

var completionSpec = { // Command Object
    name: "git",
    description: "the stupid content tracker",
    subcommands: [ // Array of Command Objects
        {
            name: "commit",
            description: "Record changes to the repository",
            options: [ ... ] 
        },
        { ... }
    ],
    options: [ // Array of Option Objects
        {
            name: "--version",
            description: "Print git's current version"
        },
        { ... }
    ]
    args: [ ... ], // Array of Arg Objects
    additionalSuggestions: [ ... ] // Array of Shortcut Objects
}

A Suggestion object is what Fig renders in the Autocomplete popup. In your completion spec, you will almost always use the Command, Option, and Arg objects.

Command and Option objects are supersets of the Suggestion object i.e. they have the same properties as the Suggestion object and more. When parsing a completion-spec, Command and Option objects are more or less converted directly into Suggestion objects.

The Arg object is more like a schema or a blueprint. We know the full range of subcommands or options a user could input. We also know that certain commands / options take arguments, but we don't necessarily know what these arguments will be. If the argument must be constrained in some way (e.g. it MUST be a file or MUST be a folder), we define some rules in the Arg object to generate suggestions.

The presence of an Arg object indicates a command/option takes an argument. Extra details inside the Arg object are used to help us generate suggestions.

For instance, we know git add takes an array of files, cd takes a folder path, and heroku -a takes a string representing your Heroku app. Because we know certain conditions about these arguments, we can define special rules for generating Suggestion objects for each of these.

You can learn more about each object type in the sections below.

Suggestion Objects (and How They're Rendered)

After taking a user's Terminal input to the relevant completion spec. It then outputs an array of Suggestion objects.

AGAIN: you will almost never use this object. Fig will create it for you. This section is just for your reference.

-m example from git commit

// Suggestion Object
{
    // Mandatory Properties
    name: ["-m", "--message"],  // string or Array of strings (required)
    type: "option", // string. Must be one of subcommand, option, argument, shortcut, special

    
    // Optional properties (Fig can generate these from the above)
    description: "The message for the commit",  // string 
    insertValue: "-m {cursor}",  // string
    icon: "😀",  // string. Either emoji or URL
}

Note: the only required property is "name". Fig automatically generates the remaining properties from rules in the completion spec. You can choose to override them if you want to.

  1. icon

  2. name

  3. description

  4. insertValue

name

This is what will show up as a suggestion in the autocomplete box. If it's an array, all strings will be shown separated by a comma.

type

This is the type of suggestion being shown. It can be one of subcommand, option, argument, shortcut, special. It is used to generate the icon if one is not provided.

description

The description for this specific suggestion. This is what will show up in the bottom autocomplete box. There isn't too much space, so try to be as concise as possible!

insertValue

When a user selects a suggestion (clicks tab or enter) it will insert this value.

Default: current suggestions name property + space

When a user selects a suggestion (clicks tab or enter) it will insert this value.

The insertValue property is often used when you can anticipate what the user is typing next. e.g. if you could automatically insert quotes if you know they are about to type a long string.

insertValue allows specific shortcuts that represent keyboard keys

  • \b - backspace

  • \033[D - left arrow key

  • \033[C - right arrow key

  • {cursor} - will insert the cursor to where it was placed

e.g. in git commit -m, the completion object may look like:

{
    name: ["-m", "--message"],
    description: "the commit message",
    insertValue: "-m '{cursor}' ",
    args: [ {} ] // Learn more about why we did this in the Arg object section
}

icon

The icon that will display next to the suggestion. It can be an emoji or a url that will be inserted as the href to an img tag. If an icon property is not provided, Fig will use a default icon based on the type property

Command Object

The Command object is a superset of the Suggestion object i.e. it takes all the same properties as a Suggestion object plus the following properties

The command object is the backbone of the completion spec. It is recursive (the subcommands property takes an array of Command objects). Fig uses a Command object to create suggestions for commands and subcommands + for parsing.

// Command Object
{
    name: "commit" // must be string NOT array of strings. This overrides the Suggestion object
    subcommands: [ ... ],  // Array of Command Objects
    options: [ ... ] // Array of Option Objects
    args: [ ... ]  // Array of Args objects
    additionalSuggestions: [ ... ] // Array of Suggestion objects
}

Important Things to Note

  • the name property must be a string NOT an array of strings like in a Suggestion object. This is for parsing purposes.

  • The subcommands, options, and args properties are all optional

  • The args property must be included if the subcommand takes an argument(s) and you want Fig to parse it correctly.

  • When converting a Command object into a Suggestion object, Fig automatically makes the type property = "subcommand"

Quick Example

Let's look at git

git is a Command object. It has a property

  • subcommands which is an array of all of git's subcommands (e.g. commit, push, add...)

  • options which is an array of all of the options available to git at that particular level

    • e.g. --version is available to git but not to git commit

  • etc

Now let's look at git push

push is one of the Command objects listed in the subcommands property for git. It represents the command git push. It is a Command Object, with properties:

  • args which is an array of Arg objects, each representing the arguments the git push command takes (ie the repository and branch)

  • etc

You can look at the git completion spec here: https://github.com/withfig/autocomplete/blob/master/specs/git.js

Option Object

The Option object is a superset of the Suggestion object i.e. it takes all the same properties as a Suggestion object. It is literally exactly the same.

Here is an example of git --version

// Option Object
{
    name: ["-v", "--version"],  // string or Array of strings (required)
    description: "The current version of git",  // string
    args [ ... ] // // Array of Args objects
}

Important Things to Note

  • When converting an Option object into a Suggestion object, Fig automatically makes the type property = "option"

  • The args property is optional but must be included if the option takes an argument(s) and you want Fig to parse it correctly.

  • Remember: you don't need properties like icon, insertValue, or type - Fig can create these for you

Arg Object

Please read this full section

The Arg object is NOT superset of the Suggestion object. These are the below properties

property

type

required

name

string

false

description

string

false

optional

boolean

false

variadic

boolean

false

suggestions

array of strings OR array of Suggestions

false

templates

Template Object

false

generator

Generator Object

false

NOTE: No properties are required. But please read below.

Important things to Note

The presence of an Arg object signals to Fig's parser that a command or an option takes an argument (or arguments). This is VERY IMPORTANT. If we don't know a command / option takes an argument, Fig's parser will get mixed up and will present the wrong suggestions.

  • If a command or option takes arguments, include the correct number of Arg objects

  • If you don't know what to include for the argument, you should include an empty object

  • If an argument is optional, add the optional property.

Here is an example of why this is very important. Let's say you are building the git completion spec. You are trying to define the -m option in git commit -m

If you didn't signal to Fig that -m took an argument, Fig would just assume that the next string the user inserts could be another option and will give poor suggestions. In reality, the next string the user inserts must be the argument to the -m option. We should only suggest accordingly. Therefore, you must include an array with a single empty Arg object in the Option object like so:

{
    name: ["-m", "--message"],
    description: "the commit message",
    insertValue: "-m '{cursor}' ",
    args: [ {} ] // An array with a single empty Arg Object
}

Properties

name

The name for the argument. Currently it is not rendered, but will be in the future.

e.g. git push <remote> [refspec] - the names of the two arguments are remote and refspec

description

The description for the argument. Similar to the name property, it is not currently rendered, but describes the argument in more depth than the name.

optional

Signals that an argument input is optional. Usually this is when something has a default value

e.g. npm install takes an optional input. npm install on its own is a valid command that will install all the files in your package.json. But if you did npm install react it would specifically install react. In this case, react is an optional argument.

Including this is important for Fig's parsing.

variadic

Signals that Fig should stop offering suggestion for future inputs because this one will continue indefinitely.

e.g. echo & git add both take a single argument that is variadic

Including this is important for Fig's parsing.

suggestions

Suggestions to provide if the user is inputting the current argument. This can either be an array of Suggestion objects OR an array of strings (which Fig will convert to an array of Suggestion objects with the name equal to each string)

generator

This property is a javascript object. If present, the object will run the script property in the user's local shell. It will then get the shell output as one big string. It will then convert this into Suggestion objects by splitting on the splitOn property (e.g. \n or ,) or by taking the string and applying a function specified in the postProcess property. The postProcess function may output an array of strings that Fig will convert into Suggestion objects OR output an array of Suggestion Objects

key

value type

options

description

required

script

string

yes

splitOn

string

yes or postProcess

postProcess

javascript function that takes one string input and outputs array of strings or Suggestion objects

yes or splitOn

Note: when using the script property you are writing bash/zsh. When you try and write a bash string in javascript, the parsing of certain characters gets annoying. I strongly recommend using the String.raw method

Look at the heroku.js completion spec for Heroku for good examples of generator.

templates

This is very similar to the generator property. There are several standard types of arguments that CLI tools take. For example, CLI tools often take filepaths and folders as input.

Rather than you implementing this yourself with generator, Fig has pre-built the logic to generate suggestions for:

  • filepaths (see example when using Fig autocomplete and open command)

  • folders (see example when using Fig autocomplete and cd command)

It is a javascript object with the following properties

properties

value type

type

string (can be one of "filepaths", "folders")

postProcess

javascript function that takes an array of suggestion objects as input and outputs array of SuggestionObjects

Alternatively, rather than including a javascript object, the templates property could just take the a single string of paths that would be provided to the template property mentioned just above.

Look at the open.js completion spec and cd.js completion spec for good examples of templates.

Testing Your Completion Spec

Where should I save my completion spec

We suggest saving your completion spec in the following folder: ~/.fig/autocompleteand editing it from there.

What's the best way to test my spec

Fig loads the completion specs as you type in your Terminal. But to be faster and save computer power, we keep the current script loaded until you start using a new CLI tool for which we have a completion spec.

So, if you make changes to a spec, go to your terminal, load up another spec (e.g. type cd plus space), then backspace to the start, then you can type in your command which will load up your newly updated spec.

Can Fig get confused

Yes! If you find yourself using keys like the arrow keys, cmd/option,ctrl/shift, OR terminal aliases or history etc, Fig may get confused. When Fig gets confused, it stops rendering completions.

If this happens, just got to a new line (enter or ctrl + c). Maybe do this twice just in case. It should be better

My spec isn't showing up in autocomplete

Is autocomplete working? Try going to a new line in the terminal and typing git or cd plus a space.

  1. If Fig pops up, autocomplete is working. Chances are it is a problem with your script. Make sure you have correct

  2. If Fig doesn't pop up, autocomplete has crushed 😬. Click to the Fig Icon (◧) in the mac status bar (very top right of your screen near the battery percentage and time) -> Click Autocomplete

    1. This Toggles autocomplete on and off and should make it work

  3. If Fig still doesn't work, quit Fig and start again ( ◧ -> Quit Fig)

  4. If Fig still doesn't work, message us in Slack or email hello@withfig.com

How else can I debug?

Type git plus a space to show the autocomplete window. Right click the fig window, and click Inspect Element. Look at the console for errors.

Autocomplete is working but my script isn't showing

Chances are you have

Others Things to Know / General Advice

If you have a problem, message the founders

We are very responsive: Slack or email hello@withfig.com

Make sure to Include Args if relevant

Your suggestions will be really weird if you don't do this. Read the Arg Object section and ask for advice if confused.

If a subcommand / option takes an argument or arguments, include an Arg object, even if it is literally an empty object.

If a subcommand / option does not take an argument, do not include the args property!

This is very important!!!

File Format

Save your completion specs like [CLI Name].js

  • e.g. git.js or cd.js

File Location

Save your completion spec in the following folder: ~/.fig/autocomplete

Other

Your completion script must start with the root object defined as a variable called completionSpec

  • e.g. var completionSpec = {...}

Last updated