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.
185 lines
4.4 KiB
185 lines
4.4 KiB
'use strict'; |
|
|
|
const colors = require('ansi-colors'); |
|
const interpolate = require('../interpolate'); |
|
const Prompt = require('../prompt'); |
|
|
|
class SnippetPrompt extends Prompt { |
|
constructor(options) { |
|
super(options); |
|
this.cursorHide(); |
|
this.reset(true); |
|
} |
|
|
|
async initialize() { |
|
this.interpolate = await interpolate(this); |
|
await super.initialize(); |
|
} |
|
|
|
async reset(first) { |
|
this.state.keys = []; |
|
this.state.invalid = new Map(); |
|
this.state.missing = new Set(); |
|
this.state.completed = 0; |
|
this.state.values = {}; |
|
|
|
if (first !== true) { |
|
await this.initialize(); |
|
await this.render(); |
|
} |
|
} |
|
|
|
moveCursor(n) { |
|
let item = this.getItem(); |
|
this.cursor += n; |
|
item.cursor += n; |
|
} |
|
|
|
dispatch(ch, key) { |
|
if (!key.code && !key.ctrl && ch != null && this.getItem()) { |
|
this.append(ch, key); |
|
return; |
|
} |
|
this.alert(); |
|
} |
|
|
|
append(ch, key) { |
|
let item = this.getItem(); |
|
let prefix = item.input.slice(0, this.cursor); |
|
let suffix = item.input.slice(this.cursor); |
|
this.input = item.input = `${prefix}${ch}${suffix}`; |
|
this.moveCursor(1); |
|
this.render(); |
|
} |
|
|
|
delete() { |
|
let item = this.getItem(); |
|
if (this.cursor <= 0 || !item.input) return this.alert(); |
|
let suffix = item.input.slice(this.cursor); |
|
let prefix = item.input.slice(0, this.cursor - 1); |
|
this.input = item.input = `${prefix}${suffix}`; |
|
this.moveCursor(-1); |
|
this.render(); |
|
} |
|
|
|
increment(i) { |
|
return i >= this.state.keys.length - 1 ? 0 : i + 1; |
|
} |
|
|
|
decrement(i) { |
|
return i <= 0 ? this.state.keys.length - 1 : i - 1; |
|
} |
|
|
|
first() { |
|
this.state.index = 0; |
|
this.render(); |
|
} |
|
|
|
last() { |
|
this.state.index = this.state.keys.length - 1; |
|
this.render(); |
|
} |
|
|
|
right() { |
|
if (this.cursor >= this.input.length) return this.alert(); |
|
this.moveCursor(1); |
|
this.render(); |
|
} |
|
|
|
left() { |
|
if (this.cursor <= 0) return this.alert(); |
|
this.moveCursor(-1); |
|
this.render(); |
|
} |
|
|
|
prev() { |
|
this.state.index = this.decrement(this.state.index); |
|
this.getItem(); |
|
this.render(); |
|
} |
|
|
|
next() { |
|
this.state.index = this.increment(this.state.index); |
|
this.getItem(); |
|
this.render(); |
|
} |
|
|
|
up() { |
|
this.prev(); |
|
} |
|
|
|
down() { |
|
this.next(); |
|
} |
|
|
|
format(value) { |
|
let color = this.state.completed < 100 ? this.styles.warning : this.styles.success; |
|
if (this.state.submitted === true && this.state.completed !== 100) { |
|
color = this.styles.danger; |
|
} |
|
return color(`${this.state.completed}% completed`); |
|
} |
|
|
|
async render() { |
|
let { index, keys = [], submitted, size } = this.state; |
|
|
|
let newline = [this.options.newline, '\n'].find(v => v != null); |
|
let prefix = await this.prefix(); |
|
let separator = await this.separator(); |
|
let message = await this.message(); |
|
|
|
let prompt = [prefix, message, separator].filter(Boolean).join(' '); |
|
this.state.prompt = prompt; |
|
|
|
let header = await this.header(); |
|
let error = (await this.error()) || ''; |
|
let hint = (await this.hint()) || ''; |
|
let body = submitted ? '' : await this.interpolate(this.state); |
|
|
|
let key = this.state.key = keys[index] || ''; |
|
let input = await this.format(key); |
|
let footer = await this.footer(); |
|
if (input) prompt += ' ' + input; |
|
if (hint && !input && this.state.completed === 0) prompt += ' ' + hint; |
|
|
|
this.clear(size); |
|
let lines = [header, prompt, body, footer, error.trim()]; |
|
this.write(lines.filter(Boolean).join(newline)); |
|
this.restore(); |
|
} |
|
|
|
getItem(name) { |
|
let { items, keys, index } = this.state; |
|
let item = items.find(ch => ch.name === keys[index]); |
|
if (item && item.input != null) { |
|
this.input = item.input; |
|
this.cursor = item.cursor; |
|
} |
|
return item; |
|
} |
|
|
|
async submit() { |
|
if (typeof this.interpolate !== 'function') await this.initialize(); |
|
await this.interpolate(this.state, true); |
|
|
|
let { invalid, missing, output, values } = this.state; |
|
if (invalid.size) { |
|
let err = ''; |
|
for (let [key, value] of invalid) err += `Invalid ${key}: ${value}\n`; |
|
this.state.error = err; |
|
return super.submit(); |
|
} |
|
|
|
if (missing.size) { |
|
this.state.error = 'Required: ' + [...missing.keys()].join(', '); |
|
return super.submit(); |
|
} |
|
|
|
let lines = colors.unstyle(output).split('\n'); |
|
let result = lines.map(v => v.slice(1)).join('\n'); |
|
this.value = { values, result }; |
|
return super.submit(); |
|
} |
|
} |
|
|
|
module.exports = SnippetPrompt;
|
|
|