Ecosyste.ms: Awesome
An open API service indexing awesome lists of open source software.
https://github.com/f/omelette
Omelette is a simple, template based autocompletion tool for Node and Deno projects with super easy API. (For Bash, Zsh and Fish)
https://github.com/f/omelette
autocompletion cli
Last synced: 25 days ago
JSON representation
Omelette is a simple, template based autocompletion tool for Node and Deno projects with super easy API. (For Bash, Zsh and Fish)
- Host: GitHub
- URL: https://github.com/f/omelette
- Owner: f
- License: mit
- Created: 2013-04-26T03:13:54.000Z (over 11 years ago)
- Default Branch: master
- Last Pushed: 2022-01-21T18:01:33.000Z (almost 3 years ago)
- Last Synced: 2024-05-17T06:46:11.079Z (6 months ago)
- Topics: autocompletion, cli
- Language: CoffeeScript
- Homepage:
- Size: 1.99 MB
- Stars: 1,379
- Watchers: 22
- Forks: 39
- Open Issues: 16
-
Metadata Files:
- Readme: README.md
- Funding: .github/FUNDING.yml
- License: LICENSE
Awesome Lists containing this project
- awesome-nodejs-cn - omelette - Shell 下的自动补全 (包 / 命令行工具)
- awesome-nodejs-cn - omelette - **star:1379** shell自动完成帮助程序 (包 / 命令行实用工具)
- awesome-list - omelette
- awesome-nodejs - omelette - Shell autocompletion helper. (Packages / Command-line utilities)
- awesome-node - omelette - Shell autocompletion helper. (Packages / Command-line utilities)
- awesome-nodejs-cn - omelette - Shell自动完成帮助程序. (目录 / 命令行工具)
- awesome-nodejs - omelette - Omelette is a simple, template based autocompletion tool for Node projects with super easy API. (For Bash, Zsh and Fish) - ★ 771 (Command-line utilities)
README
> Omelette is a simple template based autocompletion tool for **Node** and **Deno** projects with super easy API.
[![npm version](https://badge.fury.io/js/omelette.svg)](https://badge.fury.io/js/omelette)
[![Build Status](https://travis-ci.org/f/omelette.svg?branch=master)](https://travis-ci.org/f/omelette)```bash
yarn add omelette
# or
npm install omelette
```You also can use Omelette with **Deno**:
```typescript
import omelette from "https://deno.land/x/omelette/omelette.ts";
```You just have to decide your program name and CLI fragments.
```javascript
omelette`github ${['pull', 'push']} ${['origin', 'upstream']} ${['master', 'develop']}`.init()
```...and you are almost done! The output will look like this:
## Quick Start
**For a step by step guide please follow [this link](https://github.com/f/omelette/issues/33#issuecomment-439864555)**
Implementing omelette is very easy:
```javascript
import * as omelette from 'omelette';const firstArgument = ({ reply }) => {
reply([ 'beautiful', 'cruel', 'far' ])
}const planet = ({ reply }) => {
reply([ 'world', 'mars', 'pluto' ])
}omelette`hello|hi ${firstArgument} ${planet}`.init()
```### Simple Event Based API ☕️
It's based on a simple CLI template.
Let's think we have a executable file with the name **githubber**, *in a global path*.
In our program, the code will be:
```javascript
import * as omelette from 'omelette';// Write your CLI template.
const completion = omelette(`githubber|gh `);// Bind events for every template part.
completion.on('action', ({ reply }) => {
reply([ 'clone', 'update', 'push' ])
})completion.on('user', ({ reply }) => {
reply(fs.readdirSync('/Users/'))
})completion.on('repo', ({ before, reply }) => {
reply([
`http://github.com/${before}/helloworld`,
`http://github.com/${before}/blabla`
])
})// Initialize the omelette.
completion.init()// If you want to have a setup feature, you can use `omeletteInstance.setupShellInitFile()` function.
if (~process.argv.indexOf('--setup')) {
completion.setupShellInitFile()
}// Similarly, if you want to tear down autocompletion, use `omeletteInstance.cleanupShellInitFile()`
if (~process.argv.indexOf('--cleanup')) {
completion.cleanupShellInitFile()
}// Rest is yours
console.log("Your program's default workflow.")
console.log(process.argv)
````complete.reply` is the completion replier. You must pass the options into that method.
### ES6 Template Literal API 🚀
You can use **Template Literals** to define your completion with a simpler (super easy) API.
```javascript
import * as omelette from 'omelette';// Just pass a template literal to use super easy API.
omelette`hello ${[ 'cruel', 'nice' ]} ${[ 'world', 'mars' ]}`.init()
```Let's make the example above with ES6 TL:
```javascript
import * as omelette from 'omelette'// Write your CLI template.
omelette`
githubber|gh${[ 'clone', 'update', 'push' ]}
${() => fs.readdirSync('/Users/')}
${({ before }) => [
`http://github.com/${before}/helloworld`,
`http://github.com/${before}/blabla`,
]}
`.init()
```Also you can still use lambda functions to make more complex template literals:
#### Advanced Template Literals
```javascript
import * as omelette from 'omelette';omelette`
githubber|gh
${['pull', 'push', 'star'] /* Direct command list */}
${require('some/other/commands') /* Import from another file */}
${getFromRemote('http://api.example.com/commands') /* Remote call at the beginning */}
${({ reply }) => fetch('http://api.example.com/lazy-commands').then(reply) /* Fetch when argument bed */}
${() => fs.readdirSync("/Users/") /* Access filesystem via Node */}
${({ before }) => [ /* Use parameters like `before`, `line`, `fragment` or `reply` */
`${before}/helloworld`,
`${before}/blabla`
]}
`.init()// No extra configuration required.
console.log("Your program's default workflow.")
console.log(process.argv)
```### Async API ⏩
Omelette allows you to use `async` functions. You have to use `onAsync` and to pass `Promise` object to the `reply` function.
```javascript
complete.onAsync('user', async ({ reply }) => {
reply(new Promise((resolve) => {
fs.readdir('/Users/', (err, users) => {
resolve(users)
})
}))
})
```#### ⚠️ A note about `async` handlers
If you are using async handlers, you have to use `complete.next` method to continue running your main workflow.
```javascript
// ...complete.onAsync('user', async ({ reply }) => {
reply(new Promise((resolve) => {
fs.readdir('/Users/', (err, users) => {
resolve(users)
})
}))
})// Instead of running directly, you need to set an handler to run your main workflow.
complete.next(()=> {
console.log("Your program's default workflow.")
console.log(process.argv)
})// .init must be called after defining .next
complete.init()
// ...
```Using `util.promisify` will make your `async` handlers easier.
```javascript
import promisify from 'util';complete.onAsync('user', async ({ reply }) => {
reply(await promisify(fs.readdir)('/Users'))
})
```### Tree API 🌲
You can use `simple objects` as autocompletion definitions:
```javascript
omelette('hello').tree({
cruel: ['world', 'moon'],
beautiful: ['mars', 'pluto']
}).init();
```## Install
### Automated Install
> ⚠️ Not available for Deno runtime. You can make your users to put `yourprogram --completion | source` or `yourprogram --completion-fish | source` args explicitly to their shell config file.
Installing and making your users install the autocompletion feature is very simple.
You can use simply use `setupShellInitFile` function.
```javascript
try {
// Pick shell init file automatically
complete.setupShellInitFile()// Or use a manually defined init file
complete.setupShellInitFile('~/.my_bash_profile')} catch (err) {
// setupShellInitFile() throws if the used shell is not supported
}
```If you use Bash, it will create a file at `~/./completion.sh` and
append a loader code to `~/.bash_profile` file.If you use Zsh, it appends a loader code to `~/.zshrc` file.
If you use Fish, it appends a loader code to `~/.config/fish/config.fish` file.
*TL;DR: It does the Manual Install part, basically.*
### Automated Uninstallation
> ⚠️ Not available for Deno runtime. Your users need to remove the autocompletion setup script from their shell config files.
Similarly to installation, you can use `cleanupShellInitFile` to undo changes done by `setupShellInitFile`.
```javascript
complete.cleanupShellInitFile()
```As with `setupShellInitFile()`, wrap this in a `try/catch` block to handle unsupported shells.
### Manual Installation
#### Instructions for your README files:
*(You should add these instructions to your project's README, don't forget to replace `myprogram` string with your own executable name)*
In **zsh**, you should write these:
```bash
echo '. <(myprogram --completion)' >> ~/.zshrc
```In **bash**:
On macOS, you may need to install `bash-completion` using `brew install bash-completion`.
```bash
myprogram --completion >> ~/.config/hello.completion.sh
echo 'source ~/.config/hello.completion.sh' >> ~/.bash_profile
```In **fish**:
```bash
echo 'myprogram --completion-fish | source' >> ~/.config/fish/config.fish
```That's all!
Now you have an autocompletion system for your CLI tool.
## Additions
There are some useful additions to omelette.
### Parameters
Callbacks have two parameters:
- The fragment name (e.g.`command` of `` template) *(only in global event)*
- The meta data
- `fragment`: The number of fragment.
- `before`: The previous word.
- `line`: The whole command line buffer allow you to parse and reply as you wish.
- `reply`: This is the reply function to use *this-less* API.### Global Event
You can also listen to all fragments by "complete" event.
```javascript
complete.on('complete', (fragment, { reply }) => reply(["hello", "world"]));
```### Numbered Arguments
You can also listen to events in order.
```javascript
complete.on('$1', ({ reply }) => reply(["hello", "world"]))
```### Autocompletion Tree
You can create a **completion tree** to more complex autocompletions.
```js
omelette('hello').tree({
how: {
much: {
is: {
this: ['car'],
that: ['house'],
}
},
are: ['you'],
many: ['cars', 'houses'],
},
where: {
are: {
you: ['from'],
the: ['houses', 'cars'],
},
is: {
// You can also add some logic with defining functions:
your() {
return ['house', 'car'];
},
}
},
}).init()
```Now, you will be able to use your completion as tree.
> Thanks [@jblandry](https://github.com/jblandry) for the idea.
#### Advanced Tree Implementations
You can seperate your autocompletion by importing objects from another file:
```js
omelette('hello').tree(require('./autocompletion-tree.js')).init();
```### Short Names
You can set a short name for an executable:
In this example, `githubber` is long and `gh` is short.
```javascript
omelette('githubber|gh ');
```## Test
Now you can try it in your shell.
```bash
git clone https://github.com/f/omelette
cd omelette/example
alias githubber="./githubber" # The app should be global, completion will search it on global level.
./githubber --setup --debug # --setup is not provided by omelette, you should proxy it.
# (reload bash, or source ~/.bash_profile or ~/.config/fish/config.fish)
omelette-debug-githubber # See Debugging section
githubber
ghb # short alias
gh # short alias
```### Debugging
`--debug` option generates a function called `omelette-debug-`.
(`omelette-debug-githubber` in this example).When you run `omelette-debug-`, it will create aliases for your
application. (`githubber` and `gh` in this example).A long name:
```bash
$ githubber
clone update push
```Or short name:
```bash
$ gh
clone update push
```Then you can start easily.
```bash
$ ./githubber
clone update push
``````bash
$ ./githubber cl
$ ./githubber clone
Guest fka
``````bash
$ ./githubber clone fka
$ ./githubber clone fka http://github.com/fka/
http://github.com/fka/helloworld
http://github.com/fka/blabla
```## Using with Deno
Omelette now supports and is useful with **Deno**. You can make your Deno based CLI tools autocomplete powered using Omelette. It's fully featured but `setupShellInitFile` and `cleanupShellInitFile` methods does not exist for now (to prevent requirement of `allow-env`, `allow-read` and `allow-write` permissions).
### Instructions to use Omelette in your Deno projects:
Assume we have a `hello.js`:
```typescript
import omelette from "https://raw.githubusercontent.com/f/omelette/master/deno/omelette.ts";const complete = omelette("hello ");
complete.on("action", function ({ reply }) {
reply(["world", "mars", "jupiter"]);
});complete.init();
// your CLI program
```Install your program using `deno install`:
```bash
deno install hello.js
hello --completion | source # bash and zsh installation
hello --completion-fish | source # fish shell installation
```That's all! Now you have autocompletion feature!
```bash
hello
```## Users?
- **Office 365 CLI** uses Omelette to support autocompletion in [office365-cli](https://github.com/pnp/office365-cli).
- **Visual Studio App Center CLI** uses Omelette to support autocompletion in [appcenter-cli](https://github.com/Microsoft/appcenter-cli).## Contribute
I need your contributions to make that work better!
## License
This project licensed under MIT.