├── .editorconfig ├── .eslintrc.json ├── .gitattributes ├── .github └── contributing.md ├── .gitignore ├── .verb.md ├── LICENSE ├── README.md ├── example.gif ├── examples ├── enquirer.js ├── prompt.js └── states.js ├── index.js └── package.json /.editorconfig: -------------------------------------------------------------------------------- 1 | # http://editorconfig.org/ 2 | root = true 3 | 4 | [*] 5 | charset = utf-8 6 | end_of_line = lf 7 | indent_size = 2 8 | indent_style = space 9 | insert_final_newline = true 10 | trim_trailing_whitespace = true 11 | 12 | [{**/{actual,fixtures,expected,templates}/**,*.md}] 13 | trim_trailing_whitespace = false 14 | insert_final_newline = false 15 | -------------------------------------------------------------------------------- /.eslintrc.json: -------------------------------------------------------------------------------- 1 | { 2 | "env": { 3 | "browser": false, 4 | "es6": true, 5 | "node": true, 6 | "mocha": true 7 | }, 8 | 9 | "globals": { 10 | "document": false, 11 | "navigator": false, 12 | "window": false 13 | }, 14 | 15 | "rules": { 16 | "accessor-pairs": 2, 17 | "arrow-spacing": [2, { "before": true, "after": true }], 18 | "block-spacing": [2, "always"], 19 | "brace-style": [2, "1tbs", { "allowSingleLine": true }], 20 | "comma-dangle": [2, "never"], 21 | "comma-spacing": [2, { "before": false, "after": true }], 22 | "comma-style": [2, "last"], 23 | "constructor-super": 2, 24 | "curly": [2, "multi-line"], 25 | "dot-location": [2, "property"], 26 | "eol-last": 2, 27 | "eqeqeq": [2, "allow-null"], 28 | "generator-star-spacing": [2, { "before": true, "after": true }], 29 | "handle-callback-err": [2, "^(err|error)$" ], 30 | "indent": [2, 2, { "SwitchCase": 1 }], 31 | "key-spacing": [2, { "beforeColon": false, "afterColon": true }], 32 | "keyword-spacing": [2, { "before": true, "after": true }], 33 | "new-cap": [2, { "newIsCap": true, "capIsNew": false }], 34 | "new-parens": 2, 35 | "no-array-constructor": 2, 36 | "no-caller": 2, 37 | "no-class-assign": 2, 38 | "no-cond-assign": 2, 39 | "no-const-assign": 2, 40 | "no-control-regex": 2, 41 | "no-debugger": 2, 42 | "no-delete-var": 2, 43 | "no-dupe-args": 2, 44 | "no-dupe-class-members": 2, 45 | "no-dupe-keys": 2, 46 | "no-duplicate-case": 2, 47 | "no-empty-character-class": 2, 48 | "no-eval": 2, 49 | "no-ex-assign": 2, 50 | "no-extend-native": 2, 51 | "no-extra-bind": 2, 52 | "no-extra-boolean-cast": 2, 53 | "no-extra-parens": [2, "functions"], 54 | "no-fallthrough": 2, 55 | "no-floating-decimal": 2, 56 | "no-func-assign": 2, 57 | "no-implied-eval": 2, 58 | "no-inner-declarations": [2, "functions"], 59 | "no-invalid-regexp": 2, 60 | "no-irregular-whitespace": 2, 61 | "no-iterator": 2, 62 | "no-label-var": 2, 63 | "no-labels": 2, 64 | "no-lone-blocks": 2, 65 | "no-mixed-spaces-and-tabs": 2, 66 | "no-multi-spaces": 2, 67 | "no-multi-str": 2, 68 | "no-multiple-empty-lines": [2, { "max": 1 }], 69 | "no-native-reassign": 0, 70 | "no-negated-in-lhs": 2, 71 | "no-new": 2, 72 | "no-new-func": 2, 73 | "no-new-object": 2, 74 | "no-new-require": 2, 75 | "no-new-wrappers": 2, 76 | "no-obj-calls": 2, 77 | "no-octal": 2, 78 | "no-octal-escape": 2, 79 | "no-proto": 0, 80 | "no-redeclare": 2, 81 | "no-regex-spaces": 2, 82 | "no-return-assign": 2, 83 | "no-self-compare": 2, 84 | "no-sequences": 2, 85 | "no-shadow-restricted-names": 2, 86 | "no-spaced-func": 2, 87 | "no-sparse-arrays": 2, 88 | "no-this-before-super": 2, 89 | "no-throw-literal": 2, 90 | "no-trailing-spaces": 0, 91 | "no-undef": 2, 92 | "no-undef-init": 2, 93 | "no-unexpected-multiline": 2, 94 | "no-unneeded-ternary": [2, { "defaultAssignment": false }], 95 | "no-unreachable": 2, 96 | "no-unused-vars": [2, { "vars": "all", "args": "none" }], 97 | "no-useless-call": 0, 98 | "no-with": 2, 99 | "one-var": [0, { "initialized": "never" }], 100 | "operator-linebreak": [0, "after", { "overrides": { "?": "before", ":": "before" } }], 101 | "padded-blocks": [0, "never"], 102 | "quotes": [2, "single", "avoid-escape"], 103 | "radix": 2, 104 | "semi": [2, "always"], 105 | "semi-spacing": [2, { "before": false, "after": true }], 106 | "space-before-blocks": [2, "always"], 107 | "space-before-function-paren": [2, "never"], 108 | "space-in-parens": [2, "never"], 109 | "space-infix-ops": 2, 110 | "space-unary-ops": [2, { "words": true, "nonwords": false }], 111 | "spaced-comment": [0, "always", { "markers": ["global", "globals", "eslint", "eslint-disable", "*package", "!", ","] }], 112 | "use-isnan": 2, 113 | "valid-typeof": 2, 114 | "wrap-iife": [2, "any"], 115 | "yoda": [2, "never"] 116 | } 117 | } 118 | -------------------------------------------------------------------------------- /.gitattributes: -------------------------------------------------------------------------------- 1 | # Enforce Unix newlines 2 | * text eol=lf 3 | 4 | # binaries 5 | *.ai binary 6 | *.psd binary 7 | *.jpg binary 8 | *.gif binary 9 | *.png binary 10 | *.jpeg binary 11 | -------------------------------------------------------------------------------- /.github/contributing.md: -------------------------------------------------------------------------------- 1 | # Contributing to prompt-autocomplete 2 | 3 | First and foremost, thank you! We appreciate that you want to contribute to prompt-autocomplete, your time is valuable, and your contributions mean a lot to us. 4 | 5 | **What does "contributing" mean?** 6 | 7 | Creating an issue is the simplest form of contributing to a project. But there are many ways to contribute, including the following: 8 | 9 | - Updating or correcting documentation 10 | - Feature requests 11 | - Bug reports 12 | 13 | If you'd like to learn more about contributing in general, the [Guide to Idiomatic Contributing](https://github.com/jonschlinkert/idiomatic-contributing) has a lot of useful information. 14 | 15 | **Showing support for prompt-autocomplete** 16 | 17 | Please keep in mind that open source software is built by people like you, who spend their free time creating things the rest the community can use. 18 | 19 | Don't have time to contribute? No worries, here are some other ways to show your support for prompt-autocomplete: 20 | 21 | - star the [project](https://github.com/jonschlinkert/prompt-autocomplete) 22 | - tweet your support for prompt-autocomplete 23 | 24 | ## Issues 25 | 26 | ### Before creating an issue 27 | 28 | Please try to determine if the issue is caused by an underlying library, and if so, create the issue there. Sometimes this is difficult to know. We only ask that you attempt to give a reasonable attempt to find out. Oftentimes the readme will have advice about where to go to create issues. 29 | 30 | Try to follow these guidelines 31 | 32 | - **Investigate the issue**: 33 | - **Check the readme** - oftentimes you will find notes about creating issues, and where to go depending on the type of issue. 34 | - Create the issue in the appropriate repository. 35 | 36 | ### Creating an issue 37 | 38 | Please be as descriptive as possible when creating an issue. Give us the information we need to successfully answer your question or address your issue by answering the following in your issue: 39 | 40 | - **version**: please note the version of prompt-autocomplete are you using 41 | - **extensions, plugins, helpers, etc** (if applicable): please list any extensions you're using 42 | - **error messages**: please paste any error messages into the issue, or a [gist](https://gist.github.com/) 43 | 44 | ## Above and beyond 45 | 46 | Here are some tips for creating idiomatic issues. Taking just a little bit extra time will make your issue easier to read, easier to resolve, more likely to be found by others who have the same or similar issue in the future. 47 | 48 | - read the [Guide to Idiomatic Contributing](https://github.com/jonschlinkert/idiomatic-contributing) 49 | - take some time to learn basic markdown. This [markdown cheatsheet](https://gist.github.com/jonschlinkert/5854601) is super helpful, as is the GitHub guide to [basic markdown](https://help.github.com/articles/markdown-basics/). 50 | - Learn about [GitHub Flavored Markdown](https://help.github.com/articles/github-flavored-markdown/). And if you want to really go above and beyond, read [mastering markdown](https://guides.github.com/features/mastering-markdown/). 51 | - use backticks to wrap code. This ensures that code will retain its format, making it much more readable to others 52 | - use syntax highlighting by adding the correct language name after the first "code fence" 53 | 54 | 55 | [node-glob]: https://github.com/isaacs/node-glob 56 | [micromatch]: https://github.com/jonschlinkert/micromatch 57 | [so]: http://stackoverflow.com/questions/tagged/prompt-autocomplete 58 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # always ignore files 2 | *.DS_Store 3 | .idea 4 | *.sublime-* 5 | 6 | # test related, or directories generated by tests 7 | test/actual 8 | actual 9 | coverage 10 | .nyc* 11 | 12 | # npm 13 | node_modules 14 | npm-debug.log 15 | 16 | # yarn 17 | yarn.lock 18 | yarn-error.log 19 | 20 | # misc 21 | _gh_pages 22 | _draft 23 | _drafts 24 | bower_components 25 | vendor 26 | temp 27 | tmp 28 | TODO.md 29 | package-lock.json -------------------------------------------------------------------------------- /.verb.md: -------------------------------------------------------------------------------- 1 | {{#block "demo"}} 2 | ![{%= alias %} prompt example](https://raw.githubusercontent.com/{%= repo %}/master/example.gif) 3 | {{/block}} 4 | 5 | ## Install 6 | {%= include("install-npm", {save: true}) %} 7 | 8 | ## Example usage 9 | 10 | ```js 11 | var states = ['Alabama', 'Alaska', 'American Samoa', ...]; 12 | var AutoComplete = require('{%= name %}'); 13 | var autocomplete = new AutoComplete({ 14 | type: 'autocomplete', 15 | name: 'from', 16 | message: 'Select a state to travel from', 17 | source: searchStates 18 | }); 19 | 20 | // promise 21 | autocomplete.run() 22 | .then(function(answer) { 23 | console.log(answer); 24 | }); 25 | 26 | // or async 27 | autocomplete 28 | .ask(function(answer) { 29 | console.log(answer); 30 | }); 31 | 32 | function searchStates(answers, input) { 33 | return new Promise(function(resolve) { 34 | resolve(states.filter(filter(input))); 35 | }); 36 | } 37 | 38 | function filter(input) { 39 | return function(state) { 40 | return new RegExp(input, 'i').exec(state) !== null; 41 | }; 42 | } 43 | ``` 44 | 45 | ## Enquirer usage 46 | 47 | ```js 48 | var states = ['Alabama', 'Alaska', 'American Samoa', ...]; 49 | var Enquirer = require('enquirer'); 50 | var enquirer = new Enquirer(); 51 | 52 | enquirer.register('autocomplete', require('{%= name %}')); 53 | var questions = [ 54 | { 55 | type: 'autocomplete', 56 | name: 'from', 57 | message: 'Select a state to travel from', 58 | source: searchStates 59 | }, 60 | { 61 | type: 'autocomplete', 62 | name: 'to', 63 | message: 'Select a state to travel to', 64 | source: searchStates 65 | } 66 | ]; 67 | 68 | enquirer.ask(questions) 69 | .then(function(answers) { 70 | console.log(answers); 71 | }) 72 | .catch(function(err) { 73 | console.log(err); 74 | }); 75 | 76 | function searchStates(answers, input) { 77 | return new Promise(function(resolve) { 78 | resolve(states.filter(filter(input))); 79 | }); 80 | } 81 | 82 | function filter(input) { 83 | return function(state) { 84 | return new RegExp(input, 'i').exec(state) !== null; 85 | }; 86 | } 87 | ``` 88 | 89 | ## Prompts 90 | Other prompt modules: 91 | {%= related(verb.related.prompts) %} 92 | 93 | ## Attribution 94 | This is entirely based on https://www.npmjs.com/package/inquirer-autocomplete-prompt Copyright (c) 2015, Martin Hansen 95 | 96 | Thanks, Martin! 97 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2016-2017, Jon Schlinkert. 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # prompt-autocompletion [![NPM version](https://img.shields.io/npm/v/prompt-autocompletion.svg?style=flat)](https://www.npmjs.com/package/prompt-autocompletion) [![NPM downloads](https://img.shields.io/npm/dm/prompt-autocompletion.svg?style=flat)](https://npmjs.org/package/prompt-autocompletion) 2 | 3 | > Prompt that autocompletes as you type. Can be used standalone or with a prompt system like [enquirer](https://github.com/enquirer/enquirer) 4 | 5 | ![prompt-autocompletion example](https://raw.githubusercontent.com/enquirer/prompt-autocompletion/master/example.gif) 6 | 7 | ## Install 8 | 9 | Install with [npm](https://www.npmjs.com/): 10 | 11 | ```sh 12 | $ npm install --save prompt-autocompletion 13 | ``` 14 | 15 | ## Example usage 16 | 17 | ```js 18 | var states = ['Alabama', 'Alaska', 'American Samoa', ...]; 19 | var AutoComplete = require('prompt-autocompletion'); 20 | var autocomplete = new AutoComplete({ 21 | type: 'autocomplete', 22 | name: 'from', 23 | message: 'Select a state to travel from', 24 | source: searchStates 25 | }); 26 | 27 | // promise 28 | autocomplete.run() 29 | .then(function(answer) { 30 | console.log(answer); 31 | }); 32 | 33 | // or async 34 | autocomplete 35 | .ask(function(answer) { 36 | console.log(answer); 37 | }); 38 | 39 | function searchStates(answers, input) { 40 | return new Promise(function(resolve) { 41 | resolve(states.filter(filter(input))); 42 | }); 43 | } 44 | 45 | function filter(input) { 46 | return function(state) { 47 | return new RegExp(input, 'i').exec(state) !== null; 48 | }; 49 | } 50 | ``` 51 | 52 | ## Enquirer usage 53 | 54 | ```js 55 | var states = ['Alabama', 'Alaska', 'American Samoa', ...]; 56 | var Enquirer = require('enquirer'); 57 | var enquirer = new Enquirer(); 58 | 59 | enquirer.register('autocomplete', require('prompt-autocompletion')); 60 | var questions = [ 61 | { 62 | type: 'autocomplete', 63 | name: 'from', 64 | message: 'Select a state to travel from', 65 | source: searchStates 66 | }, 67 | { 68 | type: 'autocomplete', 69 | name: 'to', 70 | message: 'Select a state to travel to', 71 | source: searchStates 72 | } 73 | ]; 74 | 75 | enquirer.ask(questions) 76 | .then(function(answers) { 77 | console.log(answers); 78 | }) 79 | .catch(function(err) { 80 | console.log(err); 81 | }); 82 | 83 | function searchStates(answers, input) { 84 | return new Promise(function(resolve) { 85 | resolve(states.filter(filter(input))); 86 | }); 87 | } 88 | 89 | function filter(input) { 90 | return function(state) { 91 | return new RegExp(input, 'i').exec(state) !== null; 92 | }; 93 | } 94 | ``` 95 | 96 | ## Prompts 97 | 98 | Other prompt modules: 99 | 100 | * [prompt-checkbox](https://www.npmjs.com/package/prompt-checkbox): Multiple-choice/checkbox prompt. Can be used standalone or with a prompt system like [Enquirer](https://github.com/enquirer/enquirer). | [homepage](https://github.com/enquirer/prompt-checkbox "Multiple-choice/checkbox prompt. Can be used standalone or with a prompt system like [Enquirer].") 101 | * [prompt-confirm](https://www.npmjs.com/package/prompt-confirm): Confirm (yes/no) prompt. Can be used standalone or with a prompt system like [Enquirer](https://github.com/enquirer/enquirer). | [homepage](https://github.com/enquirer/prompt-confirm "Confirm (yes/no) prompt. Can be used standalone or with a prompt system like [Enquirer].") 102 | * [prompt-editor](https://www.npmjs.com/package/prompt-editor): Editor prompt. Opens your text editor and waits for you to save your input during… [more](https://github.com/enquirer/prompt-editor) | [homepage](https://github.com/enquirer/prompt-editor "Editor prompt. Opens your text editor and waits for you to save your input during a prompt. Can be used standalone or with a prompt system like [Enquirer].") 103 | * [prompt-expand](https://www.npmjs.com/package/prompt-expand): Expand prompt. Can be used as a standalone prompt, or with a prompt system like… [more](https://github.com/enquirer/prompt-expand) | [homepage](https://github.com/enquirer/prompt-expand "Expand prompt. Can be used as a standalone prompt, or with a prompt system like [Enquirer].") 104 | * [prompt-list](https://www.npmjs.com/package/prompt-list): List-style prompt. Can be used as a standalone prompt, or with a prompt system like… [more](https://github.com/enquirer/prompt-list) | [homepage](https://github.com/enquirer/prompt-list "List-style prompt. Can be used as a standalone prompt, or with a prompt system like [Enquirer].") 105 | * [prompt-password](https://www.npmjs.com/package/prompt-password): Password prompt. Can be used as a standalone prompt, or with a prompt system like… [more](https://github.com/enquirer/prompt-password) | [homepage](https://github.com/enquirer/prompt-password "Password prompt. Can be used as a standalone prompt, or with a prompt system like [Enquirer].") 106 | * [prompt-radio](https://www.npmjs.com/package/prompt-radio): Radio prompt. This prompt behaves like other radio-button interfaces, where only one choice is enabled… [more](https://github.com/enquirer/prompt-radio) | [homepage](https://github.com/enquirer/prompt-radio "Radio prompt. This prompt behaves like other radio-button interfaces, where only one choice is enabled whilst all others are disabled. Can be used as a standalone prompt, or with a prompt system like [Enquirer].") 107 | * [prompt-rawlist](https://www.npmjs.com/package/prompt-rawlist): Rawlist prompt. Can be used as a standalone prompt, or with a prompt system like… [more](https://github.com/enquirer/prompt-rawlist) | [homepage](https://github.com/enquirer/prompt-rawlist "Rawlist prompt. Can be used as a standalone prompt, or with a prompt system like [Enquirer].") 108 | 109 | ## Attribution 110 | 111 | This is entirely based on https://www.npmjs.com/package/inquirer-autocomplete-prompt Copyright (c) 2015, Martin Hansen [martin@martinhansen.no](mailto:martin@martinhansen.no) 112 | 113 | Thanks, Martin! 114 | 115 | ## About 116 | 117 | ### Contributing 118 | 119 | Pull requests and stars are always welcome. For bugs and feature requests, [please create an issue](../../issues/new). 120 | 121 | Please read the [contributing guide](.github/contributing.md) for avice on opening issues, pull requests, and coding standards. 122 | 123 | ### Running tests 124 | 125 | Install dev dependencies: 126 | 127 | ```sh 128 | $ npm install -d && npm test 129 | ``` 130 | 131 | ### Author 132 | 133 | **Jon Schlinkert** 134 | 135 | * [github/jonschlinkert](https://github.com/jonschlinkert) 136 | * [twitter/jonschlinkert](http://twitter.com/jonschlinkert) 137 | 138 | ### License 139 | 140 | Copyright © 2016, [Jon Schlinkert](https://github.com/jonschlinkert). 141 | Released under the [MIT license](https://github.com/enquirer/prompt-autocompletion/blob/master/LICENSE). 142 | 143 | *** 144 | 145 | _This file was generated by [verb-generate-readme](https://github.com/verbose/verb-generate-readme), v0.1.31, on October 13, 2016._ -------------------------------------------------------------------------------- /example.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/enquirer/prompt-autocompletion/ea9daf347b0129e22a235de82bdc71038d34b341/example.gif -------------------------------------------------------------------------------- /examples/enquirer.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | var states = require('./states'); 4 | var Enquirer = require('enquirer'); 5 | var enquirer = new Enquirer(); 6 | 7 | enquirer.register('autocomplete', require('..')); 8 | var questions = [ 9 | { 10 | type: 'autocomplete', 11 | name: 'from', 12 | message: 'Select a state to travel from', 13 | source: searchStates 14 | }, 15 | { 16 | type: 'autocomplete', 17 | name: 'to', 18 | message: 'Select a state to travel to', 19 | source: searchStates 20 | } 21 | ]; 22 | 23 | enquirer.ask(questions) 24 | .then(function(answers) { 25 | console.log(answers); 26 | }); 27 | 28 | function searchStates(answers, input) { 29 | return new Promise(function(resolve) { 30 | resolve(states.filter(filter(input))); 31 | }); 32 | } 33 | 34 | function filter(input) { 35 | return function(state) { 36 | return new RegExp(input, 'i').exec(state) !== null; 37 | }; 38 | } 39 | -------------------------------------------------------------------------------- /examples/prompt.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | var states = require('./states'); 4 | var Prompt = require('..'); 5 | var prompt = new Prompt({ 6 | name: 'from', 7 | message: 'Select a state to travel from', 8 | source: searchStates 9 | }); 10 | 11 | prompt.run() 12 | .then(function(answer) { 13 | console.log(answer); 14 | }); 15 | 16 | function searchStates(answers, input) { 17 | return new Promise(function(resolve) { 18 | resolve(states.filter(filter(input))); 19 | }); 20 | } 21 | 22 | function filter(input) { 23 | return function(state) { 24 | return new RegExp(input, 'i').exec(state) !== null; 25 | }; 26 | } 27 | -------------------------------------------------------------------------------- /examples/states.js: -------------------------------------------------------------------------------- 1 | module.exports = [ 2 | 'Alabama', 3 | 'Alaska', 4 | 'American Samoa', 5 | 'Arizona', 6 | 'Arkansas', 7 | 'California', 8 | 'Colorado', 9 | 'Connecticut', 10 | 'Delaware', 11 | 'District Of Columbia', 12 | 'Federated States Of Micronesia', 13 | 'Florida', 14 | 'Georgia', 15 | 'Guam', 16 | 'Hawaii', 17 | 'Idaho', 18 | 'Illinois', 19 | 'Indiana', 20 | 'Iowa', 21 | 'Kansas', 22 | 'Kentucky', 23 | 'Louisiana', 24 | 'Maine', 25 | 'Marshall Islands', 26 | 'Maryland', 27 | 'Massachusetts', 28 | 'Michigan', 29 | 'Minnesota', 30 | 'Mississippi', 31 | 'Missouri', 32 | 'Montana', 33 | 'Nebraska', 34 | 'Nevada', 35 | 'New Hampshire', 36 | 'New Jersey', 37 | 'New Mexico', 38 | 'New York', 39 | 'North Carolina', 40 | 'North Dakota', 41 | 'Northern Mariana Islands', 42 | 'Ohio', 43 | 'Oklahoma', 44 | 'Oregon', 45 | 'Palau', 46 | 'Pennsylvania', 47 | 'Puerto Rico', 48 | 'Rhode Island', 49 | 'South Carolina', 50 | 'South Dakota', 51 | 'Tennessee', 52 | 'Texas', 53 | 'Utah', 54 | 'Vermont', 55 | 'Virgin Islands', 56 | 'Virginia', 57 | 'Washington', 58 | 'West Virginia', 59 | 'Wisconsin', 60 | 'Wyoming' 61 | ]; 62 | -------------------------------------------------------------------------------- /index.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | /*! 4 | * This is almost entirely based on: 5 | * https://www.npmjs.com/package/inquirer-autocomplete-prompt 6 | * Copyright (c) 2015, Martin Hansen 7 | */ 8 | 9 | var util = require('util'); 10 | var log = require('log-utils'); 11 | var figures = require('figures'); 12 | var Paginator = require('terminal-paginator'); 13 | var BasePrompt = require('prompt-base'); 14 | var Choices = require('prompt-choices'); 15 | var utils = require('readline-utils'); 16 | 17 | /** 18 | * Create a new autocomplete `Prompt` 19 | */ 20 | 21 | function Prompt() { 22 | BasePrompt.apply(this, arguments); 23 | if (typeof this.question.source !== 'function') { 24 | throw new TypeError('expected source to be defined'); 25 | } 26 | 27 | this.currentChoices = []; 28 | this.firstRender = true; 29 | this.selected = 0; 30 | 31 | // Make sure no default is set (so it won't be printed) 32 | this.question.default = undefined; 33 | this.paginator = new Paginator(); 34 | } 35 | 36 | /** 37 | * Inherit `BasePrompt` 38 | */ 39 | 40 | util.inherits(Prompt, BasePrompt); 41 | 42 | /** 43 | * Start the prompt session 44 | * @param {Function} `cb` Callback when prompt is finished 45 | * @return {Object} Returns the instance for chaining 46 | */ 47 | 48 | Prompt.prototype.ask = function(cb) { 49 | this.callback = cb; 50 | if (Array.isArray(this.rl.history)) { 51 | this.rl.history = []; 52 | } 53 | 54 | this.only('line', this.onSubmit.bind(this)); 55 | this.only('down', this.createChoices.bind(this, '')); 56 | this.only('keypress', this.onKeypress.bind(this)); 57 | 58 | // initialize search 59 | this.search(); 60 | return this; 61 | }; 62 | 63 | /** 64 | * Render the prompt to screen 65 | * @return {Prompt} self 66 | */ 67 | 68 | Prompt.prototype.render = function() { 69 | var message = this.message; 70 | var bottomContent = ''; 71 | if (this.firstRender) { 72 | this.firstRender = false; 73 | message += log.dim('(Use arrow keys or type to search)'); 74 | } 75 | 76 | // Render choices or answer depending on the state 77 | if (this.status === 'answered') { 78 | message += log.cyan(this.answer); 79 | } else if (this.searching) { 80 | message += this.rl.line; 81 | bottomContent += ' ' + log.dim('Searching...'); 82 | } else if (this.currentChoices.length) { 83 | var choicesStr = listRender(this.currentChoices, this.selected); 84 | message += this.rl.line; 85 | bottomContent += this.paginator.paginate(choicesStr, this.selected); 86 | } else { 87 | message += this.rl.line; 88 | bottomContent += ' ' + log.yellow('No results...'); 89 | } 90 | 91 | this.ui.render(message, bottomContent); 92 | }; 93 | 94 | /** 95 | * When user press `enter` key 96 | */ 97 | 98 | Prompt.prototype.createChoices = function(line) { 99 | if (this.currentChoices.length <= this.selected) { 100 | this.rl.write(line); 101 | this.search(line); 102 | return true; 103 | } 104 | }; 105 | 106 | Prompt.prototype.onSubmit = function(line) { 107 | if (this.createChoices(line)) return; 108 | var choice = this.currentChoices.getChoice(this.selected); 109 | this.only(); 110 | this.submitAnswer(choice.value); 111 | }; 112 | 113 | Prompt.prototype.search = function(searchTerm) { 114 | this.selected = 0; 115 | var self = this; 116 | 117 | // only render searching state after first time 118 | if (this.searchedOnce) { 119 | this.searching = true; 120 | this.currentChoices = new Choices([]); 121 | this.render(); // now render current searching state 122 | } else { 123 | this.searchedOnce = true; 124 | } 125 | 126 | this.lastSearchTerm = searchTerm; 127 | var thisPromise = this.question.source(this.answers, searchTerm); 128 | 129 | // store this promise for check in the callback 130 | this.lastPromise = thisPromise; 131 | 132 | return thisPromise.then(function inner(choices) { 133 | // if another search is triggered before the 134 | // current search finishes, don't set results 135 | if (thisPromise !== self.lastPromise) return; 136 | 137 | choices = new Choices(choices.filter(function(choice) { 138 | return choice.type !== 'separator'; 139 | })); 140 | 141 | self.currentChoices = choices; 142 | self.searching = false; 143 | self.render(); 144 | }); 145 | }; 146 | 147 | /** 148 | * Coerce selection to fit within the min-max accepted range 149 | */ 150 | 151 | Prompt.prototype.coerceToRange = function() { 152 | var selectedIndex = Math.min(this.selected, this.currentChoices.length); 153 | this.selected = Math.max(selectedIndex, 0); 154 | }; 155 | 156 | /** 157 | * When user types 158 | */ 159 | 160 | Prompt.prototype.onKeypress = function(keypress) { 161 | var len = this.currentChoices.length; 162 | 163 | // Let onSubmit handle return key press 164 | if (keypress === 'return') { 165 | return; 166 | } 167 | 168 | if (keypress === 'down') { 169 | this.selected = (this.selected < len - 1) ? this.selected + 1 : 0; 170 | this.coerceToRange(); 171 | this.render(); 172 | utils.up(this.rl, 2); 173 | return; 174 | } 175 | 176 | if (keypress === 'up') { 177 | this.selected = (this.selected > 0) ? this.selected - 1 : len - 1; 178 | this.coerceToRange(); 179 | this.render(); 180 | return; 181 | } 182 | 183 | // render input 184 | this.render(); 185 | 186 | // Only search if input has actually changed 187 | if (this.lastSearchTerm !== this.rl.line) { 188 | // trigger new search 189 | this.search(this.rl.line); 190 | } 191 | }; 192 | 193 | /** 194 | * Function for rendering list choices 195 | * @param {Number} pointer Position of the pointer 196 | * @return {String} Rendered content 197 | */ 198 | 199 | function listRender(choices, pointer) { 200 | var separatorOffset = 0; 201 | var output = ''; 202 | 203 | choices.forEach(function(choice, i) { 204 | if (choice.type === 'separator') { 205 | separatorOffset++; 206 | output += ' ' + choice + '\n'; 207 | return; 208 | } 209 | 210 | var isSelected = (i - separatorOffset === pointer); 211 | var line = (isSelected ? figures.pointer + ' ' : ' ') + choice.name; 212 | 213 | if (isSelected) { 214 | line = log.cyan(line); 215 | } 216 | output += line + ' \n'; 217 | }); 218 | 219 | return output.replace(/\n$/, ''); 220 | } 221 | 222 | /** 223 | * Module exports 224 | */ 225 | 226 | module.exports = Prompt; 227 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "prompt-autocompletion", 3 | "description": "Prompt that autocompletes as you type. Can be used standalone or with a prompt system like [enquirer]", 4 | "version": "0.1.2", 5 | "homepage": "https://github.com/enquirer/prompt-autocompletion", 6 | "author": "Jon Schlinkert (https://github.com/jonschlinkert)", 7 | "repository": "enquirer/prompt-autocompletion", 8 | "bugs": { 9 | "url": "https://github.com/enquirer/prompt-autocompletion/issues" 10 | }, 11 | "license": "MIT", 12 | "files": [ 13 | "index.js" 14 | ], 15 | "main": "index.js", 16 | "engines": { 17 | "node": ">=0.10.0" 18 | }, 19 | "scripts": { 20 | "test": "mocha" 21 | }, 22 | "dependencies": { 23 | "figures": "^1.7.0", 24 | "log-utils": "^0.2.1", 25 | "prompt-base": "^0.5.0", 26 | "prompt-choices": "^0.4.0", 27 | "readline-utils": "^0.1.2", 28 | "terminal-paginator": "^0.2.1" 29 | }, 30 | "devDependencies": { 31 | "enquirer": "^0.3.1", 32 | "gulp-format-md": "^0.1.11" 33 | }, 34 | "keywords": [ 35 | "auto", 36 | "autocomplete", 37 | "autocompletion", 38 | "complete", 39 | "generategenerator", 40 | "prompt" 41 | ], 42 | "verb": { 43 | "toc": false, 44 | "layout": "common-minimal", 45 | "tasks": [ 46 | "readme" 47 | ], 48 | "plugins": [ 49 | "gulp-format-md" 50 | ], 51 | "lint": { 52 | "reflinks": true 53 | }, 54 | "related": { 55 | "list": [], 56 | "prompts": [ 57 | "prompt-checkbox", 58 | "prompt-confirm", 59 | "prompt-editor", 60 | "prompt-expand", 61 | "prompt-list", 62 | "prompt-password", 63 | "prompt-radio", 64 | "prompt-rawlist" 65 | ] 66 | }, 67 | "reflinks": [ 68 | "enquirer", 69 | "verb", 70 | "verb-generate-readme" 71 | ] 72 | } 73 | } 74 | --------------------------------------------------------------------------------