tab completion helpers, for node cli programs & others. Inspired by npm completion
JavaScript Shell
Latest commit fcb0a36 Jan 6, 2017 @mklabs 2.2.2

tabtab Build Status

A node package to do some custom command line<tab><tab> completion for any system command, for Bash, Zsh, and Fish shells.

Made possible using the same technique as npm (whose completion is quite awesome) relying on a shell script bridge to do the actual completion from node's land.

  • Supports zsh, fish and bash
  • CLI tool to manage and discover completion.
  • Automatic completion from package.json config
  • Or using an EventEmitter based API
  • Manual or Automatic installation using system dirs (ex. /usr/share/bash-completion/completions for bash).
  • A way to install completion script for a given shell on npm install, gently asking the user for install location.
    • tabtab install in package.json install script creates the completion file on user system.


npm install tabtab --save



You can add completion pretty easily in your node cli script:

#! /usr/bin/env node

// Ex. bin/ entry point for a "program" package
var tab = require('tabtab')({
  name: 'program'

// General handler. Gets called on `program <tab>` and `program stuff ... <tab>`
tab.on('program', function(data, done) {
  // General handler
  done(null, ['foo', 'bar']);

// Specific handler. Gets called on `program list <tab>`
tab.on('list', function(data, done) {
  done(null, ['file.js', 'file2.js']);

// Start must be called to register the completion commands and listen for
// completion.

These events are emitted whenever the command program completion -- .. is triggered, with special COMP_* environment variables.

tab.start() will define one command: completion for your program, which is used by the Shell completion scripts.

The data object holds interesting value to drive the output of the completion:

  • line: full command being completed
  • words: number of word
  • point: cursor position
  • partial: tabing in the middle of a word: foo bar baz bar foobarrrrrrr
  • last: last word of the line
  • lastPartial: last partial of the line
  • prev: the previous word


var tab = require('tabtab')({
  // the String package name being completed, defaults to process.title
  // (if not node default) or will attempt to determine parent's
  // package.json location and extract the name from it.
  name: 'foobar'

  // Enable / Disable cache (defaults: true)
  cache: true,

  // Cache Time To Live duration in ms (default: 5min)
  ttl: 1000 * 60 * 5

Completion results are cached by default, for a duration of 5 minutes. Caching is based on the value of the full command being completed (data.line).

Completion description

Only supported with zsh or fish, tabtab offers the ability to define per command / options description by adding them preceded by a colon, in the form of:

'command:description for command'

This way, you can define descriptions for a specific completion item and tabtab will configure zsh / fish to show them right to the completion item.

Example for zsh

$ program <tab>
command     - description for command

Example for fish

$ program <tab>
command     (description for command)


While the EventEmitter API can offer fine control over what gets completed, completion values can be defined directly in the package.json file, using the tabtab property:

  "tabtab": {
    "nvm": ["help", "use", "install", "uninstall", "run", "current", "ls", "ls-remote"],
    "use": ["stable", "default", "iojs", "v5.11.0", "v6.0.0"]

This still requires to initialize tabtab with:



For any installation method described below, be sure to reload your current shell configuration file by sourcing it (ex. for bash: source ~/.bashrc), or opening a new shell.

Manual Installation

Manually loading the completion for your cli app is done very much like npm does:

. <(tabtab install --stdout --name program)

It'll enables tab-completion for the program executable. Adding it to your ~/.bashrc or ~/.zshrc will make the completions available everywhere (not only the current shell).

tabtab install --stdout --name program >> ~/.bashrc # or ~/.zshrc

This requires an additional manual step for the user. Ideally we'd want it to be automatic, and define it at a system-level.

Automatic Installation

For completions to be active for a particular command/program, the user shell (bash, zsh or fish) must load a specific file when the shell starts.

Each shell have its own system, and different loading paths. tabtab tries to figure out the most appropriate directory depending on the $SHELL variable.

  • fish Uses ~/.config/fish/completions
  • zsh Uses /usr/local/share/zsh/site-functions
  • bash Asks pkg-config for completion directories if bash-completion is installed (defaults to /usr/share/bash-completion/completions and /etc/bash_completion.d)

tabtab CLI provides an install command to ease the process of installing a completion script when the package is installed on the user system, using npm script.

npm script:install

Using npm's install/uninstall script, you can automatically manage completion for your program whenever it gets globally installed or removed.

  "scripts": {
    "install": "tabtab install"

On install, npm will execute the tabtab install command automatically in the context of your package.


  "name": "foobar",
  "bin": "bin/foobar",
  "scripts": {
    "install": "tabtab install"
  "dependencies": {
    "tabtab": "^1.0.0"

Nothing is done's without asking confirmation, tabtab install looks at the $SHELL variable to determine the best possible locations and uses Inquirer to ask the user what it should do:

bash zsh fish

tabtab install --auto

The --auto flag can be used to bypass prompts and use the SHELL configuration file options by default:

  • bash: Will use ~/.bashrc
  • zsh: Will use ~/.zshrc
  • bash: Will use ~/.config/fish/

This way, you can silently install / uninstall completion for a specific command without asking user to do so.

tabtab uninstall --auto

The uninstall command can be used to undo what has been done by tabtab install --auto command.

Completion for other programs


The --completer option allows you to delegate the completion part to another program. Let's take nvm as an example.

The idea is to create a package named nvm-complete, with an executable that loads tabtab and handle the completion output of nvm-complete completion.

  "name": "nvm-complete",
  "bin": "./index.js",
  "scripts": {
    "install": "tabtab install --name nvm --completer nvm-complete"
  "dependencies": {
    "tabtab": "^1.0.0"
// index.js
var tabtab = require('tabtab');

tabtab.on('nvm', function(data, done) {
  return done(null, ['ls', 'ls-remote', 'install', 'use', ...]);


Alternatively, we can use tabtab property in package.json file to define static list of completion results:

  "tabtab": {
    "nvm": ["help", "use", "install", "uninstall", "run", "current", "ls", "ls-remote"],
    "use": ["stable", "default", "iojs", "v5.11.0", "v6.0.0"]

For more control over the completion results, the JS api is useful for returning specific values depdending on preceding words, like completing each node versions on nvm install <tab>.

var exex = require('child_process').exec;

// To cache the list of versions returned by ls-remote
var versions = [];
tabtab.on('install', function(data, done) {
  if (versions.length) return done(null, versions);

  // Ask nvm the list of remote, and return each as a completion item
  exec('nvm ls-remote', function(err, stdout) {
    if (err) return done(err);
    versions = versions.concat(stdout.split(/\n/));
    return done(null, versions);

On global installation of nvm-complete, the user will be asked for installation instruction (output to stdout, write to shell config, or a system dir). The completion should be active on reload or next login (close / reopen your terminal).








Debugging completion

On completion trigger (hitting tab), any STDOUT output is used as a completion results, and STDERR is completely silenced.

To be able to log and debug completion scripts and functions, you can use TABTAB_DEBUG environment variable. When defined, tabtab will redirect any debug output to the file specified.

export TABTAB_DEBUG=/tmp/tabtab.log

Trigger a completion, and tail -f /tmp/tabtab.log to see debugging output.

to be able to use the logger in your own completion, you can require('tabtab/lib/debug'). it is a thin wrapper on top of the debug module, and has the same api and behavior, except when process.env.tabtab_debug is defined.

const debug = require('tabtab/lib/debug')('tabtab:name');


tabtab(1) - manage and discover completion on the user system.

it provides utilities for installing a completion file, to discover and enable additional completion etc.

$ tabtab <command> [options]

  -h, --help              Show this help output
  -v, --version           Show package version
  --name                  Binary name being completed
  --auto                  Use default SHELL configuration file
                          (~/.bashrc, ~/.zshrc or ~/.config/fish/


  install                 Install and enable completion file on user system
  uninstall               Undo the install command (only works with --auto)

tabtab install

$ tabtab install --help

  --stdout                outputs script to console and writes nothing
  --name                  program name to complete
  --completer             program that drives the completion (default: --name)

triggers the installation process and asks user for install location. --name if not defined, is determined from package.json name property. --completer can be used to delegate the completion to another program. ex.

$ tabtab install --name bower --completer bower-complete

tabtab install is not meant to be run directly, but rather used with your package.json scripts.

tabtab uninstall

$ tabtab uninstall --name binary-name

attemps to uninstall a previous tabtab install by removing lines added by tabtab install in the SHELL specific config file (~/.bashrc, ~/.zshrc or ~/.config/fish/

Only works with --auto flag.


npm does pretty amazing stuff with its completion feature. bash and zsh provides command tab-completion, which allow you to complete the names of commands in your $path. usually these functions means bash scripting, and in the case of npm, it is partially true.

there is a special npm completion command you may want to look around, if not already.

npm completion

running this should dump this script to the console. this script works with both bash/zsh and map the correct completion functions to the npm executable. these functions takes care of parsing the comp_* variables available when hitting tab to complete a command, set them up as environment variables and run the npm completion command followed by -- words where words match value of the command being completed.

this means that using this technique npm manage to perform bash/zsh completion using node and javascript. actually, the comprehensiveness of npm completion is quite amazing.

this whole package/module is based entirely on npm's code and @isaacs work.

mit  ·  ·  @mklabs