serverless-spy
Version:
CDK-based library for writing elegant integration tests on AWS serverless architecture and an additional web console to monitor events in real time.
445 lines (322 loc) • 13.2 kB
Markdown
# tabtab [](http://travis-ci.org/mklabs/node-tabtab)
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.
---
<!-- toc -->
* [Install](#install)
* [Documentation](#documentation)
* [API](#api)
* [Completion description](#completion-description)
* [package.json](#packagejson)
* [Completions](#completions)
* [Manual Installation](#manual-installation)
* [Automatic Installation](#automatic-installation)
* [npm script:install](#npm-scriptinstall)
* [Completion for other programs](#completion-for-other-programs)
* [nvm](#nvm)
* [Bower](#bower)
* [Yeoman](#yeoman)
* [CLI](#cli)
* [tabtab install](#tabtab-install)
* [tabtab uninstall](#tabtab-uninstall)
* [Credits](#credits)
<!-- toc stop -->
## Install
npm install tabtab --save
## Documentation
### API
You can add completion pretty easily in your node cli script:
```js
#! /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.
tab.start();
```
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 foobar<tab><tab>rrrrrr
* `last`: last word of the line
* `lastPartial`: last partial of the line
* `prev`: the previous word
#### Options
```js
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:
```js
'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
```shell
$ program <tab>
command - description for command
````
Example for fish
```fish
$ program <tab>
command (description for command)
```
### package.json
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:
```js
{
"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:
```js
require('tabtab')().start();
```
## Completions
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](https://docs.npmjs.com/cli/completion):
. <(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.
```json
{
"scripts": {
"install": "tabtab install"
}
}
```
On install, npm will execute the `tabtab install` command automatically in the
context of your package.
Ex.
```json
{
"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](https://github.com/SBoudrias/Inquirer.js/) to ask the user what it
should do:



#### 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/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
#### nvm
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`.
```json
{
"name": "nvm-complete",
"bin": "./index.js",
"scripts": {
"install": "tabtab install --name nvm --completer nvm-complete"
},
"dependencies": {
"tabtab": "^1.0.0"
}
}
```
```js
// index.js
var tabtab = require('tabtab');
tabtab.on('nvm', function(data, done) {
return done(null, ['ls', 'ls-remote', 'install', 'use', ...]);
});
tabtab.start();
```
Alternatively, we can use tabtab property in package.json file to define static
list of completion results:
```json
{
"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>`.
```js
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).
#### Bower
**[examples/bower-complete](./examples/bower-complete#readme)**

#### Yeoman
**[examples/yo-complete](./examples/yo-complete#readme)**


### 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.
```js
const debug = require('tabtab/lib/debug')('tabtab:name');
```
## CLI
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]
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/config.fish)
Commands:
install Install and enable completion file on user system
uninstall Undo the install command (only works with --auto)
### tabtab install
$ tabtab install --help
options:
--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/config.fish).
Only works with `--auto` flag.
## credits
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](https://raw.github.com/isaacs/npm/caafb7323708e113d100e3e8145b949ed7a16c22/lib/utils/completion.sh)
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](./license) ·
> [mkla.bz](http://mkla.bz) ·
> [@mklabs](https://github.com/mklabs)