+'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;