| 13 | } |
| 14 | |
| 15 | export default class MultiLinePrompt extends Prompt<string> { |
| 16 | #lastKeyWasReturn = false; |
| 17 | #showSubmit: boolean; |
| 18 | public focused: 'editor' | 'submit' = 'editor'; |
| 19 | |
| 20 | get userInputWithCursor() { |
| 21 | if (this.state === 'submit') { |
| 22 | return this.userInput; |
| 23 | } |
| 24 | const userInput = this.userInput; |
| 25 | if (this.cursor >= userInput.length) { |
| 26 | return `${userInput}█`; |
| 27 | } |
| 28 | const s1 = userInput.slice(0, this.cursor); |
| 29 | const s2 = userInput[this.cursor]; |
| 30 | const s3 = userInput.slice(this.cursor + 1); |
| 31 | if (s2 === '\n') return `${s1}█\n${s3}`; |
| 32 | return `${s1}${styleText('inverse', s2)}${s3}`; |
| 33 | } |
| 34 | get cursor() { |
| 35 | return this._cursor; |
| 36 | } |
| 37 | #insertAtCursor(char: string) { |
| 38 | if (this.userInput.length === 0) { |
| 39 | this._setUserInput(char); |
| 40 | return; |
| 41 | } |
| 42 | this._setUserInput( |
| 43 | this.userInput.slice(0, this.cursor) + char + this.userInput.slice(this.cursor) |
| 44 | ); |
| 45 | } |
| 46 | #handleCursor(key?: CursorAction) { |
| 47 | const text = this.value ?? ''; |
| 48 | switch (key) { |
| 49 | case 'up': |
| 50 | this._cursor = findTextCursor(this._cursor, 0, -1, text); |
| 51 | return; |
| 52 | case 'down': |
| 53 | this._cursor = findTextCursor(this._cursor, 0, 1, text); |
| 54 | return; |
| 55 | case 'left': |
| 56 | this._cursor = findTextCursor(this._cursor, -1, 0, text); |
| 57 | return; |
| 58 | case 'right': |
| 59 | this._cursor = findTextCursor(this._cursor, 1, 0, text); |
| 60 | return; |
| 61 | } |
| 62 | } |
| 63 | |
| 64 | protected override _shouldSubmit(_char: string | undefined, _key: Key): boolean { |
| 65 | if (this.#showSubmit) { |
| 66 | if (this.focused === 'submit') { |
| 67 | return true; |
| 68 | } |
| 69 | this.#insertAtCursor('\n'); |
| 70 | this._cursor++; |
| 71 | return false; |
| 72 | } |
nothing calls this directly
no outgoing calls
no test coverage detected