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 this.paginator = new Paginator();
56 * Start the Inquiry session
57 * @param {Function} cb Callback when prompt is done
64 // Once user confirm (enter key)
65 var events = observe(this.rl);
66 var submit = events.line.pipe(map(this.getCurrentValue.bind(this)));
68 var validation = this.handleSubmitEvents(submit);
69 validation.success.forEach(this.onEnd.bind(this));
70 validation.error.forEach(this.onError.bind(this));
72 events.normalizedUpKey.pipe(takeUntil(events.line)).forEach(this.onUpKey.bind(this));
73 events.normalizedDownKey
74 .pipe(takeUntil(events.line))
75 .forEach(this.onDownKey.bind(this));
77 .pipe(takeUntil(validation.success))
78 .forEach(this.onKeypress.bind(this));
86 * Render the prompt to screen
87 * @return {RawListPrompt} self
92 var message = this.getQuestion();
93 var bottomContent = '';
95 if (this.status === 'answered') {
96 message += chalk.cyan(this.answer);
98 var choicesStr = renderChoices(this.opt.choices, this.selected);
100 '\n' + this.paginator.paginate(choicesStr, this.selected, this.opt.pageSize);
101 message += '\n Answer: ';
103 message += this.rl.line;
106 bottomContent = '\n' + chalk.red('>> ') + error;
109 this.screen.render(message, bottomContent);
113 * When user press `enter` key
116 getCurrentValue(index) {
118 index = this.rawDefault;
119 } else if (index === '') {
120 index = this.selected;
125 var choice = this.opt.choices.getChoice(index);
126 return choice ? choice.value : null;
130 this.status = 'answered';
131 this.answer = state.value;
137 this.done(state.value);
141 this.render('Please enter a valid index');
145 * When user press a key
149 var index = this.rl.line.length ? Number(this.rl.line) - 1 : 0;
151 if (this.opt.choices.getChoice(index)) {
152 this.selected = index;
154 this.selected = undefined;
160 * When user press up key
164 this.onArrowKey('up');
168 * When user press down key
172 this.onArrowKey('down');
176 * When user press up or down key
177 * @param {String} type Arrow type: up or down
181 this.selected = incrementListIndex(this.selected, type, this.opt);
182 this.rl.line = String(this.selected + 1);
187 * Function for rendering list choices
188 * @param {Number} pointer Position of the pointer
189 * @return {String} Rendered content
192 function renderChoices(choices, pointer) {
194 var separatorOffset = 0;
196 choices.forEach(function (choice, i) {
199 if (choice.type === 'separator') {
201 output += ' ' + choice;
205 var index = i - separatorOffset;
206 var display = index + 1 + ') ' + choice.name;
207 if (index === pointer) {
208 display = chalk.cyan(display);
217 module.exports = RawListPrompt;