You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
190 lines
5.0 KiB
190 lines
5.0 KiB
'use strict'; |
|
|
|
const color = require('kleur'); |
|
|
|
const Prompt = require('./prompt'); |
|
|
|
const _require = require('../util'), |
|
style = _require.style, |
|
clear = _require.clear, |
|
figures = _require.figures, |
|
wrap = _require.wrap, |
|
entriesToDisplay = _require.entriesToDisplay; |
|
|
|
const _require2 = require('sisteransi'), |
|
cursor = _require2.cursor; |
|
/** |
|
* SelectPrompt Base Element |
|
* @param {Object} opts Options |
|
* @param {String} opts.message Message |
|
* @param {Array} opts.choices Array of choice objects |
|
* @param {String} [opts.hint] Hint to display |
|
* @param {Number} [opts.initial] Index of default value |
|
* @param {Stream} [opts.stdin] The Readable stream to listen to |
|
* @param {Stream} [opts.stdout] The Writable stream to write readline data to |
|
* @param {Number} [opts.optionsPerPage=10] Max options to display at once |
|
*/ |
|
|
|
|
|
class SelectPrompt extends Prompt { |
|
constructor(opts = {}) { |
|
super(opts); |
|
this.msg = opts.message; |
|
this.hint = opts.hint || '- Use arrow-keys. Return to submit.'; |
|
this.warn = opts.warn || '- This option is disabled'; |
|
this.cursor = opts.initial || 0; |
|
this.choices = opts.choices.map((ch, idx) => { |
|
if (typeof ch === 'string') ch = { |
|
title: ch, |
|
value: idx |
|
}; |
|
return { |
|
title: ch && (ch.title || ch.value || ch), |
|
value: ch && (ch.value === undefined ? idx : ch.value), |
|
description: ch && ch.description, |
|
selected: ch && ch.selected, |
|
disabled: ch && ch.disabled |
|
}; |
|
}); |
|
this.optionsPerPage = opts.optionsPerPage || 10; |
|
this.value = (this.choices[this.cursor] || {}).value; |
|
this.clear = clear('', this.out.columns); |
|
this.render(); |
|
} |
|
|
|
moveCursor(n) { |
|
this.cursor = n; |
|
this.value = this.choices[n].value; |
|
this.fire(); |
|
} |
|
|
|
reset() { |
|
this.moveCursor(0); |
|
this.fire(); |
|
this.render(); |
|
} |
|
|
|
exit() { |
|
this.abort(); |
|
} |
|
|
|
abort() { |
|
this.done = this.aborted = true; |
|
this.fire(); |
|
this.render(); |
|
this.out.write('\n'); |
|
this.close(); |
|
} |
|
|
|
submit() { |
|
if (!this.selection.disabled) { |
|
this.done = true; |
|
this.aborted = false; |
|
this.fire(); |
|
this.render(); |
|
this.out.write('\n'); |
|
this.close(); |
|
} else this.bell(); |
|
} |
|
|
|
first() { |
|
this.moveCursor(0); |
|
this.render(); |
|
} |
|
|
|
last() { |
|
this.moveCursor(this.choices.length - 1); |
|
this.render(); |
|
} |
|
|
|
up() { |
|
if (this.cursor === 0) { |
|
this.moveCursor(this.choices.length - 1); |
|
} else { |
|
this.moveCursor(this.cursor - 1); |
|
} |
|
|
|
this.render(); |
|
} |
|
|
|
down() { |
|
if (this.cursor === this.choices.length - 1) { |
|
this.moveCursor(0); |
|
} else { |
|
this.moveCursor(this.cursor + 1); |
|
} |
|
|
|
this.render(); |
|
} |
|
|
|
next() { |
|
this.moveCursor((this.cursor + 1) % this.choices.length); |
|
this.render(); |
|
} |
|
|
|
_(c, key) { |
|
if (c === ' ') return this.submit(); |
|
} |
|
|
|
get selection() { |
|
return this.choices[this.cursor]; |
|
} |
|
|
|
render() { |
|
if (this.closed) return; |
|
if (this.firstRender) this.out.write(cursor.hide);else this.out.write(clear(this.outputText, this.out.columns)); |
|
super.render(); |
|
|
|
let _entriesToDisplay = entriesToDisplay(this.cursor, this.choices.length, this.optionsPerPage), |
|
startIndex = _entriesToDisplay.startIndex, |
|
endIndex = _entriesToDisplay.endIndex; // Print prompt |
|
|
|
|
|
this.outputText = [style.symbol(this.done, this.aborted), color.bold(this.msg), style.delimiter(false), this.done ? this.selection.title : this.selection.disabled ? color.yellow(this.warn) : color.gray(this.hint)].join(' '); // Print choices |
|
|
|
if (!this.done) { |
|
this.outputText += '\n'; |
|
|
|
for (let i = startIndex; i < endIndex; i++) { |
|
let title, |
|
prefix, |
|
desc = '', |
|
v = this.choices[i]; // Determine whether to display "more choices" indicators |
|
|
|
if (i === startIndex && startIndex > 0) { |
|
prefix = figures.arrowUp; |
|
} else if (i === endIndex - 1 && endIndex < this.choices.length) { |
|
prefix = figures.arrowDown; |
|
} else { |
|
prefix = ' '; |
|
} |
|
|
|
if (v.disabled) { |
|
title = this.cursor === i ? color.gray().underline(v.title) : color.strikethrough().gray(v.title); |
|
prefix = (this.cursor === i ? color.bold().gray(figures.pointer) + ' ' : ' ') + prefix; |
|
} else { |
|
title = this.cursor === i ? color.cyan().underline(v.title) : v.title; |
|
prefix = (this.cursor === i ? color.cyan(figures.pointer) + ' ' : ' ') + prefix; |
|
|
|
if (v.description && this.cursor === i) { |
|
desc = ` - ${v.description}`; |
|
|
|
if (prefix.length + title.length + desc.length >= this.out.columns || v.description.split(/\r?\n/).length > 1) { |
|
desc = '\n' + wrap(v.description, { |
|
margin: 3, |
|
width: this.out.columns |
|
}); |
|
} |
|
} |
|
} |
|
|
|
this.outputText += `${prefix} ${title}${color.gray(desc)}\n`; |
|
} |
|
} |
|
|
|
this.out.write(this.outputText); |
|
} |
|
|
|
} |
|
|
|
module.exports = SelectPrompt; |