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.3 KiB
185 lines
4.3 KiB
'use strict'; |
|
|
|
const Prompt = require('../prompt'); |
|
const placeholder = require('../placeholder'); |
|
const { isPrimitive } = require('../utils'); |
|
|
|
class StringPrompt extends Prompt { |
|
constructor(options) { |
|
super(options); |
|
this.initial = isPrimitive(this.initial) ? String(this.initial) : ''; |
|
if (this.initial) this.cursorHide(); |
|
this.state.prevCursor = 0; |
|
this.state.clipboard = []; |
|
} |
|
|
|
async keypress(input, key = {}) { |
|
let prev = this.state.prevKeypress; |
|
this.state.prevKeypress = key; |
|
if (this.options.multiline === true && key.name === 'return') { |
|
if (!prev || prev.name !== 'return') { |
|
return this.append('\n', key); |
|
} |
|
} |
|
return super.keypress(input, key); |
|
} |
|
|
|
moveCursor(n) { |
|
this.cursor += n; |
|
} |
|
|
|
reset() { |
|
this.input = this.value = ''; |
|
this.cursor = 0; |
|
return this.render(); |
|
} |
|
|
|
dispatch(ch, key) { |
|
if (!ch || key.ctrl || key.code) return this.alert(); |
|
this.append(ch); |
|
} |
|
|
|
append(ch) { |
|
let { cursor, input } = this.state; |
|
this.input = `${input}`.slice(0, cursor) + ch + `${input}`.slice(cursor); |
|
this.moveCursor(String(ch).length); |
|
this.render(); |
|
} |
|
|
|
insert(str) { |
|
this.append(str); |
|
} |
|
|
|
delete() { |
|
let { cursor, input } = this.state; |
|
if (cursor <= 0) return this.alert(); |
|
this.input = `${input}`.slice(0, cursor - 1) + `${input}`.slice(cursor); |
|
this.moveCursor(-1); |
|
this.render(); |
|
} |
|
|
|
deleteForward() { |
|
let { cursor, input } = this.state; |
|
if (input[cursor] === void 0) return this.alert(); |
|
this.input = `${input}`.slice(0, cursor) + `${input}`.slice(cursor + 1); |
|
this.render(); |
|
} |
|
|
|
cutForward() { |
|
let pos = this.cursor; |
|
if (this.input.length <= pos) return this.alert(); |
|
this.state.clipboard.push(this.input.slice(pos)); |
|
this.input = this.input.slice(0, pos); |
|
this.render(); |
|
} |
|
|
|
cutLeft() { |
|
let pos = this.cursor; |
|
if (pos === 0) return this.alert(); |
|
let before = this.input.slice(0, pos); |
|
let after = this.input.slice(pos); |
|
let words = before.split(' '); |
|
this.state.clipboard.push(words.pop()); |
|
this.input = words.join(' '); |
|
this.cursor = this.input.length; |
|
this.input += after; |
|
this.render(); |
|
} |
|
|
|
paste() { |
|
if (!this.state.clipboard.length) return this.alert(); |
|
this.insert(this.state.clipboard.pop()); |
|
this.render(); |
|
} |
|
|
|
toggleCursor() { |
|
if (this.state.prevCursor) { |
|
this.cursor = this.state.prevCursor; |
|
this.state.prevCursor = 0; |
|
} else { |
|
this.state.prevCursor = this.cursor; |
|
this.cursor = 0; |
|
} |
|
this.render(); |
|
} |
|
|
|
first() { |
|
this.cursor = 0; |
|
this.render(); |
|
} |
|
|
|
last() { |
|
this.cursor = this.input.length - 1; |
|
this.render(); |
|
} |
|
|
|
next() { |
|
let init = this.initial != null ? String(this.initial) : ''; |
|
if (!init || !init.startsWith(this.input)) return this.alert(); |
|
this.input = this.initial; |
|
this.cursor = this.initial.length; |
|
this.render(); |
|
} |
|
|
|
prev() { |
|
if (!this.input) return this.alert(); |
|
this.reset(); |
|
} |
|
|
|
backward() { |
|
return this.left(); |
|
} |
|
|
|
forward() { |
|
return this.right(); |
|
} |
|
|
|
right() { |
|
if (this.cursor >= this.input.length) return this.alert(); |
|
this.moveCursor(1); |
|
return this.render(); |
|
} |
|
|
|
left() { |
|
if (this.cursor <= 0) return this.alert(); |
|
this.moveCursor(-1); |
|
return this.render(); |
|
} |
|
|
|
isValue(value) { |
|
return !!value; |
|
} |
|
|
|
async format(input = this.value) { |
|
let initial = await this.resolve(this.initial, this.state); |
|
if (!this.state.submitted) { |
|
return placeholder(this, { input, initial, pos: this.cursor }); |
|
} |
|
return this.styles.submitted(input || initial); |
|
} |
|
|
|
async render() { |
|
let size = this.state.size; |
|
|
|
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 output = await this.format(); |
|
let help = (await this.error()) || (await this.hint()); |
|
let footer = await this.footer(); |
|
|
|
if (help && !output.includes(help)) output += ' ' + help; |
|
prompt += ' ' + output; |
|
|
|
this.clear(size); |
|
this.write([header, prompt, footer].filter(Boolean).join('\n')); |
|
this.restore(); |
|
} |
|
} |
|
|
|
module.exports = StringPrompt;
|
|
|