tabalot

Tab complete all the things

tabalot

Tab complete all the things!

npm install tabalot

tabalot is a node module that lets you build command line apps with rich built in tab completion support

Lets make a sample app and link it with npm. Write the example below to a file called app.js

#!/usr/bin/env node
var tab = require('tabalot');
 
tab('hello')
    (function() {
        console.log('world');
    })
 
tab.parse();

You need to add a package.json file as well. The one below will make app.js executable as tabtest

{
    "name": "tabtest",
    "bin": {
        "tabtest": "./app.js" // we need a bin name 
    }
}

To try the app locally just use npm to link it

npm link # will add the app to your path

And install the tab completion

tabtest completion --save # installs the completion to your bash_completion.d folder

If you use zsh you can install it with tabtest completion > ~./zshrc

The app is now installed and ready to be tab completed. Open a shell and try the following

tabtest <tab>
tabtest hello <enter>
world

It is as simple as that.

To complete arguments we just need to pass them to tabalot

tab('hello')
    ('--world', '-w', ['world', 'welt', 'verden'])
    ('--debug')
    (function(opts) {
        console.log(opts);
    })

In the above program we just added a boolean argument --debug and a --world argument that should complete to one of the 3 values.

Try running

tabtest <tab>
tabtest hello --<tab><tab>       # prints --world --debug
tabtest hello --world <tab><tab> # prints world verden welt
tabtest hello --world v<tab>
tabtest hello --world verden <enter>

The above program will output

{
    world: 'verden',
    debug: false
}

If you want to complete a positional (or nameless) argument simply omit the name and it will be added as an argument to call function

tab('hello')
    (['world', 'verden', 'welt'])
    (function(worldopts) {
        console.log(world)
    })

Try running

tabtest <tab>
tabtest hello <tab><tab> # prints world verden welt
tabtest hello v<tab>
tabtest hello verden <enter>

The above program will output

verden

Instead of passing the static values ['world', 'welt', 'verden'] we can pass an async function to the completer as well

tab('hello')
    ('--world', '-w', function(callback) {
        callback(null, ['world', 'welt' 'verden']);
    })
    (function(opts) {
        console.log(opts);
    })

If you omit the command name from tab that route will be called and tab completed if no one else matches

tab()
    ('--world', '-w', ['world', 'welt'])
    (function() {
        console.log('I was called by doing tabtest --world world');
    })

Tabalot ships with support for a couple of typical completions. Use these by passing @name as the completer.

tab('hello')
    ('--file', '@file') // completes a file or directory 
    ('--dir', '@dir')   // completes a directory 
    ('--host', '@host') // completes a hostname (by looking at known_hosts) 

License

MIT