{"id":13454158,"url":"https://github.com/f/omelette","last_synced_at":"2025-05-14T14:02:04.601Z","repository":{"id":37444595,"uuid":"9686495","full_name":"f/omelette","owner":"f","description":"Omelette is a simple, template based autocompletion tool for Node and Deno projects with super easy API. (For Bash, Zsh and Fish)","archived":false,"fork":false,"pushed_at":"2022-01-21T18:01:33.000Z","size":2088,"stargazers_count":1393,"open_issues_count":21,"forks_count":40,"subscribers_count":20,"default_branch":"master","last_synced_at":"2025-05-04T16:50:15.462Z","etag":null,"topics":["autocompletion","cli"],"latest_commit_sha":null,"homepage":"","language":"CoffeeScript","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/f.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":".github/FUNDING.yml","license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null},"funding":{"patreon":"fka"}},"created_at":"2013-04-26T03:13:54.000Z","updated_at":"2025-04-28T07:25:02.000Z","dependencies_parsed_at":"2022-07-20T12:17:36.788Z","dependency_job_id":null,"html_url":"https://github.com/f/omelette","commit_stats":null,"previous_names":[],"tags_count":23,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/f%2Fomelette","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/f%2Fomelette/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/f%2Fomelette/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/f%2Fomelette/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/f","download_url":"https://codeload.github.com/f/omelette/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":254159140,"owners_count":22024558,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["autocompletion","cli"],"created_at":"2024-07-31T08:00:51.443Z","updated_at":"2025-05-14T14:02:04.543Z","avatar_url":"https://github.com/f.png","language":"CoffeeScript","readme":"\u003cimg src=\"https://rawgit.com/f/omelette/master/resources/logo.svg?v1\" height=\"80\"\u003e\n\n\u003e Omelette is a simple template based autocompletion tool for **Node** and **Deno** projects with super easy API.\n\n[![npm version](https://badge.fury.io/js/omelette.svg)](https://badge.fury.io/js/omelette)\n[![Build Status](https://travis-ci.org/f/omelette.svg?branch=master)](https://travis-ci.org/f/omelette)\n\n```bash\nyarn add omelette\n# or\nnpm install omelette\n```\n\nYou also can use Omelette with **Deno**:\n\n```typescript\nimport omelette from \"https://deno.land/x/omelette/omelette.ts\";\n```\n\nYou just have to decide your program name and CLI fragments.\n\n```javascript\nomelette`github ${['pull', 'push']} ${['origin', 'upstream']} ${['master', 'develop']}`.init()\n```\n\n...and you are almost done! The output will look like this:\n\n\u003cimg src=\"https://raw.github.com/f/omelette/master/resources/omelette-new.gif?v1\" width=\"640\"\u003e\n\n## Quick Start\n\n**For a step by step guide please follow [this link](https://github.com/f/omelette/issues/33#issuecomment-439864555)**\n\nImplementing omelette is very easy:\n\n```javascript\nimport * as omelette from 'omelette';\n\nconst firstArgument = ({ reply }) =\u003e {\n  reply([ 'beautiful', 'cruel', 'far' ])\n}\n\nconst planet = ({ reply }) =\u003e {\n  reply([ 'world', 'mars', 'pluto' ])\n}\n\nomelette`hello|hi ${firstArgument} ${planet}`.init()\n```\n\n\u003cimg src=\"https://raw.github.com/f/omelette/master/resources/omelette-new-hello.gif?v1\" width=\"640\"\u003e\n\n### Simple Event Based API ☕️\n\nIt's based on a simple CLI template.\n\nLet's think we have a executable file with the name **githubber**, *in a global path*.\n\nIn our program, the code will be:\n\n```javascript\nimport * as omelette from 'omelette';\n\n// Write your CLI template.\nconst completion = omelette(`githubber|gh \u003caction\u003e \u003cuser\u003e \u003crepo\u003e`);\n\n// Bind events for every template part.\ncompletion.on('action', ({ reply }) =\u003e {\n  reply([ 'clone', 'update', 'push' ])\n})\n\ncompletion.on('user', ({ reply }) =\u003e {\n  reply(fs.readdirSync('/Users/'))\n})\n\ncompletion.on('repo', ({ before, reply }) =\u003e {\n  reply([\n    `http://github.com/${before}/helloworld`,\n    `http://github.com/${before}/blabla`\n  ])\n})\n\n// Initialize the omelette.\ncompletion.init()\n\n// If you want to have a setup feature, you can use `omeletteInstance.setupShellInitFile()` function.\nif (~process.argv.indexOf('--setup')) {\n  completion.setupShellInitFile()\n}\n\n// Similarly, if you want to tear down autocompletion, use `omeletteInstance.cleanupShellInitFile()`\nif (~process.argv.indexOf('--cleanup')) {\n  completion.cleanupShellInitFile()\n}\n\n// Rest is yours\nconsole.log(\"Your program's default workflow.\")\nconsole.log(process.argv)\n```\n\n`complete.reply` is the completion replier. You must pass the options into that method.\n\n### ES6 Template Literal API 🚀\n\nYou can use **Template Literals** to define your completion with a simpler (super easy) API.\n\n```javascript\nimport * as omelette from 'omelette';\n\n// Just pass a template literal to use super easy API.\nomelette`hello ${[ 'cruel', 'nice' ]} ${[ 'world', 'mars' ]}`.init()\n```\n\nLet's make the example above with ES6 TL:\n\n```javascript\nimport * as omelette from 'omelette'\n\n// Write your CLI template.\nomelette`\n  githubber|gh\n\n  ${[ 'clone', 'update', 'push' ]}\n  ${() =\u003e fs.readdirSync('/Users/')}\n  ${({ before }) =\u003e [\n    `http://github.com/${before}/helloworld`,\n    `http://github.com/${before}/blabla`,\n  ]}\n`.init()\n```\n\nAlso you can still use lambda functions to make more complex template literals:\n\n#### Advanced Template Literals\n\n```javascript\nimport * as omelette from 'omelette';\n\nomelette`\n  githubber|gh\n      ${['pull', 'push', 'star'] /* Direct command list */}\n      ${require('some/other/commands') /* Import from another file */}\n      ${getFromRemote('http://api.example.com/commands') /* Remote call at the beginning */}\n      ${({ reply }) =\u003e fetch('http://api.example.com/lazy-commands').then(reply) /* Fetch when argument \u003ctab\u003ebed */}\n      ${() =\u003e fs.readdirSync(\"/Users/\") /* Access filesystem via Node */}\n      ${({ before }) =\u003e [ /* Use parameters like `before`, `line`, `fragment` or `reply` */\n        `${before}/helloworld`,\n        `${before}/blabla`\n      ]}\n  `.init()\n\n// No extra configuration required.\n\nconsole.log(\"Your program's default workflow.\")\nconsole.log(process.argv)\n```\n\n### Async API ⏩\n\nOmelette allows you to use `async` functions. You have to use `onAsync` and to pass `Promise` object to the `reply` function.\n\n```javascript\ncomplete.onAsync('user', async ({ reply }) =\u003e {\n  reply(new Promise((resolve) =\u003e {\n    fs.readdir('/Users/', (err, users) =\u003e {\n      resolve(users)\n    })\n  }))\n})\n```\n\n#### ⚠️ A note about `async` handlers\n\nIf you are using async handlers, you have to use `complete.next` method to continue running your main workflow.\n\n```javascript\n// ...\n\ncomplete.onAsync('user', async ({ reply }) =\u003e {\n  reply(new Promise((resolve) =\u003e {\n    fs.readdir('/Users/', (err, users) =\u003e {\n      resolve(users)\n    })\n  }))\n})\n\n// Instead of running directly, you need to set an handler to run your main workflow.\ncomplete.next(()=\u003e {\n  console.log(\"Your program's default workflow.\")\n  console.log(process.argv)\n})\n\n// .init must be called after defining .next\ncomplete.init()\n// ...\n```\n\nUsing `util.promisify` will make your `async` handlers easier.\n\n```javascript\nimport promisify from 'util';\n\ncomplete.onAsync('user', async ({ reply }) =\u003e {\n  reply(await promisify(fs.readdir)('/Users'))\n})\n```\n\n### Tree API 🌲\n\nYou can use `simple objects` as autocompletion definitions:\n\n```javascript\nomelette('hello').tree({\n  cruel: ['world', 'moon'],\n  beautiful: ['mars', 'pluto']\n}).init();\n```\n\n## Install\n\n### Automated Install\n\n\u003e ⚠️ 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.\n\nInstalling and making your users install the autocompletion feature is very simple.\n\nYou can use simply use `setupShellInitFile` function.\n\n```javascript\ntry {\n  // Pick shell init file automatically\n  complete.setupShellInitFile()\n\n  // Or use a manually defined init file\n  complete.setupShellInitFile('~/.my_bash_profile')\n\n} catch (err) {\n  // setupShellInitFile() throws if the used shell is not supported\n}\n```\n\nIf you use Bash, it will create a file at `~/.\u003cprogram-name\u003e/completion.sh` and\nappend a loader code to `~/.bash_profile` file.\n\nIf you use Zsh, it appends a loader code to `~/.zshrc` file.\n\nIf you use Fish, it appends a loader code to `~/.config/fish/config.fish` file.\n\n*TL;DR: It does the Manual Install part, basically.*\n\n### Automated Uninstallation\n\n\u003e ⚠️ Not available for Deno runtime. Your users need to remove the autocompletion setup script from their shell config files.\n\nSimilarly to installation, you can use `cleanupShellInitFile` to undo changes done by `setupShellInitFile`.\n\n```javascript\ncomplete.cleanupShellInitFile()\n```\n\nAs with `setupShellInitFile()`, wrap this in a `try/catch` block to handle unsupported shells.\n\n### Manual Installation\n\n#### Instructions for your README files:\n\n*(You should add these instructions to your project's README, don't forget to replace `myprogram` string with your own executable name)*\n\nIn **zsh**, you should write these:\n\n```bash\necho '. \u003c(myprogram --completion)' \u003e\u003e ~/.zshrc\n```\n\nIn **bash**:\n\nOn macOS, you may need to install `bash-completion` using `brew install bash-completion`.\n\n```bash\nmyprogram --completion \u003e\u003e ~/.config/hello.completion.sh\necho 'source ~/.config/hello.completion.sh' \u003e\u003e ~/.bash_profile\n```\n\nIn **fish**:\n\n```bash\necho 'myprogram --completion-fish | source' \u003e\u003e ~/.config/fish/config.fish\n```\n\nThat's all!\n\nNow you have an autocompletion system for your CLI tool.\n\n## Additions\n\nThere are some useful additions to omelette.\n\n### Parameters\n\nCallbacks have two parameters:\n\n  - The fragment name (e.g.`command` of `\u003ccommand\u003e` template) *(only in global event)*\n  - The meta data\n    - `fragment`: The number of fragment.\n    - `before`: The previous word.\n    - `line`: The whole command line buffer allow you to parse and reply as you wish.\n    - `reply`: This is the reply function to use *this-less* API.\n\n### Global Event\n\nYou can also listen to all fragments by \"complete\" event.\n\n```javascript\ncomplete.on('complete', (fragment, { reply }) =\u003e reply([\"hello\", \"world\"]));\n```\n\n### Numbered Arguments\n\nYou can also listen to events in order.\n\n```javascript\ncomplete.on('$1', ({ reply }) =\u003e reply([\"hello\", \"world\"]))\n```\n\n### Autocompletion Tree\n\nYou can create a **completion tree** to more complex autocompletions.\n\n```js\nomelette('hello').tree({\n  how: {\n    much: {\n      is: {\n        this: ['car'],\n        that: ['house'],\n      }\n    },\n    are: ['you'],\n    many: ['cars', 'houses'],\n  },\n  where: {\n    are: {\n      you: ['from'],\n      the: ['houses', 'cars'],\n    },\n    is: {\n      // You can also add some logic with defining functions:\n      your() {\n        return ['house', 'car'];\n      },\n    }\n  },\n}).init()\n```\n\nNow, you will be able to use your completion as tree.\n\n\u003cimg src=\"https://raw.github.com/f/omelette/master/resources/omelette-tree-new.gif?v1\" width=\"640\"\u003e\n\n\u003e Thanks [@jblandry](https://github.com/jblandry) for the idea.\n\n#### Advanced Tree Implementations\n\nYou can seperate your autocompletion by importing objects from another file:\n\n```js\nomelette('hello').tree(require('./autocompletion-tree.js')).init();\n```\n\n### Short Names\n\nYou can set a short name for an executable:\n\nIn this example, `githubber` is long and `gh` is short.\n\n```javascript\nomelette('githubber|gh \u003cmodule\u003e \u003ccommand\u003e \u003csuboption\u003e');\n```\n\n## Test\n\nNow you can try it in your shell.\n\n```bash\ngit clone https://github.com/f/omelette\ncd omelette/example\nalias githubber=\"./githubber\" # The app should be global, completion will search it on global level.\n./githubber --setup --debug # --setup is not provided by omelette, you should proxy it.\n# (reload bash, or source ~/.bash_profile or ~/.config/fish/config.fish)\nomelette-debug-githubber # See Debugging section\ngithubber\u003ctab\u003e\nghb\u003ctab\u003e # short alias\ngh\u003ctab\u003e # short alias\n```\n\n### Debugging\n\n`--debug` option generates a function called `omelette-debug-\u003cprogramname\u003e`.\n(`omelette-debug-githubber` in this example).\n\nWhen you run `omelette-debug-\u003cprogramname\u003e`, it will create aliases for your\napplication. (`githubber` and `gh` in this example).\n\nA long name:\n\n```bash\n$ githubber\u003ctab\u003e\nclone update push\n```\n\nOr short name:\n\n```bash\n$ gh\u003ctab\u003e\nclone update push\n```\n\nThen you can start easily.\n\n```bash\n$ ./githubber\u003ctab\u003e\nclone update push\n```\n\n```bash\n$ ./githubber cl\u003ctab\u003e\n$ ./githubber clone\u003ctab\u003e\nGuest fka\n```\n\n```bash\n$ ./githubber clone fka\u003ctab\u003e\n$ ./githubber clone fka http://github.com/fka/\u003ctab\u003e\nhttp://github.com/fka/helloworld\nhttp://github.com/fka/blabla\n```\n\n## Using with Deno\n\nOmelette 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).\n\n### Instructions to use Omelette in your Deno projects:\n\nAssume we have a `hello.js`:\n\n```typescript\nimport omelette from \"https://raw.githubusercontent.com/f/omelette/master/deno/omelette.ts\";\n\nconst complete = omelette(\"hello \u003caction\u003e\");\n\ncomplete.on(\"action\", function ({ reply }) {\n  reply([\"world\", \"mars\", \"jupiter\"]);\n});\n\ncomplete.init();\n\n// your CLI program\n```\n\nInstall your program using `deno install`:\n\n```bash\ndeno install hello.js\nhello --completion | source # bash and zsh installation\nhello --completion-fish | source # fish shell installation\n```\n\nThat's all! Now you have autocompletion feature!\n\n```bash\nhello \u003ctab\u003e\u003ctab\u003e\n```\n\n## Users?\n\n- **Office 365 CLI** uses Omelette to support autocompletion in [office365-cli](https://github.com/pnp/office365-cli).\n- **Visual Studio App Center CLI** uses Omelette to support autocompletion in [appcenter-cli](https://github.com/Microsoft/appcenter-cli).\n\n## Contribute\n\nI need your contributions to make that work better!\n\n## License\n\nThis project licensed under MIT.\n","funding_links":["https://patreon.com/fka"],"categories":["Packages","CoffeeScript","包","目录","cli","Command-line utilities"],"sub_categories":["Command-line utilities","命令行工具","命令行实用工具"],"project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Ff%2Fomelette","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Ff%2Fomelette","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Ff%2Fomelette/lists"}