3 * `rawlist` type prompt
7 extend: require('lodash/extend'),
8 isNumber: require('lodash/isNumber'),
9 findIndex: require('lodash/findIndex'),
11 var chalk = require('chalk');
12 var { map, takeUntil } = require('rxjs/operators');
13 var Base = require('./base');
14 var Separator = require('../objects/separator');
15 var observe = require('../utils/events');
16 var Paginator = require('../utils/paginator');
17 var incrementListIndex = require('../utils/incrementListIndex');
19 class RawListPrompt extends Base {
20 constructor(questions, rl, answers) {
21 super(questions, rl, answers);
23 if (!this.opt.choices) {
24 this.throwParamError('choices');
27 this.opt.validChoices = this.opt.choices.filter(Separator.exclude);
33 validate: function (val) {
38 var def = this.opt.default;
39 if (_.isNumber(def) && def >= 0 && def < this.opt.choices.realLength) {
41 this.rawDefault = def;
42 } else if (!_.isNumber(def) && def != null) {
43 let index = _.findIndex(this.opt.choices.realChoices, ({ value }) => value === def);
44 let safeIndex = Math.max(index, 0);
45 this.selected = safeIndex;
46 this.rawDefault = safeIndex;
49 // Make sure no default is set (so it won't be printed)
50 this.opt.default = null;
52 const shouldLoop = this.opt.loop === undefined ? true : this.opt.loop;
53 this.paginator = new Paginator(undefined, { isInfinite: shouldLoop });
57 * Start the Inquiry session
58 * @param {Function} cb Callback when prompt is done
65 // Once user confirm (enter key)
66 var events = observe(this.rl);
67 var submit = events.line.pipe(map(this.getCurrentValue.bind(this)));
69 var validation = this.handleSubmitEvents(submit);
70 validation.success.forEach(this.onEnd.bind(this));
71 validation.error.forEach(this.onError.bind(this));
73 events.normalizedUpKey.pipe(takeUntil(events.line)).forEach(this.onUpKey.bind(this));
74 events.normalizedDownKey
75 .pipe(takeUntil(events.line))
76 .forEach(this.onDownKey.bind(this));
78 .pipe(takeUntil(validation.success))
79 .forEach(this.onKeypress.bind(this));
87 * Render the prompt to screen
88 * @return {RawListPrompt} self
93 var message = this.getQuestion();
94 var bottomContent = '';
96 if (this.status === 'answered') {
97 message += chalk.cyan(this.answer);
99 var choicesStr = renderChoices(this.opt.choices, this.selected);
101 '\n' + this.paginator.paginate(choicesStr, this.selected, this.opt.pageSize);
102 message += '\n Answer: ';
104 message += this.rl.line;
107 bottomContent = '\n' + chalk.red('>> ') + error;
110 this.screen.render(message, bottomContent);
114 * When user press `enter` key
117 getCurrentValue(index) {
119 index = this.rawDefault;
120 } else if (index === '') {
121 index = this.selected;
126 var choice = this.opt.choices.getChoice(index);
127 return choice ? choice.value : null;
131 this.status = 'answered';
132 this.answer = state.value;
138 this.done(state.value);
142 this.render('Please enter a valid index');
146 * When user press a key
150 var index = this.rl.line.length ? Number(this.rl.line) - 1 : 0;
152 if (this.opt.choices.getChoice(index)) {
153 this.selected = index;
155 this.selected = undefined;
161 * When user press up key
165 this.onArrowKey('up');
169 * When user press down key
173 this.onArrowKey('down');
177 * When user press up or down key
178 * @param {String} type Arrow type: up or down
182 this.selected = incrementListIndex(this.selected, type, this.opt);
183 this.rl.line = String(this.selected + 1);
188 * Function for rendering list choices
189 * @param {Number} pointer Position of the pointer
190 * @return {String} Rendered content
193 function renderChoices(choices, pointer) {
195 var separatorOffset = 0;
197 choices.forEach(function (choice, i) {
200 if (choice.type === 'separator') {
202 output += ' ' + choice;
206 var index = i - separatorOffset;
207 var display = index + 1 + ') ' + choice.name;
208 if (index === pointer) {
209 display = chalk.cyan(display);
218 module.exports = RawListPrompt;