@ponythewhite/base-context-tui 1.0.1 → 1.0.4

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1,5 +1,5 @@
1
1
  {
2
- "sourceCommit": "9247ae92d4cc1a43fcb003316e6762be579a6a05",
2
+ "sourceCommit": "84d72c5846ae0d65614b6b2bf966c48dd18ad7aa",
3
3
  "sourceDirty": false,
4
4
  "buildHost": {
5
5
  "platform": "linux",
@@ -5,6 +5,7 @@ import { type Component, type Focusable } from "../tui.js";
5
5
  export declare class Input implements Component, Focusable {
6
6
  private value;
7
7
  private cursor;
8
+ private masked;
8
9
  onSubmit?: (value: string) => void;
9
10
  onEscape?: () => void;
10
11
  focused: boolean;
@@ -13,6 +14,7 @@ export declare class Input implements Component, Focusable {
13
14
  private killRing;
14
15
  private lastAction;
15
16
  private undoStack;
17
+ setMasked(masked: boolean): void;
16
18
  getValue(): string;
17
19
  getCursor(): number;
18
20
  setValue(value: string): void;
@@ -32,6 +34,7 @@ export declare class Input implements Component, Focusable {
32
34
  private moveWordForwards;
33
35
  private handlePaste;
34
36
  invalidate(): void;
37
+ private displayState;
35
38
  render(width: number): string[];
36
39
  }
37
40
  //# sourceMappingURL=input.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"input.d.ts","sourceRoot":"","sources":["../../src/components/input.ts"],"names":[],"mappings":"AAGA,OAAO,EAAE,KAAK,SAAS,EAAiB,KAAK,SAAS,EAAE,MAAM,WAAW,CAAC;AAW1E;;GAEG;AACH,qBAAa,KAAM,YAAW,SAAS,EAAE,SAAS;IACjD,OAAO,CAAC,KAAK,CAAc;IAC3B,OAAO,CAAC,MAAM,CAAa;IACpB,QAAQ,CAAC,EAAE,CAAC,KAAK,EAAE,MAAM,KAAK,IAAI,CAAC;IACnC,QAAQ,CAAC,EAAE,MAAM,IAAI,CAAC;IAE7B,OAAO,EAAE,OAAO,CAAS;IAEzB,OAAO,CAAC,WAAW,CAAc;IACjC,OAAO,CAAC,SAAS,CAAkB;IAEnC,OAAO,CAAC,QAAQ,CAAkB;IAClC,OAAO,CAAC,UAAU,CAA8C;IAEhE,OAAO,CAAC,SAAS,CAA+B;IAEhD,QAAQ,IAAI,MAAM,CAEjB;IAED,SAAS,IAAI,MAAM,CAElB;IAED,QAAQ,CAAC,KAAK,EAAE,MAAM,GAAG,IAAI,CAG5B;IAED,WAAW,CAAC,IAAI,EAAE,MAAM,GAAG,IAAI,CAkJ9B;IAED,OAAO,CAAC,eAAe;IAUvB,OAAO,CAAC,eAAe;IAavB,OAAO,CAAC,mBAAmB;IAY3B,OAAO,CAAC,iBAAiB;IAUzB,OAAO,CAAC,eAAe;IASvB,OAAO,CAAC,mBAAmB;IAqB3B,OAAO,CAAC,iBAAiB;IAoBzB,OAAO,CAAC,IAAI;IAWZ,OAAO,CAAC,OAAO;IAgBf,OAAO,CAAC,QAAQ;IAIhB,OAAO,CAAC,IAAI;IAQZ,OAAO,CAAC,iBAAiB;IA+BzB,OAAO,CAAC,gBAAgB;IAgCxB,OAAO,CAAC,WAAW;IAUnB,UAAU,IAAI,IAAI,CAAG;IAErB,MAAM,CAAC,KAAK,EAAE,MAAM,GAAG,MAAM,EAAE,CAyD9B;CACD","sourcesContent":["import { getKeybindings } from \"../keybindings.js\";\nimport { decodeKittyPrintable } from \"../keys.js\";\nimport { KillRing } from \"../kill-ring.js\";\nimport { type Component, CURSOR_MARKER, type Focusable } from \"../tui.js\";\nimport { UndoStack } from \"../undo-stack.js\";\nimport { getSegmenter, isPunctuationChar, isWhitespaceChar, sliceByColumn, visibleWidth } from \"../utils.js\";\n\nconst segmenter = getSegmenter();\n\ninterface InputState {\n\tvalue: string;\n\tcursor: number;\n}\n\n/**\n * Input component - single-line text input with horizontal scrolling\n */\nexport class Input implements Component, Focusable {\n\tprivate value: string = \"\";\n\tprivate cursor: number = 0; // Cursor position in the value\n\tpublic onSubmit?: (value: string) => void;\n\tpublic onEscape?: () => void;\n\n\tfocused: boolean = false;\n\n\tprivate pasteBuffer: string = \"\";\n\tprivate isInPaste: boolean = false;\n\n\tprivate killRing = new KillRing();\n\tprivate lastAction: \"kill\" | \"yank\" | \"type-word\" | null = null;\n\n\tprivate undoStack = new UndoStack<InputState>();\n\n\tgetValue(): string {\n\t\treturn this.value;\n\t}\n\n\tgetCursor(): number {\n\t\treturn this.cursor;\n\t}\n\n\tsetValue(value: string): void {\n\t\tthis.value = value;\n\t\tthis.cursor = Math.min(this.cursor, value.length);\n\t}\n\n\thandleInput(data: string): void {\n\t\tif (data.includes(\"\\x1b[200~\")) {\n\t\t\tthis.isInPaste = true;\n\t\t\tthis.pasteBuffer = \"\";\n\t\t\tdata = data.replace(\"\\x1b[200~\", \"\");\n\t\t}\n\n\t\tif (this.isInPaste) {\n\t\t\tthis.pasteBuffer += data;\n\n\t\t\tconst endIndex = this.pasteBuffer.indexOf(\"\\x1b[201~\");\n\t\t\tif (endIndex !== -1) {\n\t\t\t\tconst pasteContent = this.pasteBuffer.substring(0, endIndex);\n\n\t\t\t\tthis.handlePaste(pasteContent);\n\n\t\t\t\tthis.isInPaste = false;\n\n\t\t\t\tconst remaining = this.pasteBuffer.substring(endIndex + 6); // 6 = length of \\x1b[201~\n\t\t\t\tthis.pasteBuffer = \"\";\n\t\t\t\tif (remaining) {\n\t\t\t\t\tthis.handleInput(remaining);\n\t\t\t\t}\n\t\t\t}\n\t\t\treturn;\n\t\t}\n\n\t\tconst kb = getKeybindings();\n\n\t\tif (kb.matches(data, \"tui.select.cancel\")) {\n\t\t\tif (this.onEscape) this.onEscape();\n\t\t\treturn;\n\t\t}\n\n\t\tif (kb.matches(data, \"tui.editor.undo\")) {\n\t\t\tthis.undo();\n\t\t\treturn;\n\t\t}\n\n\t\tif (kb.matches(data, \"tui.input.submit\") || data === \"\\n\") {\n\t\t\tif (this.onSubmit) this.onSubmit(this.value);\n\t\t\treturn;\n\t\t}\n\n\t\tif (kb.matches(data, \"tui.editor.deleteCharBackward\")) {\n\t\t\tthis.handleBackspace();\n\t\t\treturn;\n\t\t}\n\n\t\tif (kb.matches(data, \"tui.editor.deleteCharForward\")) {\n\t\t\tthis.handleForwardDelete();\n\t\t\treturn;\n\t\t}\n\n\t\tif (kb.matches(data, \"tui.editor.deleteWordBackward\")) {\n\t\t\tthis.deleteWordBackwards();\n\t\t\treturn;\n\t\t}\n\n\t\tif (kb.matches(data, \"tui.editor.deleteWordForward\")) {\n\t\t\tthis.deleteWordForward();\n\t\t\treturn;\n\t\t}\n\n\t\tif (kb.matches(data, \"tui.editor.deleteToLineStart\")) {\n\t\t\tthis.deleteToLineStart();\n\t\t\treturn;\n\t\t}\n\n\t\tif (kb.matches(data, \"tui.editor.deleteToLineEnd\")) {\n\t\t\tthis.deleteToLineEnd();\n\t\t\treturn;\n\t\t}\n\n\t\tif (kb.matches(data, \"tui.editor.yank\")) {\n\t\t\tthis.yank();\n\t\t\treturn;\n\t\t}\n\t\tif (kb.matches(data, \"tui.editor.yankPop\")) {\n\t\t\tthis.yankPop();\n\t\t\treturn;\n\t\t}\n\n\t\tif (kb.matches(data, \"tui.editor.cursorLeft\")) {\n\t\t\tthis.lastAction = null;\n\t\t\tif (this.cursor > 0) {\n\t\t\t\tconst beforeCursor = this.value.slice(0, this.cursor);\n\t\t\t\tconst graphemes = [...segmenter.segment(beforeCursor)];\n\t\t\t\tconst lastGrapheme = graphemes[graphemes.length - 1];\n\t\t\t\tthis.cursor -= lastGrapheme ? lastGrapheme.segment.length : 1;\n\t\t\t}\n\t\t\treturn;\n\t\t}\n\n\t\tif (kb.matches(data, \"tui.editor.cursorRight\")) {\n\t\t\tthis.lastAction = null;\n\t\t\tif (this.cursor < this.value.length) {\n\t\t\t\tconst afterCursor = this.value.slice(this.cursor);\n\t\t\t\tconst graphemes = [...segmenter.segment(afterCursor)];\n\t\t\t\tconst firstGrapheme = graphemes[0];\n\t\t\t\tthis.cursor += firstGrapheme ? firstGrapheme.segment.length : 1;\n\t\t\t}\n\t\t\treturn;\n\t\t}\n\n\t\tif (kb.matches(data, \"tui.editor.cursorLineStart\")) {\n\t\t\tthis.lastAction = null;\n\t\t\tthis.cursor = 0;\n\t\t\treturn;\n\t\t}\n\n\t\tif (kb.matches(data, \"tui.editor.cursorLineEnd\")) {\n\t\t\tthis.lastAction = null;\n\t\t\tthis.cursor = this.value.length;\n\t\t\treturn;\n\t\t}\n\n\t\tif (kb.matches(data, \"tui.editor.cursorWordLeft\")) {\n\t\t\tthis.moveWordBackwards();\n\t\t\treturn;\n\t\t}\n\n\t\tif (kb.matches(data, \"tui.editor.cursorWordRight\")) {\n\t\t\tthis.moveWordForwards();\n\t\t\treturn;\n\t\t}\n\n\t\t// Kitty CSI-u printable character (e.g. \\x1b[97u for 'a').\n\t\t// Terminals with Kitty protocol flag 1 (disambiguate) send CSI-u for all keys,\n\t\t// including plain printable characters. Decode before the control-char check\n\t\t// since CSI-u sequences contain \\x1b which would be rejected.\n\t\tconst kittyPrintable = decodeKittyPrintable(data);\n\t\tif (kittyPrintable !== undefined) {\n\t\t\tthis.insertCharacter(kittyPrintable);\n\t\t\treturn;\n\t\t}\n\n\t\t// Regular character input - accept printable characters including Unicode,\n\t\t// but reject control characters (C0: 0x00-0x1F, DEL: 0x7F, C1: 0x80-0x9F)\n\t\tconst hasControlChars = [...data].some((ch) => {\n\t\t\tconst code = ch.charCodeAt(0);\n\t\t\treturn code < 32 || code === 0x7f || (code >= 0x80 && code <= 0x9f);\n\t\t});\n\t\tif (!hasControlChars) {\n\t\t\tthis.insertCharacter(data);\n\t\t}\n\t}\n\n\tprivate insertCharacter(char: string): void {\n\t\tif (isWhitespaceChar(char) || this.lastAction !== \"type-word\") {\n\t\t\tthis.pushUndo();\n\t\t}\n\t\tthis.lastAction = \"type-word\";\n\n\t\tthis.value = this.value.slice(0, this.cursor) + char + this.value.slice(this.cursor);\n\t\tthis.cursor += char.length;\n\t}\n\n\tprivate handleBackspace(): void {\n\t\tthis.lastAction = null;\n\t\tif (this.cursor > 0) {\n\t\t\tthis.pushUndo();\n\t\t\tconst beforeCursor = this.value.slice(0, this.cursor);\n\t\t\tconst graphemes = [...segmenter.segment(beforeCursor)];\n\t\t\tconst lastGrapheme = graphemes[graphemes.length - 1];\n\t\t\tconst graphemeLength = lastGrapheme ? lastGrapheme.segment.length : 1;\n\t\t\tthis.value = this.value.slice(0, this.cursor - graphemeLength) + this.value.slice(this.cursor);\n\t\t\tthis.cursor -= graphemeLength;\n\t\t}\n\t}\n\n\tprivate handleForwardDelete(): void {\n\t\tthis.lastAction = null;\n\t\tif (this.cursor < this.value.length) {\n\t\t\tthis.pushUndo();\n\t\t\tconst afterCursor = this.value.slice(this.cursor);\n\t\t\tconst graphemes = [...segmenter.segment(afterCursor)];\n\t\t\tconst firstGrapheme = graphemes[0];\n\t\t\tconst graphemeLength = firstGrapheme ? firstGrapheme.segment.length : 1;\n\t\t\tthis.value = this.value.slice(0, this.cursor) + this.value.slice(this.cursor + graphemeLength);\n\t\t}\n\t}\n\n\tprivate deleteToLineStart(): void {\n\t\tif (this.cursor === 0) return;\n\t\tthis.pushUndo();\n\t\tconst deletedText = this.value.slice(0, this.cursor);\n\t\tthis.killRing.push(deletedText, { prepend: true, accumulate: this.lastAction === \"kill\" });\n\t\tthis.lastAction = \"kill\";\n\t\tthis.value = this.value.slice(this.cursor);\n\t\tthis.cursor = 0;\n\t}\n\n\tprivate deleteToLineEnd(): void {\n\t\tif (this.cursor >= this.value.length) return;\n\t\tthis.pushUndo();\n\t\tconst deletedText = this.value.slice(this.cursor);\n\t\tthis.killRing.push(deletedText, { prepend: false, accumulate: this.lastAction === \"kill\" });\n\t\tthis.lastAction = \"kill\";\n\t\tthis.value = this.value.slice(0, this.cursor);\n\t}\n\n\tprivate deleteWordBackwards(): void {\n\t\tif (this.cursor === 0) return;\n\n\t\t// Save lastAction before cursor movement (moveWordBackwards resets it)\n\t\tconst wasKill = this.lastAction === \"kill\";\n\n\t\tthis.pushUndo();\n\n\t\tconst oldCursor = this.cursor;\n\t\tthis.moveWordBackwards();\n\t\tconst deleteFrom = this.cursor;\n\t\tthis.cursor = oldCursor;\n\n\t\tconst deletedText = this.value.slice(deleteFrom, this.cursor);\n\t\tthis.killRing.push(deletedText, { prepend: true, accumulate: wasKill });\n\t\tthis.lastAction = \"kill\";\n\n\t\tthis.value = this.value.slice(0, deleteFrom) + this.value.slice(this.cursor);\n\t\tthis.cursor = deleteFrom;\n\t}\n\n\tprivate deleteWordForward(): void {\n\t\tif (this.cursor >= this.value.length) return;\n\n\t\t// Save lastAction before cursor movement (moveWordForwards resets it)\n\t\tconst wasKill = this.lastAction === \"kill\";\n\n\t\tthis.pushUndo();\n\n\t\tconst oldCursor = this.cursor;\n\t\tthis.moveWordForwards();\n\t\tconst deleteTo = this.cursor;\n\t\tthis.cursor = oldCursor;\n\n\t\tconst deletedText = this.value.slice(this.cursor, deleteTo);\n\t\tthis.killRing.push(deletedText, { prepend: false, accumulate: wasKill });\n\t\tthis.lastAction = \"kill\";\n\n\t\tthis.value = this.value.slice(0, this.cursor) + this.value.slice(deleteTo);\n\t}\n\n\tprivate yank(): void {\n\t\tconst text = this.killRing.peek();\n\t\tif (!text) return;\n\n\t\tthis.pushUndo();\n\n\t\tthis.value = this.value.slice(0, this.cursor) + text + this.value.slice(this.cursor);\n\t\tthis.cursor += text.length;\n\t\tthis.lastAction = \"yank\";\n\t}\n\n\tprivate yankPop(): void {\n\t\tif (this.lastAction !== \"yank\" || this.killRing.length <= 1) return;\n\n\t\tthis.pushUndo();\n\n\t\tconst prevText = this.killRing.peek() || \"\";\n\t\tthis.value = this.value.slice(0, this.cursor - prevText.length) + this.value.slice(this.cursor);\n\t\tthis.cursor -= prevText.length;\n\n\t\tthis.killRing.rotate();\n\t\tconst text = this.killRing.peek() || \"\";\n\t\tthis.value = this.value.slice(0, this.cursor) + text + this.value.slice(this.cursor);\n\t\tthis.cursor += text.length;\n\t\tthis.lastAction = \"yank\";\n\t}\n\n\tprivate pushUndo(): void {\n\t\tthis.undoStack.push({ value: this.value, cursor: this.cursor });\n\t}\n\n\tprivate undo(): void {\n\t\tconst snapshot = this.undoStack.pop();\n\t\tif (!snapshot) return;\n\t\tthis.value = snapshot.value;\n\t\tthis.cursor = snapshot.cursor;\n\t\tthis.lastAction = null;\n\t}\n\n\tprivate moveWordBackwards(): void {\n\t\tif (this.cursor === 0) {\n\t\t\treturn;\n\t\t}\n\n\t\tthis.lastAction = null;\n\t\tconst textBeforeCursor = this.value.slice(0, this.cursor);\n\t\tconst graphemes = [...segmenter.segment(textBeforeCursor)];\n\n\t\twhile (graphemes.length > 0 && isWhitespaceChar(graphemes[graphemes.length - 1]?.segment || \"\")) {\n\t\t\tthis.cursor -= graphemes.pop()?.segment.length || 0;\n\t\t}\n\n\t\tif (graphemes.length > 0) {\n\t\t\tconst lastGrapheme = graphemes[graphemes.length - 1]?.segment || \"\";\n\t\t\tif (isPunctuationChar(lastGrapheme)) {\n\t\t\t\twhile (graphemes.length > 0 && isPunctuationChar(graphemes[graphemes.length - 1]?.segment || \"\")) {\n\t\t\t\t\tthis.cursor -= graphemes.pop()?.segment.length || 0;\n\t\t\t\t}\n\t\t\t} else {\n\t\t\t\twhile (\n\t\t\t\t\tgraphemes.length > 0 &&\n\t\t\t\t\t!isWhitespaceChar(graphemes[graphemes.length - 1]?.segment || \"\") &&\n\t\t\t\t\t!isPunctuationChar(graphemes[graphemes.length - 1]?.segment || \"\")\n\t\t\t\t) {\n\t\t\t\t\tthis.cursor -= graphemes.pop()?.segment.length || 0;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\n\tprivate moveWordForwards(): void {\n\t\tif (this.cursor >= this.value.length) {\n\t\t\treturn;\n\t\t}\n\n\t\tthis.lastAction = null;\n\t\tconst textAfterCursor = this.value.slice(this.cursor);\n\t\tconst segments = segmenter.segment(textAfterCursor);\n\t\tconst iterator = segments[Symbol.iterator]();\n\t\tlet next = iterator.next();\n\n\t\twhile (!next.done && isWhitespaceChar(next.value.segment)) {\n\t\t\tthis.cursor += next.value.segment.length;\n\t\t\tnext = iterator.next();\n\t\t}\n\n\t\tif (!next.done) {\n\t\t\tconst firstGrapheme = next.value.segment;\n\t\t\tif (isPunctuationChar(firstGrapheme)) {\n\t\t\t\twhile (!next.done && isPunctuationChar(next.value.segment)) {\n\t\t\t\t\tthis.cursor += next.value.segment.length;\n\t\t\t\t\tnext = iterator.next();\n\t\t\t\t}\n\t\t\t} else {\n\t\t\t\twhile (!next.done && !isWhitespaceChar(next.value.segment) && !isPunctuationChar(next.value.segment)) {\n\t\t\t\t\tthis.cursor += next.value.segment.length;\n\t\t\t\t\tnext = iterator.next();\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\n\tprivate handlePaste(pastedText: string): void {\n\t\tthis.lastAction = null;\n\t\tthis.pushUndo();\n\n\t\tconst cleanText = pastedText.replace(/\\r\\n/g, \"\").replace(/\\r/g, \"\").replace(/\\n/g, \"\").replace(/\\t/g, \" \");\n\n\t\tthis.value = this.value.slice(0, this.cursor) + cleanText + this.value.slice(this.cursor);\n\t\tthis.cursor += cleanText.length;\n\t}\n\n\tinvalidate(): void {}\n\n\trender(width: number): string[] {\n\t\tconst prompt = \"> \";\n\t\tconst availableWidth = width - prompt.length;\n\n\t\tif (availableWidth <= 0) {\n\t\t\treturn [prompt];\n\t\t}\n\n\t\tlet visibleText = \"\";\n\t\tlet cursorDisplay = this.cursor;\n\t\tconst totalWidth = visibleWidth(this.value);\n\n\t\tif (totalWidth < availableWidth) {\n\t\t\tvisibleText = this.value;\n\t\t} else {\n\t\t\tconst scrollWidth = this.cursor === this.value.length ? availableWidth - 1 : availableWidth;\n\t\t\tconst cursorCol = visibleWidth(this.value.slice(0, this.cursor));\n\n\t\t\tif (scrollWidth > 0) {\n\t\t\t\tconst halfWidth = Math.floor(scrollWidth / 2);\n\t\t\t\tlet startCol = 0;\n\n\t\t\t\tif (cursorCol < halfWidth) {\n\t\t\t\t\tstartCol = 0;\n\t\t\t\t} else if (cursorCol > totalWidth - halfWidth) {\n\t\t\t\t\tstartCol = Math.max(0, totalWidth - scrollWidth);\n\t\t\t\t} else {\n\t\t\t\t\tstartCol = Math.max(0, cursorCol - halfWidth);\n\t\t\t\t}\n\n\t\t\t\tvisibleText = sliceByColumn(this.value, startCol, scrollWidth, true);\n\t\t\t\tconst beforeCursor = sliceByColumn(this.value, startCol, Math.max(0, cursorCol - startCol), true);\n\t\t\t\tcursorDisplay = beforeCursor.length;\n\t\t\t} else {\n\t\t\t\tvisibleText = \"\";\n\t\t\t\tcursorDisplay = 0;\n\t\t\t}\n\t\t}\n\n\t\tconst graphemes = [...segmenter.segment(visibleText.slice(cursorDisplay))];\n\t\tconst cursorGrapheme = graphemes[0];\n\n\t\tconst beforeCursor = visibleText.slice(0, cursorDisplay);\n\t\tconst atCursor = cursorGrapheme?.segment ?? \" \"; // Character at cursor, or space if at end\n\t\tconst afterCursor = visibleText.slice(cursorDisplay + atCursor.length);\n\n\t\t// Hardware cursor marker (zero-width, emitted before fake cursor for IME positioning)\n\t\tconst marker = this.focused ? CURSOR_MARKER : \"\";\n\n\t\tconst cursorChar = `\\x1b[7m${atCursor}\\x1b[27m`; // ESC[7m = reverse video, ESC[27m = normal\n\t\tconst textWithCursor = beforeCursor + marker + cursorChar + afterCursor;\n\n\t\tconst visualLength = visibleWidth(textWithCursor);\n\t\tconst padding = \" \".repeat(Math.max(0, availableWidth - visualLength));\n\t\tconst line = prompt + textWithCursor + padding;\n\n\t\treturn [line];\n\t}\n}\n"]}
1
+ {"version":3,"file":"input.d.ts","sourceRoot":"","sources":["../../src/components/input.ts"],"names":[],"mappings":"AAGA,OAAO,EAAE,KAAK,SAAS,EAAiB,KAAK,SAAS,EAAE,MAAM,WAAW,CAAC;AAW1E;;GAEG;AACH,qBAAa,KAAM,YAAW,SAAS,EAAE,SAAS;IACjD,OAAO,CAAC,KAAK,CAAc;IAC3B,OAAO,CAAC,MAAM,CAAa;IAC3B,OAAO,CAAC,MAAM,CAAS;IAChB,QAAQ,CAAC,EAAE,CAAC,KAAK,EAAE,MAAM,KAAK,IAAI,CAAC;IACnC,QAAQ,CAAC,EAAE,MAAM,IAAI,CAAC;IAE7B,OAAO,EAAE,OAAO,CAAS;IAEzB,OAAO,CAAC,WAAW,CAAc;IACjC,OAAO,CAAC,SAAS,CAAkB;IAEnC,OAAO,CAAC,QAAQ,CAAkB;IAClC,OAAO,CAAC,UAAU,CAA8C;IAEhE,OAAO,CAAC,SAAS,CAA+B;IAEhD,SAAS,CAAC,MAAM,EAAE,OAAO,GAAG,IAAI,CAE/B;IAED,QAAQ,IAAI,MAAM,CAEjB;IAED,SAAS,IAAI,MAAM,CAElB;IAED,QAAQ,CAAC,KAAK,EAAE,MAAM,GAAG,IAAI,CAG5B;IAED,WAAW,CAAC,IAAI,EAAE,MAAM,GAAG,IAAI,CAkJ9B;IAED,OAAO,CAAC,eAAe;IAUvB,OAAO,CAAC,eAAe;IAavB,OAAO,CAAC,mBAAmB;IAY3B,OAAO,CAAC,iBAAiB;IAUzB,OAAO,CAAC,eAAe;IASvB,OAAO,CAAC,mBAAmB;IAqB3B,OAAO,CAAC,iBAAiB;IAoBzB,OAAO,CAAC,IAAI;IAWZ,OAAO,CAAC,OAAO;IAgBf,OAAO,CAAC,QAAQ;IAIhB,OAAO,CAAC,IAAI;IAQZ,OAAO,CAAC,iBAAiB;IA+BzB,OAAO,CAAC,gBAAgB;IAgCxB,OAAO,CAAC,WAAW;IAUnB,UAAU,IAAI,IAAI,CAAG;IAErB,OAAO,CAAC,YAAY;IAQpB,MAAM,CAAC,KAAK,EAAE,MAAM,GAAG,MAAM,EAAE,CA0D9B;CACD","sourcesContent":["import { getKeybindings } from \"../keybindings.js\";\nimport { decodeKittyPrintable } from \"../keys.js\";\nimport { KillRing } from \"../kill-ring.js\";\nimport { type Component, CURSOR_MARKER, type Focusable } from \"../tui.js\";\nimport { UndoStack } from \"../undo-stack.js\";\nimport { getSegmenter, isPunctuationChar, isWhitespaceChar, sliceByColumn, visibleWidth } from \"../utils.js\";\n\nconst segmenter = getSegmenter();\n\ninterface InputState {\n\tvalue: string;\n\tcursor: number;\n}\n\n/**\n * Input component - single-line text input with horizontal scrolling\n */\nexport class Input implements Component, Focusable {\n\tprivate value: string = \"\";\n\tprivate cursor: number = 0; // Cursor position in the value\n\tprivate masked = false;\n\tpublic onSubmit?: (value: string) => void;\n\tpublic onEscape?: () => void;\n\n\tfocused: boolean = false;\n\n\tprivate pasteBuffer: string = \"\";\n\tprivate isInPaste: boolean = false;\n\n\tprivate killRing = new KillRing();\n\tprivate lastAction: \"kill\" | \"yank\" | \"type-word\" | null = null;\n\n\tprivate undoStack = new UndoStack<InputState>();\n\n\tsetMasked(masked: boolean): void {\n\t\tthis.masked = masked;\n\t}\n\n\tgetValue(): string {\n\t\treturn this.value;\n\t}\n\n\tgetCursor(): number {\n\t\treturn this.cursor;\n\t}\n\n\tsetValue(value: string): void {\n\t\tthis.value = value;\n\t\tthis.cursor = Math.min(this.cursor, value.length);\n\t}\n\n\thandleInput(data: string): void {\n\t\tif (data.includes(\"\\x1b[200~\")) {\n\t\t\tthis.isInPaste = true;\n\t\t\tthis.pasteBuffer = \"\";\n\t\t\tdata = data.replace(\"\\x1b[200~\", \"\");\n\t\t}\n\n\t\tif (this.isInPaste) {\n\t\t\tthis.pasteBuffer += data;\n\n\t\t\tconst endIndex = this.pasteBuffer.indexOf(\"\\x1b[201~\");\n\t\t\tif (endIndex !== -1) {\n\t\t\t\tconst pasteContent = this.pasteBuffer.substring(0, endIndex);\n\n\t\t\t\tthis.handlePaste(pasteContent);\n\n\t\t\t\tthis.isInPaste = false;\n\n\t\t\t\tconst remaining = this.pasteBuffer.substring(endIndex + 6); // 6 = length of \\x1b[201~\n\t\t\t\tthis.pasteBuffer = \"\";\n\t\t\t\tif (remaining) {\n\t\t\t\t\tthis.handleInput(remaining);\n\t\t\t\t}\n\t\t\t}\n\t\t\treturn;\n\t\t}\n\n\t\tconst kb = getKeybindings();\n\n\t\tif (kb.matches(data, \"tui.select.cancel\")) {\n\t\t\tif (this.onEscape) this.onEscape();\n\t\t\treturn;\n\t\t}\n\n\t\tif (kb.matches(data, \"tui.editor.undo\")) {\n\t\t\tthis.undo();\n\t\t\treturn;\n\t\t}\n\n\t\tif (kb.matches(data, \"tui.input.submit\") || data === \"\\n\") {\n\t\t\tif (this.onSubmit) this.onSubmit(this.value);\n\t\t\treturn;\n\t\t}\n\n\t\tif (kb.matches(data, \"tui.editor.deleteCharBackward\")) {\n\t\t\tthis.handleBackspace();\n\t\t\treturn;\n\t\t}\n\n\t\tif (kb.matches(data, \"tui.editor.deleteCharForward\")) {\n\t\t\tthis.handleForwardDelete();\n\t\t\treturn;\n\t\t}\n\n\t\tif (kb.matches(data, \"tui.editor.deleteWordBackward\")) {\n\t\t\tthis.deleteWordBackwards();\n\t\t\treturn;\n\t\t}\n\n\t\tif (kb.matches(data, \"tui.editor.deleteWordForward\")) {\n\t\t\tthis.deleteWordForward();\n\t\t\treturn;\n\t\t}\n\n\t\tif (kb.matches(data, \"tui.editor.deleteToLineStart\")) {\n\t\t\tthis.deleteToLineStart();\n\t\t\treturn;\n\t\t}\n\n\t\tif (kb.matches(data, \"tui.editor.deleteToLineEnd\")) {\n\t\t\tthis.deleteToLineEnd();\n\t\t\treturn;\n\t\t}\n\n\t\tif (kb.matches(data, \"tui.editor.yank\")) {\n\t\t\tthis.yank();\n\t\t\treturn;\n\t\t}\n\t\tif (kb.matches(data, \"tui.editor.yankPop\")) {\n\t\t\tthis.yankPop();\n\t\t\treturn;\n\t\t}\n\n\t\tif (kb.matches(data, \"tui.editor.cursorLeft\")) {\n\t\t\tthis.lastAction = null;\n\t\t\tif (this.cursor > 0) {\n\t\t\t\tconst beforeCursor = this.value.slice(0, this.cursor);\n\t\t\t\tconst graphemes = [...segmenter.segment(beforeCursor)];\n\t\t\t\tconst lastGrapheme = graphemes[graphemes.length - 1];\n\t\t\t\tthis.cursor -= lastGrapheme ? lastGrapheme.segment.length : 1;\n\t\t\t}\n\t\t\treturn;\n\t\t}\n\n\t\tif (kb.matches(data, \"tui.editor.cursorRight\")) {\n\t\t\tthis.lastAction = null;\n\t\t\tif (this.cursor < this.value.length) {\n\t\t\t\tconst afterCursor = this.value.slice(this.cursor);\n\t\t\t\tconst graphemes = [...segmenter.segment(afterCursor)];\n\t\t\t\tconst firstGrapheme = graphemes[0];\n\t\t\t\tthis.cursor += firstGrapheme ? firstGrapheme.segment.length : 1;\n\t\t\t}\n\t\t\treturn;\n\t\t}\n\n\t\tif (kb.matches(data, \"tui.editor.cursorLineStart\")) {\n\t\t\tthis.lastAction = null;\n\t\t\tthis.cursor = 0;\n\t\t\treturn;\n\t\t}\n\n\t\tif (kb.matches(data, \"tui.editor.cursorLineEnd\")) {\n\t\t\tthis.lastAction = null;\n\t\t\tthis.cursor = this.value.length;\n\t\t\treturn;\n\t\t}\n\n\t\tif (kb.matches(data, \"tui.editor.cursorWordLeft\")) {\n\t\t\tthis.moveWordBackwards();\n\t\t\treturn;\n\t\t}\n\n\t\tif (kb.matches(data, \"tui.editor.cursorWordRight\")) {\n\t\t\tthis.moveWordForwards();\n\t\t\treturn;\n\t\t}\n\n\t\t// Kitty CSI-u printable character (e.g. \\x1b[97u for 'a').\n\t\t// Terminals with Kitty protocol flag 1 (disambiguate) send CSI-u for all keys,\n\t\t// including plain printable characters. Decode before the control-char check\n\t\t// since CSI-u sequences contain \\x1b which would be rejected.\n\t\tconst kittyPrintable = decodeKittyPrintable(data);\n\t\tif (kittyPrintable !== undefined) {\n\t\t\tthis.insertCharacter(kittyPrintable);\n\t\t\treturn;\n\t\t}\n\n\t\t// Regular character input - accept printable characters including Unicode,\n\t\t// but reject control characters (C0: 0x00-0x1F, DEL: 0x7F, C1: 0x80-0x9F)\n\t\tconst hasControlChars = [...data].some((ch) => {\n\t\t\tconst code = ch.charCodeAt(0);\n\t\t\treturn code < 32 || code === 0x7f || (code >= 0x80 && code <= 0x9f);\n\t\t});\n\t\tif (!hasControlChars) {\n\t\t\tthis.insertCharacter(data);\n\t\t}\n\t}\n\n\tprivate insertCharacter(char: string): void {\n\t\tif (isWhitespaceChar(char) || this.lastAction !== \"type-word\") {\n\t\t\tthis.pushUndo();\n\t\t}\n\t\tthis.lastAction = \"type-word\";\n\n\t\tthis.value = this.value.slice(0, this.cursor) + char + this.value.slice(this.cursor);\n\t\tthis.cursor += char.length;\n\t}\n\n\tprivate handleBackspace(): void {\n\t\tthis.lastAction = null;\n\t\tif (this.cursor > 0) {\n\t\t\tthis.pushUndo();\n\t\t\tconst beforeCursor = this.value.slice(0, this.cursor);\n\t\t\tconst graphemes = [...segmenter.segment(beforeCursor)];\n\t\t\tconst lastGrapheme = graphemes[graphemes.length - 1];\n\t\t\tconst graphemeLength = lastGrapheme ? lastGrapheme.segment.length : 1;\n\t\t\tthis.value = this.value.slice(0, this.cursor - graphemeLength) + this.value.slice(this.cursor);\n\t\t\tthis.cursor -= graphemeLength;\n\t\t}\n\t}\n\n\tprivate handleForwardDelete(): void {\n\t\tthis.lastAction = null;\n\t\tif (this.cursor < this.value.length) {\n\t\t\tthis.pushUndo();\n\t\t\tconst afterCursor = this.value.slice(this.cursor);\n\t\t\tconst graphemes = [...segmenter.segment(afterCursor)];\n\t\t\tconst firstGrapheme = graphemes[0];\n\t\t\tconst graphemeLength = firstGrapheme ? firstGrapheme.segment.length : 1;\n\t\t\tthis.value = this.value.slice(0, this.cursor) + this.value.slice(this.cursor + graphemeLength);\n\t\t}\n\t}\n\n\tprivate deleteToLineStart(): void {\n\t\tif (this.cursor === 0) return;\n\t\tthis.pushUndo();\n\t\tconst deletedText = this.value.slice(0, this.cursor);\n\t\tthis.killRing.push(deletedText, { prepend: true, accumulate: this.lastAction === \"kill\" });\n\t\tthis.lastAction = \"kill\";\n\t\tthis.value = this.value.slice(this.cursor);\n\t\tthis.cursor = 0;\n\t}\n\n\tprivate deleteToLineEnd(): void {\n\t\tif (this.cursor >= this.value.length) return;\n\t\tthis.pushUndo();\n\t\tconst deletedText = this.value.slice(this.cursor);\n\t\tthis.killRing.push(deletedText, { prepend: false, accumulate: this.lastAction === \"kill\" });\n\t\tthis.lastAction = \"kill\";\n\t\tthis.value = this.value.slice(0, this.cursor);\n\t}\n\n\tprivate deleteWordBackwards(): void {\n\t\tif (this.cursor === 0) return;\n\n\t\t// Save lastAction before cursor movement (moveWordBackwards resets it)\n\t\tconst wasKill = this.lastAction === \"kill\";\n\n\t\tthis.pushUndo();\n\n\t\tconst oldCursor = this.cursor;\n\t\tthis.moveWordBackwards();\n\t\tconst deleteFrom = this.cursor;\n\t\tthis.cursor = oldCursor;\n\n\t\tconst deletedText = this.value.slice(deleteFrom, this.cursor);\n\t\tthis.killRing.push(deletedText, { prepend: true, accumulate: wasKill });\n\t\tthis.lastAction = \"kill\";\n\n\t\tthis.value = this.value.slice(0, deleteFrom) + this.value.slice(this.cursor);\n\t\tthis.cursor = deleteFrom;\n\t}\n\n\tprivate deleteWordForward(): void {\n\t\tif (this.cursor >= this.value.length) return;\n\n\t\t// Save lastAction before cursor movement (moveWordForwards resets it)\n\t\tconst wasKill = this.lastAction === \"kill\";\n\n\t\tthis.pushUndo();\n\n\t\tconst oldCursor = this.cursor;\n\t\tthis.moveWordForwards();\n\t\tconst deleteTo = this.cursor;\n\t\tthis.cursor = oldCursor;\n\n\t\tconst deletedText = this.value.slice(this.cursor, deleteTo);\n\t\tthis.killRing.push(deletedText, { prepend: false, accumulate: wasKill });\n\t\tthis.lastAction = \"kill\";\n\n\t\tthis.value = this.value.slice(0, this.cursor) + this.value.slice(deleteTo);\n\t}\n\n\tprivate yank(): void {\n\t\tconst text = this.killRing.peek();\n\t\tif (!text) return;\n\n\t\tthis.pushUndo();\n\n\t\tthis.value = this.value.slice(0, this.cursor) + text + this.value.slice(this.cursor);\n\t\tthis.cursor += text.length;\n\t\tthis.lastAction = \"yank\";\n\t}\n\n\tprivate yankPop(): void {\n\t\tif (this.lastAction !== \"yank\" || this.killRing.length <= 1) return;\n\n\t\tthis.pushUndo();\n\n\t\tconst prevText = this.killRing.peek() || \"\";\n\t\tthis.value = this.value.slice(0, this.cursor - prevText.length) + this.value.slice(this.cursor);\n\t\tthis.cursor -= prevText.length;\n\n\t\tthis.killRing.rotate();\n\t\tconst text = this.killRing.peek() || \"\";\n\t\tthis.value = this.value.slice(0, this.cursor) + text + this.value.slice(this.cursor);\n\t\tthis.cursor += text.length;\n\t\tthis.lastAction = \"yank\";\n\t}\n\n\tprivate pushUndo(): void {\n\t\tthis.undoStack.push({ value: this.value, cursor: this.cursor });\n\t}\n\n\tprivate undo(): void {\n\t\tconst snapshot = this.undoStack.pop();\n\t\tif (!snapshot) return;\n\t\tthis.value = snapshot.value;\n\t\tthis.cursor = snapshot.cursor;\n\t\tthis.lastAction = null;\n\t}\n\n\tprivate moveWordBackwards(): void {\n\t\tif (this.cursor === 0) {\n\t\t\treturn;\n\t\t}\n\n\t\tthis.lastAction = null;\n\t\tconst textBeforeCursor = this.value.slice(0, this.cursor);\n\t\tconst graphemes = [...segmenter.segment(textBeforeCursor)];\n\n\t\twhile (graphemes.length > 0 && isWhitespaceChar(graphemes[graphemes.length - 1]?.segment || \"\")) {\n\t\t\tthis.cursor -= graphemes.pop()?.segment.length || 0;\n\t\t}\n\n\t\tif (graphemes.length > 0) {\n\t\t\tconst lastGrapheme = graphemes[graphemes.length - 1]?.segment || \"\";\n\t\t\tif (isPunctuationChar(lastGrapheme)) {\n\t\t\t\twhile (graphemes.length > 0 && isPunctuationChar(graphemes[graphemes.length - 1]?.segment || \"\")) {\n\t\t\t\t\tthis.cursor -= graphemes.pop()?.segment.length || 0;\n\t\t\t\t}\n\t\t\t} else {\n\t\t\t\twhile (\n\t\t\t\t\tgraphemes.length > 0 &&\n\t\t\t\t\t!isWhitespaceChar(graphemes[graphemes.length - 1]?.segment || \"\") &&\n\t\t\t\t\t!isPunctuationChar(graphemes[graphemes.length - 1]?.segment || \"\")\n\t\t\t\t) {\n\t\t\t\t\tthis.cursor -= graphemes.pop()?.segment.length || 0;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\n\tprivate moveWordForwards(): void {\n\t\tif (this.cursor >= this.value.length) {\n\t\t\treturn;\n\t\t}\n\n\t\tthis.lastAction = null;\n\t\tconst textAfterCursor = this.value.slice(this.cursor);\n\t\tconst segments = segmenter.segment(textAfterCursor);\n\t\tconst iterator = segments[Symbol.iterator]();\n\t\tlet next = iterator.next();\n\n\t\twhile (!next.done && isWhitespaceChar(next.value.segment)) {\n\t\t\tthis.cursor += next.value.segment.length;\n\t\t\tnext = iterator.next();\n\t\t}\n\n\t\tif (!next.done) {\n\t\t\tconst firstGrapheme = next.value.segment;\n\t\t\tif (isPunctuationChar(firstGrapheme)) {\n\t\t\t\twhile (!next.done && isPunctuationChar(next.value.segment)) {\n\t\t\t\t\tthis.cursor += next.value.segment.length;\n\t\t\t\t\tnext = iterator.next();\n\t\t\t\t}\n\t\t\t} else {\n\t\t\t\twhile (!next.done && !isWhitespaceChar(next.value.segment) && !isPunctuationChar(next.value.segment)) {\n\t\t\t\t\tthis.cursor += next.value.segment.length;\n\t\t\t\t\tnext = iterator.next();\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\n\tprivate handlePaste(pastedText: string): void {\n\t\tthis.lastAction = null;\n\t\tthis.pushUndo();\n\n\t\tconst cleanText = pastedText.replace(/\\r\\n/g, \"\").replace(/\\r/g, \"\").replace(/\\n/g, \"\").replace(/\\t/g, \" \");\n\n\t\tthis.value = this.value.slice(0, this.cursor) + cleanText + this.value.slice(this.cursor);\n\t\tthis.cursor += cleanText.length;\n\t}\n\n\tinvalidate(): void {}\n\n\tprivate displayState(): InputState {\n\t\tif (!this.masked) return { value: this.value, cursor: this.cursor };\n\t\t// Mask by grapheme; edits and submissions keep the original buffer.\n\t\tconst graphemes = [...segmenter.segment(this.value)];\n\t\tconst beforeCursor = [...segmenter.segment(this.value.slice(0, this.cursor))];\n\t\treturn { value: \"•\".repeat(graphemes.length), cursor: beforeCursor.length };\n\t}\n\n\trender(width: number): string[] {\n\t\tconst prompt = \"> \";\n\t\tconst availableWidth = width - prompt.length;\n\n\t\tif (availableWidth <= 0) {\n\t\t\treturn [prompt];\n\t\t}\n\n\t\tconst display = this.displayState();\n\t\tlet visibleText = \"\";\n\t\tlet cursorDisplay = display.cursor;\n\t\tconst totalWidth = visibleWidth(display.value);\n\n\t\tif (totalWidth < availableWidth) {\n\t\t\tvisibleText = display.value;\n\t\t} else {\n\t\t\tconst scrollWidth = display.cursor === display.value.length ? availableWidth - 1 : availableWidth;\n\t\t\tconst cursorCol = visibleWidth(display.value.slice(0, display.cursor));\n\n\t\t\tif (scrollWidth > 0) {\n\t\t\t\tconst halfWidth = Math.floor(scrollWidth / 2);\n\t\t\t\tlet startCol = 0;\n\n\t\t\t\tif (cursorCol < halfWidth) {\n\t\t\t\t\tstartCol = 0;\n\t\t\t\t} else if (cursorCol > totalWidth - halfWidth) {\n\t\t\t\t\tstartCol = Math.max(0, totalWidth - scrollWidth);\n\t\t\t\t} else {\n\t\t\t\t\tstartCol = Math.max(0, cursorCol - halfWidth);\n\t\t\t\t}\n\n\t\t\t\tvisibleText = sliceByColumn(display.value, startCol, scrollWidth, true);\n\t\t\t\tconst beforeCursor = sliceByColumn(display.value, startCol, Math.max(0, cursorCol - startCol), true);\n\t\t\t\tcursorDisplay = beforeCursor.length;\n\t\t\t} else {\n\t\t\t\tvisibleText = \"\";\n\t\t\t\tcursorDisplay = 0;\n\t\t\t}\n\t\t}\n\n\t\tconst graphemes = [...segmenter.segment(visibleText.slice(cursorDisplay))];\n\t\tconst cursorGrapheme = graphemes[0];\n\n\t\tconst beforeCursor = visibleText.slice(0, cursorDisplay);\n\t\tconst atCursor = cursorGrapheme?.segment ?? \" \"; // Character at cursor, or space if at end\n\t\tconst afterCursor = visibleText.slice(cursorDisplay + atCursor.length);\n\n\t\t// Hardware cursor marker (zero-width, emitted before fake cursor for IME positioning)\n\t\tconst marker = this.focused ? CURSOR_MARKER : \"\";\n\n\t\tconst cursorChar = `\\x1b[7m${atCursor}\\x1b[27m`; // ESC[7m = reverse video, ESC[27m = normal\n\t\tconst textWithCursor = beforeCursor + marker + cursorChar + afterCursor;\n\n\t\tconst visualLength = visibleWidth(textWithCursor);\n\t\tconst padding = \" \".repeat(Math.max(0, availableWidth - visualLength));\n\t\tconst line = prompt + textWithCursor + padding;\n\n\t\treturn [line];\n\t}\n}\n"]}
@@ -11,6 +11,7 @@ const segmenter = getSegmenter();
11
11
  export class Input {
12
12
  value = "";
13
13
  cursor = 0; // Cursor position in the value
14
+ masked = false;
14
15
  onSubmit;
15
16
  onEscape;
16
17
  focused = false;
@@ -19,6 +20,9 @@ export class Input {
19
20
  killRing = new KillRing();
20
21
  lastAction = null;
21
22
  undoStack = new UndoStack();
23
+ setMasked(masked) {
24
+ this.masked = masked;
25
+ }
22
26
  getValue() {
23
27
  return this.value;
24
28
  }
@@ -331,21 +335,30 @@ export class Input {
331
335
  this.cursor += cleanText.length;
332
336
  }
333
337
  invalidate() { }
338
+ displayState() {
339
+ if (!this.masked)
340
+ return { value: this.value, cursor: this.cursor };
341
+ // Mask by grapheme; edits and submissions keep the original buffer.
342
+ const graphemes = [...segmenter.segment(this.value)];
343
+ const beforeCursor = [...segmenter.segment(this.value.slice(0, this.cursor))];
344
+ return { value: "•".repeat(graphemes.length), cursor: beforeCursor.length };
345
+ }
334
346
  render(width) {
335
347
  const prompt = "> ";
336
348
  const availableWidth = width - prompt.length;
337
349
  if (availableWidth <= 0) {
338
350
  return [prompt];
339
351
  }
352
+ const display = this.displayState();
340
353
  let visibleText = "";
341
- let cursorDisplay = this.cursor;
342
- const totalWidth = visibleWidth(this.value);
354
+ let cursorDisplay = display.cursor;
355
+ const totalWidth = visibleWidth(display.value);
343
356
  if (totalWidth < availableWidth) {
344
- visibleText = this.value;
357
+ visibleText = display.value;
345
358
  }
346
359
  else {
347
- const scrollWidth = this.cursor === this.value.length ? availableWidth - 1 : availableWidth;
348
- const cursorCol = visibleWidth(this.value.slice(0, this.cursor));
360
+ const scrollWidth = display.cursor === display.value.length ? availableWidth - 1 : availableWidth;
361
+ const cursorCol = visibleWidth(display.value.slice(0, display.cursor));
349
362
  if (scrollWidth > 0) {
350
363
  const halfWidth = Math.floor(scrollWidth / 2);
351
364
  let startCol = 0;
@@ -358,8 +371,8 @@ export class Input {
358
371
  else {
359
372
  startCol = Math.max(0, cursorCol - halfWidth);
360
373
  }
361
- visibleText = sliceByColumn(this.value, startCol, scrollWidth, true);
362
- const beforeCursor = sliceByColumn(this.value, startCol, Math.max(0, cursorCol - startCol), true);
374
+ visibleText = sliceByColumn(display.value, startCol, scrollWidth, true);
375
+ const beforeCursor = sliceByColumn(display.value, startCol, Math.max(0, cursorCol - startCol), true);
363
376
  cursorDisplay = beforeCursor.length;
364
377
  }
365
378
  else {
@@ -1 +1 @@
1
- {"version":3,"file":"input.js","sourceRoot":"","sources":["../../src/components/input.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,cAAc,EAAE,MAAM,mBAAmB,CAAC;AACnD,OAAO,EAAE,oBAAoB,EAAE,MAAM,YAAY,CAAC;AAClD,OAAO,EAAE,QAAQ,EAAE,MAAM,iBAAiB,CAAC;AAC3C,OAAO,EAAkB,aAAa,EAAkB,MAAM,WAAW,CAAC;AAC1E,OAAO,EAAE,SAAS,EAAE,MAAM,kBAAkB,CAAC;AAC7C,OAAO,EAAE,YAAY,EAAE,iBAAiB,EAAE,gBAAgB,EAAE,aAAa,EAAE,YAAY,EAAE,MAAM,aAAa,CAAC;AAE7G,MAAM,SAAS,GAAG,YAAY,EAAE,CAAC;AAOjC;;GAEG;AACH,MAAM,OAAO,KAAK;IACT,KAAK,GAAW,EAAE,CAAC;IACnB,MAAM,GAAW,CAAC,CAAC,CAAC,+BAA+B;IACpD,QAAQ,CAA2B;IACnC,QAAQ,CAAc;IAE7B,OAAO,GAAY,KAAK,CAAC;IAEjB,WAAW,GAAW,EAAE,CAAC;IACzB,SAAS,GAAY,KAAK,CAAC;IAE3B,QAAQ,GAAG,IAAI,QAAQ,EAAE,CAAC;IAC1B,UAAU,GAAyC,IAAI,CAAC;IAExD,SAAS,GAAG,IAAI,SAAS,EAAc,CAAC;IAEhD,QAAQ,GAAW;QAClB,OAAO,IAAI,CAAC,KAAK,CAAC;IAAA,CAClB;IAED,SAAS,GAAW;QACnB,OAAO,IAAI,CAAC,MAAM,CAAC;IAAA,CACnB;IAED,QAAQ,CAAC,KAAa,EAAQ;QAC7B,IAAI,CAAC,KAAK,GAAG,KAAK,CAAC;QACnB,IAAI,CAAC,MAAM,GAAG,IAAI,CAAC,GAAG,CAAC,IAAI,CAAC,MAAM,EAAE,KAAK,CAAC,MAAM,CAAC,CAAC;IAAA,CAClD;IAED,WAAW,CAAC,IAAY,EAAQ;QAC/B,IAAI,IAAI,CAAC,QAAQ,CAAC,WAAW,CAAC,EAAE,CAAC;YAChC,IAAI,CAAC,SAAS,GAAG,IAAI,CAAC;YACtB,IAAI,CAAC,WAAW,GAAG,EAAE,CAAC;YACtB,IAAI,GAAG,IAAI,CAAC,OAAO,CAAC,WAAW,EAAE,EAAE,CAAC,CAAC;QACtC,CAAC;QAED,IAAI,IAAI,CAAC,SAAS,EAAE,CAAC;YACpB,IAAI,CAAC,WAAW,IAAI,IAAI,CAAC;YAEzB,MAAM,QAAQ,GAAG,IAAI,CAAC,WAAW,CAAC,OAAO,CAAC,WAAW,CAAC,CAAC;YACvD,IAAI,QAAQ,KAAK,CAAC,CAAC,EAAE,CAAC;gBACrB,MAAM,YAAY,GAAG,IAAI,CAAC,WAAW,CAAC,SAAS,CAAC,CAAC,EAAE,QAAQ,CAAC,CAAC;gBAE7D,IAAI,CAAC,WAAW,CAAC,YAAY,CAAC,CAAC;gBAE/B,IAAI,CAAC,SAAS,GAAG,KAAK,CAAC;gBAEvB,MAAM,SAAS,GAAG,IAAI,CAAC,WAAW,CAAC,SAAS,CAAC,QAAQ,GAAG,CAAC,CAAC,CAAC,CAAC,0BAA0B;gBACtF,IAAI,CAAC,WAAW,GAAG,EAAE,CAAC;gBACtB,IAAI,SAAS,EAAE,CAAC;oBACf,IAAI,CAAC,WAAW,CAAC,SAAS,CAAC,CAAC;gBAC7B,CAAC;YACF,CAAC;YACD,OAAO;QACR,CAAC;QAED,MAAM,EAAE,GAAG,cAAc,EAAE,CAAC;QAE5B,IAAI,EAAE,CAAC,OAAO,CAAC,IAAI,EAAE,mBAAmB,CAAC,EAAE,CAAC;YAC3C,IAAI,IAAI,CAAC,QAAQ;gBAAE,IAAI,CAAC,QAAQ,EAAE,CAAC;YACnC,OAAO;QACR,CAAC;QAED,IAAI,EAAE,CAAC,OAAO,CAAC,IAAI,EAAE,iBAAiB,CAAC,EAAE,CAAC;YACzC,IAAI,CAAC,IAAI,EAAE,CAAC;YACZ,OAAO;QACR,CAAC;QAED,IAAI,EAAE,CAAC,OAAO,CAAC,IAAI,EAAE,kBAAkB,CAAC,IAAI,IAAI,KAAK,IAAI,EAAE,CAAC;YAC3D,IAAI,IAAI,CAAC,QAAQ;gBAAE,IAAI,CAAC,QAAQ,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;YAC7C,OAAO;QACR,CAAC;QAED,IAAI,EAAE,CAAC,OAAO,CAAC,IAAI,EAAE,+BAA+B,CAAC,EAAE,CAAC;YACvD,IAAI,CAAC,eAAe,EAAE,CAAC;YACvB,OAAO;QACR,CAAC;QAED,IAAI,EAAE,CAAC,OAAO,CAAC,IAAI,EAAE,8BAA8B,CAAC,EAAE,CAAC;YACtD,IAAI,CAAC,mBAAmB,EAAE,CAAC;YAC3B,OAAO;QACR,CAAC;QAED,IAAI,EAAE,CAAC,OAAO,CAAC,IAAI,EAAE,+BAA+B,CAAC,EAAE,CAAC;YACvD,IAAI,CAAC,mBAAmB,EAAE,CAAC;YAC3B,OAAO;QACR,CAAC;QAED,IAAI,EAAE,CAAC,OAAO,CAAC,IAAI,EAAE,8BAA8B,CAAC,EAAE,CAAC;YACtD,IAAI,CAAC,iBAAiB,EAAE,CAAC;YACzB,OAAO;QACR,CAAC;QAED,IAAI,EAAE,CAAC,OAAO,CAAC,IAAI,EAAE,8BAA8B,CAAC,EAAE,CAAC;YACtD,IAAI,CAAC,iBAAiB,EAAE,CAAC;YACzB,OAAO;QACR,CAAC;QAED,IAAI,EAAE,CAAC,OAAO,CAAC,IAAI,EAAE,4BAA4B,CAAC,EAAE,CAAC;YACpD,IAAI,CAAC,eAAe,EAAE,CAAC;YACvB,OAAO;QACR,CAAC;QAED,IAAI,EAAE,CAAC,OAAO,CAAC,IAAI,EAAE,iBAAiB,CAAC,EAAE,CAAC;YACzC,IAAI,CAAC,IAAI,EAAE,CAAC;YACZ,OAAO;QACR,CAAC;QACD,IAAI,EAAE,CAAC,OAAO,CAAC,IAAI,EAAE,oBAAoB,CAAC,EAAE,CAAC;YAC5C,IAAI,CAAC,OAAO,EAAE,CAAC;YACf,OAAO;QACR,CAAC;QAED,IAAI,EAAE,CAAC,OAAO,CAAC,IAAI,EAAE,uBAAuB,CAAC,EAAE,CAAC;YAC/C,IAAI,CAAC,UAAU,GAAG,IAAI,CAAC;YACvB,IAAI,IAAI,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;gBACrB,MAAM,YAAY,GAAG,IAAI,CAAC,KAAK,CAAC,KAAK,CAAC,CAAC,EAAE,IAAI,CAAC,MAAM,CAAC,CAAC;gBACtD,MAAM,SAAS,GAAG,CAAC,GAAG,SAAS,CAAC,OAAO,CAAC,YAAY,CAAC,CAAC,CAAC;gBACvD,MAAM,YAAY,GAAG,SAAS,CAAC,SAAS,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC;gBACrD,IAAI,CAAC,MAAM,IAAI,YAAY,CAAC,CAAC,CAAC,YAAY,CAAC,OAAO,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,CAAC;YAC/D,CAAC;YACD,OAAO;QACR,CAAC;QAED,IAAI,EAAE,CAAC,OAAO,CAAC,IAAI,EAAE,wBAAwB,CAAC,EAAE,CAAC;YAChD,IAAI,CAAC,UAAU,GAAG,IAAI,CAAC;YACvB,IAAI,IAAI,CAAC,MAAM,GAAG,IAAI,CAAC,KAAK,CAAC,MAAM,EAAE,CAAC;gBACrC,MAAM,WAAW,GAAG,IAAI,CAAC,KAAK,CAAC,KAAK,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC;gBAClD,MAAM,SAAS,GAAG,CAAC,GAAG,SAAS,CAAC,OAAO,CAAC,WAAW,CAAC,CAAC,CAAC;gBACtD,MAAM,aAAa,GAAG,SAAS,CAAC,CAAC,CAAC,CAAC;gBACnC,IAAI,CAAC,MAAM,IAAI,aAAa,CAAC,CAAC,CAAC,aAAa,CAAC,OAAO,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,CAAC;YACjE,CAAC;YACD,OAAO;QACR,CAAC;QAED,IAAI,EAAE,CAAC,OAAO,CAAC,IAAI,EAAE,4BAA4B,CAAC,EAAE,CAAC;YACpD,IAAI,CAAC,UAAU,GAAG,IAAI,CAAC;YACvB,IAAI,CAAC,MAAM,GAAG,CAAC,CAAC;YAChB,OAAO;QACR,CAAC;QAED,IAAI,EAAE,CAAC,OAAO,CAAC,IAAI,EAAE,0BAA0B,CAAC,EAAE,CAAC;YAClD,IAAI,CAAC,UAAU,GAAG,IAAI,CAAC;YACvB,IAAI,CAAC,MAAM,GAAG,IAAI,CAAC,KAAK,CAAC,MAAM,CAAC;YAChC,OAAO;QACR,CAAC;QAED,IAAI,EAAE,CAAC,OAAO,CAAC,IAAI,EAAE,2BAA2B,CAAC,EAAE,CAAC;YACnD,IAAI,CAAC,iBAAiB,EAAE,CAAC;YACzB,OAAO;QACR,CAAC;QAED,IAAI,EAAE,CAAC,OAAO,CAAC,IAAI,EAAE,4BAA4B,CAAC,EAAE,CAAC;YACpD,IAAI,CAAC,gBAAgB,EAAE,CAAC;YACxB,OAAO;QACR,CAAC;QAED,2DAA2D;QAC3D,+EAA+E;QAC/E,6EAA6E;QAC7E,8DAA8D;QAC9D,MAAM,cAAc,GAAG,oBAAoB,CAAC,IAAI,CAAC,CAAC;QAClD,IAAI,cAAc,KAAK,SAAS,EAAE,CAAC;YAClC,IAAI,CAAC,eAAe,CAAC,cAAc,CAAC,CAAC;YACrC,OAAO;QACR,CAAC;QAED,2EAA2E;QAC3E,0EAA0E;QAC1E,MAAM,eAAe,GAAG,CAAC,GAAG,IAAI,CAAC,CAAC,IAAI,CAAC,CAAC,EAAE,EAAE,EAAE,CAAC;YAC9C,MAAM,IAAI,GAAG,EAAE,CAAC,UAAU,CAAC,CAAC,CAAC,CAAC;YAC9B,OAAO,IAAI,GAAG,EAAE,IAAI,IAAI,KAAK,IAAI,IAAI,CAAC,IAAI,IAAI,IAAI,IAAI,IAAI,IAAI,IAAI,CAAC,CAAC;QAAA,CACpE,CAAC,CAAC;QACH,IAAI,CAAC,eAAe,EAAE,CAAC;YACtB,IAAI,CAAC,eAAe,CAAC,IAAI,CAAC,CAAC;QAC5B,CAAC;IAAA,CACD;IAEO,eAAe,CAAC,IAAY,EAAQ;QAC3C,IAAI,gBAAgB,CAAC,IAAI,CAAC,IAAI,IAAI,CAAC,UAAU,KAAK,WAAW,EAAE,CAAC;YAC/D,IAAI,CAAC,QAAQ,EAAE,CAAC;QACjB,CAAC;QACD,IAAI,CAAC,UAAU,GAAG,WAAW,CAAC;QAE9B,IAAI,CAAC,KAAK,GAAG,IAAI,CAAC,KAAK,CAAC,KAAK,CAAC,CAAC,EAAE,IAAI,CAAC,MAAM,CAAC,GAAG,IAAI,GAAG,IAAI,CAAC,KAAK,CAAC,KAAK,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC;QACrF,IAAI,CAAC,MAAM,IAAI,IAAI,CAAC,MAAM,CAAC;IAAA,CAC3B;IAEO,eAAe,GAAS;QAC/B,IAAI,CAAC,UAAU,GAAG,IAAI,CAAC;QACvB,IAAI,IAAI,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;YACrB,IAAI,CAAC,QAAQ,EAAE,CAAC;YAChB,MAAM,YAAY,GAAG,IAAI,CAAC,KAAK,CAAC,KAAK,CAAC,CAAC,EAAE,IAAI,CAAC,MAAM,CAAC,CAAC;YACtD,MAAM,SAAS,GAAG,CAAC,GAAG,SAAS,CAAC,OAAO,CAAC,YAAY,CAAC,CAAC,CAAC;YACvD,MAAM,YAAY,GAAG,SAAS,CAAC,SAAS,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC;YACrD,MAAM,cAAc,GAAG,YAAY,CAAC,CAAC,CAAC,YAAY,CAAC,OAAO,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,CAAC;YACtE,IAAI,CAAC,KAAK,GAAG,IAAI,CAAC,KAAK,CAAC,KAAK,CAAC,CAAC,EAAE,IAAI,CAAC,MAAM,GAAG,cAAc,CAAC,GAAG,IAAI,CAAC,KAAK,CAAC,KAAK,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC;YAC/F,IAAI,CAAC,MAAM,IAAI,cAAc,CAAC;QAC/B,CAAC;IAAA,CACD;IAEO,mBAAmB,GAAS;QACnC,IAAI,CAAC,UAAU,GAAG,IAAI,CAAC;QACvB,IAAI,IAAI,CAAC,MAAM,GAAG,IAAI,CAAC,KAAK,CAAC,MAAM,EAAE,CAAC;YACrC,IAAI,CAAC,QAAQ,EAAE,CAAC;YAChB,MAAM,WAAW,GAAG,IAAI,CAAC,KAAK,CAAC,KAAK,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC;YAClD,MAAM,SAAS,GAAG,CAAC,GAAG,SAAS,CAAC,OAAO,CAAC,WAAW,CAAC,CAAC,CAAC;YACtD,MAAM,aAAa,GAAG,SAAS,CAAC,CAAC,CAAC,CAAC;YACnC,MAAM,cAAc,GAAG,aAAa,CAAC,CAAC,CAAC,aAAa,CAAC,OAAO,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,CAAC;YACxE,IAAI,CAAC,KAAK,GAAG,IAAI,CAAC,KAAK,CAAC,KAAK,CAAC,CAAC,EAAE,IAAI,CAAC,MAAM,CAAC,GAAG,IAAI,CAAC,KAAK,CAAC,KAAK,CAAC,IAAI,CAAC,MAAM,GAAG,cAAc,CAAC,CAAC;QAChG,CAAC;IAAA,CACD;IAEO,iBAAiB,GAAS;QACjC,IAAI,IAAI,CAAC,MAAM,KAAK,CAAC;YAAE,OAAO;QAC9B,IAAI,CAAC,QAAQ,EAAE,CAAC;QAChB,MAAM,WAAW,GAAG,IAAI,CAAC,KAAK,CAAC,KAAK,CAAC,CAAC,EAAE,IAAI,CAAC,MAAM,CAAC,CAAC;QACrD,IAAI,CAAC,QAAQ,CAAC,IAAI,CAAC,WAAW,EAAE,EAAE,OAAO,EAAE,IAAI,EAAE,UAAU,EAAE,IAAI,CAAC,UAAU,KAAK,MAAM,EAAE,CAAC,CAAC;QAC3F,IAAI,CAAC,UAAU,GAAG,MAAM,CAAC;QACzB,IAAI,CAAC,KAAK,GAAG,IAAI,CAAC,KAAK,CAAC,KAAK,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC;QAC3C,IAAI,CAAC,MAAM,GAAG,CAAC,CAAC;IAAA,CAChB;IAEO,eAAe,GAAS;QAC/B,IAAI,IAAI,CAAC,MAAM,IAAI,IAAI,CAAC,KAAK,CAAC,MAAM;YAAE,OAAO;QAC7C,IAAI,CAAC,QAAQ,EAAE,CAAC;QAChB,MAAM,WAAW,GAAG,IAAI,CAAC,KAAK,CAAC,KAAK,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC;QAClD,IAAI,CAAC,QAAQ,CAAC,IAAI,CAAC,WAAW,EAAE,EAAE,OAAO,EAAE,KAAK,EAAE,UAAU,EAAE,IAAI,CAAC,UAAU,KAAK,MAAM,EAAE,CAAC,CAAC;QAC5F,IAAI,CAAC,UAAU,GAAG,MAAM,CAAC;QACzB,IAAI,CAAC,KAAK,GAAG,IAAI,CAAC,KAAK,CAAC,KAAK,CAAC,CAAC,EAAE,IAAI,CAAC,MAAM,CAAC,CAAC;IAAA,CAC9C;IAEO,mBAAmB,GAAS;QACnC,IAAI,IAAI,CAAC,MAAM,KAAK,CAAC;YAAE,OAAO;QAE9B,uEAAuE;QACvE,MAAM,OAAO,GAAG,IAAI,CAAC,UAAU,KAAK,MAAM,CAAC;QAE3C,IAAI,CAAC,QAAQ,EAAE,CAAC;QAEhB,MAAM,SAAS,GAAG,IAAI,CAAC,MAAM,CAAC;QAC9B,IAAI,CAAC,iBAAiB,EAAE,CAAC;QACzB,MAAM,UAAU,GAAG,IAAI,CAAC,MAAM,CAAC;QAC/B,IAAI,CAAC,MAAM,GAAG,SAAS,CAAC;QAExB,MAAM,WAAW,GAAG,IAAI,CAAC,KAAK,CAAC,KAAK,CAAC,UAAU,EAAE,IAAI,CAAC,MAAM,CAAC,CAAC;QAC9D,IAAI,CAAC,QAAQ,CAAC,IAAI,CAAC,WAAW,EAAE,EAAE,OAAO,EAAE,IAAI,EAAE,UAAU,EAAE,OAAO,EAAE,CAAC,CAAC;QACxE,IAAI,CAAC,UAAU,GAAG,MAAM,CAAC;QAEzB,IAAI,CAAC,KAAK,GAAG,IAAI,CAAC,KAAK,CAAC,KAAK,CAAC,CAAC,EAAE,UAAU,CAAC,GAAG,IAAI,CAAC,KAAK,CAAC,KAAK,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC;QAC7E,IAAI,CAAC,MAAM,GAAG,UAAU,CAAC;IAAA,CACzB;IAEO,iBAAiB,GAAS;QACjC,IAAI,IAAI,CAAC,MAAM,IAAI,IAAI,CAAC,KAAK,CAAC,MAAM;YAAE,OAAO;QAE7C,sEAAsE;QACtE,MAAM,OAAO,GAAG,IAAI,CAAC,UAAU,KAAK,MAAM,CAAC;QAE3C,IAAI,CAAC,QAAQ,EAAE,CAAC;QAEhB,MAAM,SAAS,GAAG,IAAI,CAAC,MAAM,CAAC;QAC9B,IAAI,CAAC,gBAAgB,EAAE,CAAC;QACxB,MAAM,QAAQ,GAAG,IAAI,CAAC,MAAM,CAAC;QAC7B,IAAI,CAAC,MAAM,GAAG,SAAS,CAAC;QAExB,MAAM,WAAW,GAAG,IAAI,CAAC,KAAK,CAAC,KAAK,CAAC,IAAI,CAAC,MAAM,EAAE,QAAQ,CAAC,CAAC;QAC5D,IAAI,CAAC,QAAQ,CAAC,IAAI,CAAC,WAAW,EAAE,EAAE,OAAO,EAAE,KAAK,EAAE,UAAU,EAAE,OAAO,EAAE,CAAC,CAAC;QACzE,IAAI,CAAC,UAAU,GAAG,MAAM,CAAC;QAEzB,IAAI,CAAC,KAAK,GAAG,IAAI,CAAC,KAAK,CAAC,KAAK,CAAC,CAAC,EAAE,IAAI,CAAC,MAAM,CAAC,GAAG,IAAI,CAAC,KAAK,CAAC,KAAK,CAAC,QAAQ,CAAC,CAAC;IAAA,CAC3E;IAEO,IAAI,GAAS;QACpB,MAAM,IAAI,GAAG,IAAI,CAAC,QAAQ,CAAC,IAAI,EAAE,CAAC;QAClC,IAAI,CAAC,IAAI;YAAE,OAAO;QAElB,IAAI,CAAC,QAAQ,EAAE,CAAC;QAEhB,IAAI,CAAC,KAAK,GAAG,IAAI,CAAC,KAAK,CAAC,KAAK,CAAC,CAAC,EAAE,IAAI,CAAC,MAAM,CAAC,GAAG,IAAI,GAAG,IAAI,CAAC,KAAK,CAAC,KAAK,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC;QACrF,IAAI,CAAC,MAAM,IAAI,IAAI,CAAC,MAAM,CAAC;QAC3B,IAAI,CAAC,UAAU,GAAG,MAAM,CAAC;IAAA,CACzB;IAEO,OAAO,GAAS;QACvB,IAAI,IAAI,CAAC,UAAU,KAAK,MAAM,IAAI,IAAI,CAAC,QAAQ,CAAC,MAAM,IAAI,CAAC;YAAE,OAAO;QAEpE,IAAI,CAAC,QAAQ,EAAE,CAAC;QAEhB,MAAM,QAAQ,GAAG,IAAI,CAAC,QAAQ,CAAC,IAAI,EAAE,IAAI,EAAE,CAAC;QAC5C,IAAI,CAAC,KAAK,GAAG,IAAI,CAAC,KAAK,CAAC,KAAK,CAAC,CAAC,EAAE,IAAI,CAAC,MAAM,GAAG,QAAQ,CAAC,MAAM,CAAC,GAAG,IAAI,CAAC,KAAK,CAAC,KAAK,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC;QAChG,IAAI,CAAC,MAAM,IAAI,QAAQ,CAAC,MAAM,CAAC;QAE/B,IAAI,CAAC,QAAQ,CAAC,MAAM,EAAE,CAAC;QACvB,MAAM,IAAI,GAAG,IAAI,CAAC,QAAQ,CAAC,IAAI,EAAE,IAAI,EAAE,CAAC;QACxC,IAAI,CAAC,KAAK,GAAG,IAAI,CAAC,KAAK,CAAC,KAAK,CAAC,CAAC,EAAE,IAAI,CAAC,MAAM,CAAC,GAAG,IAAI,GAAG,IAAI,CAAC,KAAK,CAAC,KAAK,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC;QACrF,IAAI,CAAC,MAAM,IAAI,IAAI,CAAC,MAAM,CAAC;QAC3B,IAAI,CAAC,UAAU,GAAG,MAAM,CAAC;IAAA,CACzB;IAEO,QAAQ,GAAS;QACxB,IAAI,CAAC,SAAS,CAAC,IAAI,CAAC,EAAE,KAAK,EAAE,IAAI,CAAC,KAAK,EAAE,MAAM,EAAE,IAAI,CAAC,MAAM,EAAE,CAAC,CAAC;IAAA,CAChE;IAEO,IAAI,GAAS;QACpB,MAAM,QAAQ,GAAG,IAAI,CAAC,SAAS,CAAC,GAAG,EAAE,CAAC;QACtC,IAAI,CAAC,QAAQ;YAAE,OAAO;QACtB,IAAI,CAAC,KAAK,GAAG,QAAQ,CAAC,KAAK,CAAC;QAC5B,IAAI,CAAC,MAAM,GAAG,QAAQ,CAAC,MAAM,CAAC;QAC9B,IAAI,CAAC,UAAU,GAAG,IAAI,CAAC;IAAA,CACvB;IAEO,iBAAiB,GAAS;QACjC,IAAI,IAAI,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;YACvB,OAAO;QACR,CAAC;QAED,IAAI,CAAC,UAAU,GAAG,IAAI,CAAC;QACvB,MAAM,gBAAgB,GAAG,IAAI,CAAC,KAAK,CAAC,KAAK,CAAC,CAAC,EAAE,IAAI,CAAC,MAAM,CAAC,CAAC;QAC1D,MAAM,SAAS,GAAG,CAAC,GAAG,SAAS,CAAC,OAAO,CAAC,gBAAgB,CAAC,CAAC,CAAC;QAE3D,OAAO,SAAS,CAAC,MAAM,GAAG,CAAC,IAAI,gBAAgB,CAAC,SAAS,CAAC,SAAS,CAAC,MAAM,GAAG,CAAC,CAAC,EAAE,OAAO,IAAI,EAAE,CAAC,EAAE,CAAC;YACjG,IAAI,CAAC,MAAM,IAAI,SAAS,CAAC,GAAG,EAAE,EAAE,OAAO,CAAC,MAAM,IAAI,CAAC,CAAC;QACrD,CAAC;QAED,IAAI,SAAS,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;YAC1B,MAAM,YAAY,GAAG,SAAS,CAAC,SAAS,CAAC,MAAM,GAAG,CAAC,CAAC,EAAE,OAAO,IAAI,EAAE,CAAC;YACpE,IAAI,iBAAiB,CAAC,YAAY,CAAC,EAAE,CAAC;gBACrC,OAAO,SAAS,CAAC,MAAM,GAAG,CAAC,IAAI,iBAAiB,CAAC,SAAS,CAAC,SAAS,CAAC,MAAM,GAAG,CAAC,CAAC,EAAE,OAAO,IAAI,EAAE,CAAC,EAAE,CAAC;oBAClG,IAAI,CAAC,MAAM,IAAI,SAAS,CAAC,GAAG,EAAE,EAAE,OAAO,CAAC,MAAM,IAAI,CAAC,CAAC;gBACrD,CAAC;YACF,CAAC;iBAAM,CAAC;gBACP,OACC,SAAS,CAAC,MAAM,GAAG,CAAC;oBACpB,CAAC,gBAAgB,CAAC,SAAS,CAAC,SAAS,CAAC,MAAM,GAAG,CAAC,CAAC,EAAE,OAAO,IAAI,EAAE,CAAC;oBACjE,CAAC,iBAAiB,CAAC,SAAS,CAAC,SAAS,CAAC,MAAM,GAAG,CAAC,CAAC,EAAE,OAAO,IAAI,EAAE,CAAC,EACjE,CAAC;oBACF,IAAI,CAAC,MAAM,IAAI,SAAS,CAAC,GAAG,EAAE,EAAE,OAAO,CAAC,MAAM,IAAI,CAAC,CAAC;gBACrD,CAAC;YACF,CAAC;QACF,CAAC;IAAA,CACD;IAEO,gBAAgB,GAAS;QAChC,IAAI,IAAI,CAAC,MAAM,IAAI,IAAI,CAAC,KAAK,CAAC,MAAM,EAAE,CAAC;YACtC,OAAO;QACR,CAAC;QAED,IAAI,CAAC,UAAU,GAAG,IAAI,CAAC;QACvB,MAAM,eAAe,GAAG,IAAI,CAAC,KAAK,CAAC,KAAK,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC;QACtD,MAAM,QAAQ,GAAG,SAAS,CAAC,OAAO,CAAC,eAAe,CAAC,CAAC;QACpD,MAAM,QAAQ,GAAG,QAAQ,CAAC,MAAM,CAAC,QAAQ,CAAC,EAAE,CAAC;QAC7C,IAAI,IAAI,GAAG,QAAQ,CAAC,IAAI,EAAE,CAAC;QAE3B,OAAO,CAAC,IAAI,CAAC,IAAI,IAAI,gBAAgB,CAAC,IAAI,CAAC,KAAK,CAAC,OAAO,CAAC,EAAE,CAAC;YAC3D,IAAI,CAAC,MAAM,IAAI,IAAI,CAAC,KAAK,CAAC,OAAO,CAAC,MAAM,CAAC;YACzC,IAAI,GAAG,QAAQ,CAAC,IAAI,EAAE,CAAC;QACxB,CAAC;QAED,IAAI,CAAC,IAAI,CAAC,IAAI,EAAE,CAAC;YAChB,MAAM,aAAa,GAAG,IAAI,CAAC,KAAK,CAAC,OAAO,CAAC;YACzC,IAAI,iBAAiB,CAAC,aAAa,CAAC,EAAE,CAAC;gBACtC,OAAO,CAAC,IAAI,CAAC,IAAI,IAAI,iBAAiB,CAAC,IAAI,CAAC,KAAK,CAAC,OAAO,CAAC,EAAE,CAAC;oBAC5D,IAAI,CAAC,MAAM,IAAI,IAAI,CAAC,KAAK,CAAC,OAAO,CAAC,MAAM,CAAC;oBACzC,IAAI,GAAG,QAAQ,CAAC,IAAI,EAAE,CAAC;gBACxB,CAAC;YACF,CAAC;iBAAM,CAAC;gBACP,OAAO,CAAC,IAAI,CAAC,IAAI,IAAI,CAAC,gBAAgB,CAAC,IAAI,CAAC,KAAK,CAAC,OAAO,CAAC,IAAI,CAAC,iBAAiB,CAAC,IAAI,CAAC,KAAK,CAAC,OAAO,CAAC,EAAE,CAAC;oBACtG,IAAI,CAAC,MAAM,IAAI,IAAI,CAAC,KAAK,CAAC,OAAO,CAAC,MAAM,CAAC;oBACzC,IAAI,GAAG,QAAQ,CAAC,IAAI,EAAE,CAAC;gBACxB,CAAC;YACF,CAAC;QACF,CAAC;IAAA,CACD;IAEO,WAAW,CAAC,UAAkB,EAAQ;QAC7C,IAAI,CAAC,UAAU,GAAG,IAAI,CAAC;QACvB,IAAI,CAAC,QAAQ,EAAE,CAAC;QAEhB,MAAM,SAAS,GAAG,UAAU,CAAC,OAAO,CAAC,OAAO,EAAE,EAAE,CAAC,CAAC,OAAO,CAAC,KAAK,EAAE,EAAE,CAAC,CAAC,OAAO,CAAC,KAAK,EAAE,EAAE,CAAC,CAAC,OAAO,CAAC,KAAK,EAAE,MAAM,CAAC,CAAC;QAE/G,IAAI,CAAC,KAAK,GAAG,IAAI,CAAC,KAAK,CAAC,KAAK,CAAC,CAAC,EAAE,IAAI,CAAC,MAAM,CAAC,GAAG,SAAS,GAAG,IAAI,CAAC,KAAK,CAAC,KAAK,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC;QAC1F,IAAI,CAAC,MAAM,IAAI,SAAS,CAAC,MAAM,CAAC;IAAA,CAChC;IAED,UAAU,GAAS,EAAC,CAAC;IAErB,MAAM,CAAC,KAAa,EAAY;QAC/B,MAAM,MAAM,GAAG,IAAI,CAAC;QACpB,MAAM,cAAc,GAAG,KAAK,GAAG,MAAM,CAAC,MAAM,CAAC;QAE7C,IAAI,cAAc,IAAI,CAAC,EAAE,CAAC;YACzB,OAAO,CAAC,MAAM,CAAC,CAAC;QACjB,CAAC;QAED,IAAI,WAAW,GAAG,EAAE,CAAC;QACrB,IAAI,aAAa,GAAG,IAAI,CAAC,MAAM,CAAC;QAChC,MAAM,UAAU,GAAG,YAAY,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;QAE5C,IAAI,UAAU,GAAG,cAAc,EAAE,CAAC;YACjC,WAAW,GAAG,IAAI,CAAC,KAAK,CAAC;QAC1B,CAAC;aAAM,CAAC;YACP,MAAM,WAAW,GAAG,IAAI,CAAC,MAAM,KAAK,IAAI,CAAC,KAAK,CAAC,MAAM,CAAC,CAAC,CAAC,cAAc,GAAG,CAAC,CAAC,CAAC,CAAC,cAAc,CAAC;YAC5F,MAAM,SAAS,GAAG,YAAY,CAAC,IAAI,CAAC,KAAK,CAAC,KAAK,CAAC,CAAC,EAAE,IAAI,CAAC,MAAM,CAAC,CAAC,CAAC;YAEjE,IAAI,WAAW,GAAG,CAAC,EAAE,CAAC;gBACrB,MAAM,SAAS,GAAG,IAAI,CAAC,KAAK,CAAC,WAAW,GAAG,CAAC,CAAC,CAAC;gBAC9C,IAAI,QAAQ,GAAG,CAAC,CAAC;gBAEjB,IAAI,SAAS,GAAG,SAAS,EAAE,CAAC;oBAC3B,QAAQ,GAAG,CAAC,CAAC;gBACd,CAAC;qBAAM,IAAI,SAAS,GAAG,UAAU,GAAG,SAAS,EAAE,CAAC;oBAC/C,QAAQ,GAAG,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE,UAAU,GAAG,WAAW,CAAC,CAAC;gBAClD,CAAC;qBAAM,CAAC;oBACP,QAAQ,GAAG,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE,SAAS,GAAG,SAAS,CAAC,CAAC;gBAC/C,CAAC;gBAED,WAAW,GAAG,aAAa,CAAC,IAAI,CAAC,KAAK,EAAE,QAAQ,EAAE,WAAW,EAAE,IAAI,CAAC,CAAC;gBACrE,MAAM,YAAY,GAAG,aAAa,CAAC,IAAI,CAAC,KAAK,EAAE,QAAQ,EAAE,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE,SAAS,GAAG,QAAQ,CAAC,EAAE,IAAI,CAAC,CAAC;gBAClG,aAAa,GAAG,YAAY,CAAC,MAAM,CAAC;YACrC,CAAC;iBAAM,CAAC;gBACP,WAAW,GAAG,EAAE,CAAC;gBACjB,aAAa,GAAG,CAAC,CAAC;YACnB,CAAC;QACF,CAAC;QAED,MAAM,SAAS,GAAG,CAAC,GAAG,SAAS,CAAC,OAAO,CAAC,WAAW,CAAC,KAAK,CAAC,aAAa,CAAC,CAAC,CAAC,CAAC;QAC3E,MAAM,cAAc,GAAG,SAAS,CAAC,CAAC,CAAC,CAAC;QAEpC,MAAM,YAAY,GAAG,WAAW,CAAC,KAAK,CAAC,CAAC,EAAE,aAAa,CAAC,CAAC;QACzD,MAAM,QAAQ,GAAG,cAAc,EAAE,OAAO,IAAI,GAAG,CAAC,CAAC,0CAA0C;QAC3F,MAAM,WAAW,GAAG,WAAW,CAAC,KAAK,CAAC,aAAa,GAAG,QAAQ,CAAC,MAAM,CAAC,CAAC;QAEvE,sFAAsF;QACtF,MAAM,MAAM,GAAG,IAAI,CAAC,OAAO,CAAC,CAAC,CAAC,aAAa,CAAC,CAAC,CAAC,EAAE,CAAC;QAEjD,MAAM,UAAU,GAAG,UAAU,QAAQ,UAAU,CAAC,CAAC,2CAA2C;QAC5F,MAAM,cAAc,GAAG,YAAY,GAAG,MAAM,GAAG,UAAU,GAAG,WAAW,CAAC;QAExE,MAAM,YAAY,GAAG,YAAY,CAAC,cAAc,CAAC,CAAC;QAClD,MAAM,OAAO,GAAG,GAAG,CAAC,MAAM,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE,cAAc,GAAG,YAAY,CAAC,CAAC,CAAC;QACvE,MAAM,IAAI,GAAG,MAAM,GAAG,cAAc,GAAG,OAAO,CAAC;QAE/C,OAAO,CAAC,IAAI,CAAC,CAAC;IAAA,CACd;CACD","sourcesContent":["import { getKeybindings } from \"../keybindings.js\";\nimport { decodeKittyPrintable } from \"../keys.js\";\nimport { KillRing } from \"../kill-ring.js\";\nimport { type Component, CURSOR_MARKER, type Focusable } from \"../tui.js\";\nimport { UndoStack } from \"../undo-stack.js\";\nimport { getSegmenter, isPunctuationChar, isWhitespaceChar, sliceByColumn, visibleWidth } from \"../utils.js\";\n\nconst segmenter = getSegmenter();\n\ninterface InputState {\n\tvalue: string;\n\tcursor: number;\n}\n\n/**\n * Input component - single-line text input with horizontal scrolling\n */\nexport class Input implements Component, Focusable {\n\tprivate value: string = \"\";\n\tprivate cursor: number = 0; // Cursor position in the value\n\tpublic onSubmit?: (value: string) => void;\n\tpublic onEscape?: () => void;\n\n\tfocused: boolean = false;\n\n\tprivate pasteBuffer: string = \"\";\n\tprivate isInPaste: boolean = false;\n\n\tprivate killRing = new KillRing();\n\tprivate lastAction: \"kill\" | \"yank\" | \"type-word\" | null = null;\n\n\tprivate undoStack = new UndoStack<InputState>();\n\n\tgetValue(): string {\n\t\treturn this.value;\n\t}\n\n\tgetCursor(): number {\n\t\treturn this.cursor;\n\t}\n\n\tsetValue(value: string): void {\n\t\tthis.value = value;\n\t\tthis.cursor = Math.min(this.cursor, value.length);\n\t}\n\n\thandleInput(data: string): void {\n\t\tif (data.includes(\"\\x1b[200~\")) {\n\t\t\tthis.isInPaste = true;\n\t\t\tthis.pasteBuffer = \"\";\n\t\t\tdata = data.replace(\"\\x1b[200~\", \"\");\n\t\t}\n\n\t\tif (this.isInPaste) {\n\t\t\tthis.pasteBuffer += data;\n\n\t\t\tconst endIndex = this.pasteBuffer.indexOf(\"\\x1b[201~\");\n\t\t\tif (endIndex !== -1) {\n\t\t\t\tconst pasteContent = this.pasteBuffer.substring(0, endIndex);\n\n\t\t\t\tthis.handlePaste(pasteContent);\n\n\t\t\t\tthis.isInPaste = false;\n\n\t\t\t\tconst remaining = this.pasteBuffer.substring(endIndex + 6); // 6 = length of \\x1b[201~\n\t\t\t\tthis.pasteBuffer = \"\";\n\t\t\t\tif (remaining) {\n\t\t\t\t\tthis.handleInput(remaining);\n\t\t\t\t}\n\t\t\t}\n\t\t\treturn;\n\t\t}\n\n\t\tconst kb = getKeybindings();\n\n\t\tif (kb.matches(data, \"tui.select.cancel\")) {\n\t\t\tif (this.onEscape) this.onEscape();\n\t\t\treturn;\n\t\t}\n\n\t\tif (kb.matches(data, \"tui.editor.undo\")) {\n\t\t\tthis.undo();\n\t\t\treturn;\n\t\t}\n\n\t\tif (kb.matches(data, \"tui.input.submit\") || data === \"\\n\") {\n\t\t\tif (this.onSubmit) this.onSubmit(this.value);\n\t\t\treturn;\n\t\t}\n\n\t\tif (kb.matches(data, \"tui.editor.deleteCharBackward\")) {\n\t\t\tthis.handleBackspace();\n\t\t\treturn;\n\t\t}\n\n\t\tif (kb.matches(data, \"tui.editor.deleteCharForward\")) {\n\t\t\tthis.handleForwardDelete();\n\t\t\treturn;\n\t\t}\n\n\t\tif (kb.matches(data, \"tui.editor.deleteWordBackward\")) {\n\t\t\tthis.deleteWordBackwards();\n\t\t\treturn;\n\t\t}\n\n\t\tif (kb.matches(data, \"tui.editor.deleteWordForward\")) {\n\t\t\tthis.deleteWordForward();\n\t\t\treturn;\n\t\t}\n\n\t\tif (kb.matches(data, \"tui.editor.deleteToLineStart\")) {\n\t\t\tthis.deleteToLineStart();\n\t\t\treturn;\n\t\t}\n\n\t\tif (kb.matches(data, \"tui.editor.deleteToLineEnd\")) {\n\t\t\tthis.deleteToLineEnd();\n\t\t\treturn;\n\t\t}\n\n\t\tif (kb.matches(data, \"tui.editor.yank\")) {\n\t\t\tthis.yank();\n\t\t\treturn;\n\t\t}\n\t\tif (kb.matches(data, \"tui.editor.yankPop\")) {\n\t\t\tthis.yankPop();\n\t\t\treturn;\n\t\t}\n\n\t\tif (kb.matches(data, \"tui.editor.cursorLeft\")) {\n\t\t\tthis.lastAction = null;\n\t\t\tif (this.cursor > 0) {\n\t\t\t\tconst beforeCursor = this.value.slice(0, this.cursor);\n\t\t\t\tconst graphemes = [...segmenter.segment(beforeCursor)];\n\t\t\t\tconst lastGrapheme = graphemes[graphemes.length - 1];\n\t\t\t\tthis.cursor -= lastGrapheme ? lastGrapheme.segment.length : 1;\n\t\t\t}\n\t\t\treturn;\n\t\t}\n\n\t\tif (kb.matches(data, \"tui.editor.cursorRight\")) {\n\t\t\tthis.lastAction = null;\n\t\t\tif (this.cursor < this.value.length) {\n\t\t\t\tconst afterCursor = this.value.slice(this.cursor);\n\t\t\t\tconst graphemes = [...segmenter.segment(afterCursor)];\n\t\t\t\tconst firstGrapheme = graphemes[0];\n\t\t\t\tthis.cursor += firstGrapheme ? firstGrapheme.segment.length : 1;\n\t\t\t}\n\t\t\treturn;\n\t\t}\n\n\t\tif (kb.matches(data, \"tui.editor.cursorLineStart\")) {\n\t\t\tthis.lastAction = null;\n\t\t\tthis.cursor = 0;\n\t\t\treturn;\n\t\t}\n\n\t\tif (kb.matches(data, \"tui.editor.cursorLineEnd\")) {\n\t\t\tthis.lastAction = null;\n\t\t\tthis.cursor = this.value.length;\n\t\t\treturn;\n\t\t}\n\n\t\tif (kb.matches(data, \"tui.editor.cursorWordLeft\")) {\n\t\t\tthis.moveWordBackwards();\n\t\t\treturn;\n\t\t}\n\n\t\tif (kb.matches(data, \"tui.editor.cursorWordRight\")) {\n\t\t\tthis.moveWordForwards();\n\t\t\treturn;\n\t\t}\n\n\t\t// Kitty CSI-u printable character (e.g. \\x1b[97u for 'a').\n\t\t// Terminals with Kitty protocol flag 1 (disambiguate) send CSI-u for all keys,\n\t\t// including plain printable characters. Decode before the control-char check\n\t\t// since CSI-u sequences contain \\x1b which would be rejected.\n\t\tconst kittyPrintable = decodeKittyPrintable(data);\n\t\tif (kittyPrintable !== undefined) {\n\t\t\tthis.insertCharacter(kittyPrintable);\n\t\t\treturn;\n\t\t}\n\n\t\t// Regular character input - accept printable characters including Unicode,\n\t\t// but reject control characters (C0: 0x00-0x1F, DEL: 0x7F, C1: 0x80-0x9F)\n\t\tconst hasControlChars = [...data].some((ch) => {\n\t\t\tconst code = ch.charCodeAt(0);\n\t\t\treturn code < 32 || code === 0x7f || (code >= 0x80 && code <= 0x9f);\n\t\t});\n\t\tif (!hasControlChars) {\n\t\t\tthis.insertCharacter(data);\n\t\t}\n\t}\n\n\tprivate insertCharacter(char: string): void {\n\t\tif (isWhitespaceChar(char) || this.lastAction !== \"type-word\") {\n\t\t\tthis.pushUndo();\n\t\t}\n\t\tthis.lastAction = \"type-word\";\n\n\t\tthis.value = this.value.slice(0, this.cursor) + char + this.value.slice(this.cursor);\n\t\tthis.cursor += char.length;\n\t}\n\n\tprivate handleBackspace(): void {\n\t\tthis.lastAction = null;\n\t\tif (this.cursor > 0) {\n\t\t\tthis.pushUndo();\n\t\t\tconst beforeCursor = this.value.slice(0, this.cursor);\n\t\t\tconst graphemes = [...segmenter.segment(beforeCursor)];\n\t\t\tconst lastGrapheme = graphemes[graphemes.length - 1];\n\t\t\tconst graphemeLength = lastGrapheme ? lastGrapheme.segment.length : 1;\n\t\t\tthis.value = this.value.slice(0, this.cursor - graphemeLength) + this.value.slice(this.cursor);\n\t\t\tthis.cursor -= graphemeLength;\n\t\t}\n\t}\n\n\tprivate handleForwardDelete(): void {\n\t\tthis.lastAction = null;\n\t\tif (this.cursor < this.value.length) {\n\t\t\tthis.pushUndo();\n\t\t\tconst afterCursor = this.value.slice(this.cursor);\n\t\t\tconst graphemes = [...segmenter.segment(afterCursor)];\n\t\t\tconst firstGrapheme = graphemes[0];\n\t\t\tconst graphemeLength = firstGrapheme ? firstGrapheme.segment.length : 1;\n\t\t\tthis.value = this.value.slice(0, this.cursor) + this.value.slice(this.cursor + graphemeLength);\n\t\t}\n\t}\n\n\tprivate deleteToLineStart(): void {\n\t\tif (this.cursor === 0) return;\n\t\tthis.pushUndo();\n\t\tconst deletedText = this.value.slice(0, this.cursor);\n\t\tthis.killRing.push(deletedText, { prepend: true, accumulate: this.lastAction === \"kill\" });\n\t\tthis.lastAction = \"kill\";\n\t\tthis.value = this.value.slice(this.cursor);\n\t\tthis.cursor = 0;\n\t}\n\n\tprivate deleteToLineEnd(): void {\n\t\tif (this.cursor >= this.value.length) return;\n\t\tthis.pushUndo();\n\t\tconst deletedText = this.value.slice(this.cursor);\n\t\tthis.killRing.push(deletedText, { prepend: false, accumulate: this.lastAction === \"kill\" });\n\t\tthis.lastAction = \"kill\";\n\t\tthis.value = this.value.slice(0, this.cursor);\n\t}\n\n\tprivate deleteWordBackwards(): void {\n\t\tif (this.cursor === 0) return;\n\n\t\t// Save lastAction before cursor movement (moveWordBackwards resets it)\n\t\tconst wasKill = this.lastAction === \"kill\";\n\n\t\tthis.pushUndo();\n\n\t\tconst oldCursor = this.cursor;\n\t\tthis.moveWordBackwards();\n\t\tconst deleteFrom = this.cursor;\n\t\tthis.cursor = oldCursor;\n\n\t\tconst deletedText = this.value.slice(deleteFrom, this.cursor);\n\t\tthis.killRing.push(deletedText, { prepend: true, accumulate: wasKill });\n\t\tthis.lastAction = \"kill\";\n\n\t\tthis.value = this.value.slice(0, deleteFrom) + this.value.slice(this.cursor);\n\t\tthis.cursor = deleteFrom;\n\t}\n\n\tprivate deleteWordForward(): void {\n\t\tif (this.cursor >= this.value.length) return;\n\n\t\t// Save lastAction before cursor movement (moveWordForwards resets it)\n\t\tconst wasKill = this.lastAction === \"kill\";\n\n\t\tthis.pushUndo();\n\n\t\tconst oldCursor = this.cursor;\n\t\tthis.moveWordForwards();\n\t\tconst deleteTo = this.cursor;\n\t\tthis.cursor = oldCursor;\n\n\t\tconst deletedText = this.value.slice(this.cursor, deleteTo);\n\t\tthis.killRing.push(deletedText, { prepend: false, accumulate: wasKill });\n\t\tthis.lastAction = \"kill\";\n\n\t\tthis.value = this.value.slice(0, this.cursor) + this.value.slice(deleteTo);\n\t}\n\n\tprivate yank(): void {\n\t\tconst text = this.killRing.peek();\n\t\tif (!text) return;\n\n\t\tthis.pushUndo();\n\n\t\tthis.value = this.value.slice(0, this.cursor) + text + this.value.slice(this.cursor);\n\t\tthis.cursor += text.length;\n\t\tthis.lastAction = \"yank\";\n\t}\n\n\tprivate yankPop(): void {\n\t\tif (this.lastAction !== \"yank\" || this.killRing.length <= 1) return;\n\n\t\tthis.pushUndo();\n\n\t\tconst prevText = this.killRing.peek() || \"\";\n\t\tthis.value = this.value.slice(0, this.cursor - prevText.length) + this.value.slice(this.cursor);\n\t\tthis.cursor -= prevText.length;\n\n\t\tthis.killRing.rotate();\n\t\tconst text = this.killRing.peek() || \"\";\n\t\tthis.value = this.value.slice(0, this.cursor) + text + this.value.slice(this.cursor);\n\t\tthis.cursor += text.length;\n\t\tthis.lastAction = \"yank\";\n\t}\n\n\tprivate pushUndo(): void {\n\t\tthis.undoStack.push({ value: this.value, cursor: this.cursor });\n\t}\n\n\tprivate undo(): void {\n\t\tconst snapshot = this.undoStack.pop();\n\t\tif (!snapshot) return;\n\t\tthis.value = snapshot.value;\n\t\tthis.cursor = snapshot.cursor;\n\t\tthis.lastAction = null;\n\t}\n\n\tprivate moveWordBackwards(): void {\n\t\tif (this.cursor === 0) {\n\t\t\treturn;\n\t\t}\n\n\t\tthis.lastAction = null;\n\t\tconst textBeforeCursor = this.value.slice(0, this.cursor);\n\t\tconst graphemes = [...segmenter.segment(textBeforeCursor)];\n\n\t\twhile (graphemes.length > 0 && isWhitespaceChar(graphemes[graphemes.length - 1]?.segment || \"\")) {\n\t\t\tthis.cursor -= graphemes.pop()?.segment.length || 0;\n\t\t}\n\n\t\tif (graphemes.length > 0) {\n\t\t\tconst lastGrapheme = graphemes[graphemes.length - 1]?.segment || \"\";\n\t\t\tif (isPunctuationChar(lastGrapheme)) {\n\t\t\t\twhile (graphemes.length > 0 && isPunctuationChar(graphemes[graphemes.length - 1]?.segment || \"\")) {\n\t\t\t\t\tthis.cursor -= graphemes.pop()?.segment.length || 0;\n\t\t\t\t}\n\t\t\t} else {\n\t\t\t\twhile (\n\t\t\t\t\tgraphemes.length > 0 &&\n\t\t\t\t\t!isWhitespaceChar(graphemes[graphemes.length - 1]?.segment || \"\") &&\n\t\t\t\t\t!isPunctuationChar(graphemes[graphemes.length - 1]?.segment || \"\")\n\t\t\t\t) {\n\t\t\t\t\tthis.cursor -= graphemes.pop()?.segment.length || 0;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\n\tprivate moveWordForwards(): void {\n\t\tif (this.cursor >= this.value.length) {\n\t\t\treturn;\n\t\t}\n\n\t\tthis.lastAction = null;\n\t\tconst textAfterCursor = this.value.slice(this.cursor);\n\t\tconst segments = segmenter.segment(textAfterCursor);\n\t\tconst iterator = segments[Symbol.iterator]();\n\t\tlet next = iterator.next();\n\n\t\twhile (!next.done && isWhitespaceChar(next.value.segment)) {\n\t\t\tthis.cursor += next.value.segment.length;\n\t\t\tnext = iterator.next();\n\t\t}\n\n\t\tif (!next.done) {\n\t\t\tconst firstGrapheme = next.value.segment;\n\t\t\tif (isPunctuationChar(firstGrapheme)) {\n\t\t\t\twhile (!next.done && isPunctuationChar(next.value.segment)) {\n\t\t\t\t\tthis.cursor += next.value.segment.length;\n\t\t\t\t\tnext = iterator.next();\n\t\t\t\t}\n\t\t\t} else {\n\t\t\t\twhile (!next.done && !isWhitespaceChar(next.value.segment) && !isPunctuationChar(next.value.segment)) {\n\t\t\t\t\tthis.cursor += next.value.segment.length;\n\t\t\t\t\tnext = iterator.next();\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\n\tprivate handlePaste(pastedText: string): void {\n\t\tthis.lastAction = null;\n\t\tthis.pushUndo();\n\n\t\tconst cleanText = pastedText.replace(/\\r\\n/g, \"\").replace(/\\r/g, \"\").replace(/\\n/g, \"\").replace(/\\t/g, \" \");\n\n\t\tthis.value = this.value.slice(0, this.cursor) + cleanText + this.value.slice(this.cursor);\n\t\tthis.cursor += cleanText.length;\n\t}\n\n\tinvalidate(): void {}\n\n\trender(width: number): string[] {\n\t\tconst prompt = \"> \";\n\t\tconst availableWidth = width - prompt.length;\n\n\t\tif (availableWidth <= 0) {\n\t\t\treturn [prompt];\n\t\t}\n\n\t\tlet visibleText = \"\";\n\t\tlet cursorDisplay = this.cursor;\n\t\tconst totalWidth = visibleWidth(this.value);\n\n\t\tif (totalWidth < availableWidth) {\n\t\t\tvisibleText = this.value;\n\t\t} else {\n\t\t\tconst scrollWidth = this.cursor === this.value.length ? availableWidth - 1 : availableWidth;\n\t\t\tconst cursorCol = visibleWidth(this.value.slice(0, this.cursor));\n\n\t\t\tif (scrollWidth > 0) {\n\t\t\t\tconst halfWidth = Math.floor(scrollWidth / 2);\n\t\t\t\tlet startCol = 0;\n\n\t\t\t\tif (cursorCol < halfWidth) {\n\t\t\t\t\tstartCol = 0;\n\t\t\t\t} else if (cursorCol > totalWidth - halfWidth) {\n\t\t\t\t\tstartCol = Math.max(0, totalWidth - scrollWidth);\n\t\t\t\t} else {\n\t\t\t\t\tstartCol = Math.max(0, cursorCol - halfWidth);\n\t\t\t\t}\n\n\t\t\t\tvisibleText = sliceByColumn(this.value, startCol, scrollWidth, true);\n\t\t\t\tconst beforeCursor = sliceByColumn(this.value, startCol, Math.max(0, cursorCol - startCol), true);\n\t\t\t\tcursorDisplay = beforeCursor.length;\n\t\t\t} else {\n\t\t\t\tvisibleText = \"\";\n\t\t\t\tcursorDisplay = 0;\n\t\t\t}\n\t\t}\n\n\t\tconst graphemes = [...segmenter.segment(visibleText.slice(cursorDisplay))];\n\t\tconst cursorGrapheme = graphemes[0];\n\n\t\tconst beforeCursor = visibleText.slice(0, cursorDisplay);\n\t\tconst atCursor = cursorGrapheme?.segment ?? \" \"; // Character at cursor, or space if at end\n\t\tconst afterCursor = visibleText.slice(cursorDisplay + atCursor.length);\n\n\t\t// Hardware cursor marker (zero-width, emitted before fake cursor for IME positioning)\n\t\tconst marker = this.focused ? CURSOR_MARKER : \"\";\n\n\t\tconst cursorChar = `\\x1b[7m${atCursor}\\x1b[27m`; // ESC[7m = reverse video, ESC[27m = normal\n\t\tconst textWithCursor = beforeCursor + marker + cursorChar + afterCursor;\n\n\t\tconst visualLength = visibleWidth(textWithCursor);\n\t\tconst padding = \" \".repeat(Math.max(0, availableWidth - visualLength));\n\t\tconst line = prompt + textWithCursor + padding;\n\n\t\treturn [line];\n\t}\n}\n"]}
1
+ {"version":3,"file":"input.js","sourceRoot":"","sources":["../../src/components/input.ts"],"names":[],"mappings":"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","sourcesContent":["import { getKeybindings } from \"../keybindings.js\";\nimport { decodeKittyPrintable } from \"../keys.js\";\nimport { KillRing } from \"../kill-ring.js\";\nimport { type Component, CURSOR_MARKER, type Focusable } from \"../tui.js\";\nimport { UndoStack } from \"../undo-stack.js\";\nimport { getSegmenter, isPunctuationChar, isWhitespaceChar, sliceByColumn, visibleWidth } from \"../utils.js\";\n\nconst segmenter = getSegmenter();\n\ninterface InputState {\n\tvalue: string;\n\tcursor: number;\n}\n\n/**\n * Input component - single-line text input with horizontal scrolling\n */\nexport class Input implements Component, Focusable {\n\tprivate value: string = \"\";\n\tprivate cursor: number = 0; // Cursor position in the value\n\tprivate masked = false;\n\tpublic onSubmit?: (value: string) => void;\n\tpublic onEscape?: () => void;\n\n\tfocused: boolean = false;\n\n\tprivate pasteBuffer: string = \"\";\n\tprivate isInPaste: boolean = false;\n\n\tprivate killRing = new KillRing();\n\tprivate lastAction: \"kill\" | \"yank\" | \"type-word\" | null = null;\n\n\tprivate undoStack = new UndoStack<InputState>();\n\n\tsetMasked(masked: boolean): void {\n\t\tthis.masked = masked;\n\t}\n\n\tgetValue(): string {\n\t\treturn this.value;\n\t}\n\n\tgetCursor(): number {\n\t\treturn this.cursor;\n\t}\n\n\tsetValue(value: string): void {\n\t\tthis.value = value;\n\t\tthis.cursor = Math.min(this.cursor, value.length);\n\t}\n\n\thandleInput(data: string): void {\n\t\tif (data.includes(\"\\x1b[200~\")) {\n\t\t\tthis.isInPaste = true;\n\t\t\tthis.pasteBuffer = \"\";\n\t\t\tdata = data.replace(\"\\x1b[200~\", \"\");\n\t\t}\n\n\t\tif (this.isInPaste) {\n\t\t\tthis.pasteBuffer += data;\n\n\t\t\tconst endIndex = this.pasteBuffer.indexOf(\"\\x1b[201~\");\n\t\t\tif (endIndex !== -1) {\n\t\t\t\tconst pasteContent = this.pasteBuffer.substring(0, endIndex);\n\n\t\t\t\tthis.handlePaste(pasteContent);\n\n\t\t\t\tthis.isInPaste = false;\n\n\t\t\t\tconst remaining = this.pasteBuffer.substring(endIndex + 6); // 6 = length of \\x1b[201~\n\t\t\t\tthis.pasteBuffer = \"\";\n\t\t\t\tif (remaining) {\n\t\t\t\t\tthis.handleInput(remaining);\n\t\t\t\t}\n\t\t\t}\n\t\t\treturn;\n\t\t}\n\n\t\tconst kb = getKeybindings();\n\n\t\tif (kb.matches(data, \"tui.select.cancel\")) {\n\t\t\tif (this.onEscape) this.onEscape();\n\t\t\treturn;\n\t\t}\n\n\t\tif (kb.matches(data, \"tui.editor.undo\")) {\n\t\t\tthis.undo();\n\t\t\treturn;\n\t\t}\n\n\t\tif (kb.matches(data, \"tui.input.submit\") || data === \"\\n\") {\n\t\t\tif (this.onSubmit) this.onSubmit(this.value);\n\t\t\treturn;\n\t\t}\n\n\t\tif (kb.matches(data, \"tui.editor.deleteCharBackward\")) {\n\t\t\tthis.handleBackspace();\n\t\t\treturn;\n\t\t}\n\n\t\tif (kb.matches(data, \"tui.editor.deleteCharForward\")) {\n\t\t\tthis.handleForwardDelete();\n\t\t\treturn;\n\t\t}\n\n\t\tif (kb.matches(data, \"tui.editor.deleteWordBackward\")) {\n\t\t\tthis.deleteWordBackwards();\n\t\t\treturn;\n\t\t}\n\n\t\tif (kb.matches(data, \"tui.editor.deleteWordForward\")) {\n\t\t\tthis.deleteWordForward();\n\t\t\treturn;\n\t\t}\n\n\t\tif (kb.matches(data, \"tui.editor.deleteToLineStart\")) {\n\t\t\tthis.deleteToLineStart();\n\t\t\treturn;\n\t\t}\n\n\t\tif (kb.matches(data, \"tui.editor.deleteToLineEnd\")) {\n\t\t\tthis.deleteToLineEnd();\n\t\t\treturn;\n\t\t}\n\n\t\tif (kb.matches(data, \"tui.editor.yank\")) {\n\t\t\tthis.yank();\n\t\t\treturn;\n\t\t}\n\t\tif (kb.matches(data, \"tui.editor.yankPop\")) {\n\t\t\tthis.yankPop();\n\t\t\treturn;\n\t\t}\n\n\t\tif (kb.matches(data, \"tui.editor.cursorLeft\")) {\n\t\t\tthis.lastAction = null;\n\t\t\tif (this.cursor > 0) {\n\t\t\t\tconst beforeCursor = this.value.slice(0, this.cursor);\n\t\t\t\tconst graphemes = [...segmenter.segment(beforeCursor)];\n\t\t\t\tconst lastGrapheme = graphemes[graphemes.length - 1];\n\t\t\t\tthis.cursor -= lastGrapheme ? lastGrapheme.segment.length : 1;\n\t\t\t}\n\t\t\treturn;\n\t\t}\n\n\t\tif (kb.matches(data, \"tui.editor.cursorRight\")) {\n\t\t\tthis.lastAction = null;\n\t\t\tif (this.cursor < this.value.length) {\n\t\t\t\tconst afterCursor = this.value.slice(this.cursor);\n\t\t\t\tconst graphemes = [...segmenter.segment(afterCursor)];\n\t\t\t\tconst firstGrapheme = graphemes[0];\n\t\t\t\tthis.cursor += firstGrapheme ? firstGrapheme.segment.length : 1;\n\t\t\t}\n\t\t\treturn;\n\t\t}\n\n\t\tif (kb.matches(data, \"tui.editor.cursorLineStart\")) {\n\t\t\tthis.lastAction = null;\n\t\t\tthis.cursor = 0;\n\t\t\treturn;\n\t\t}\n\n\t\tif (kb.matches(data, \"tui.editor.cursorLineEnd\")) {\n\t\t\tthis.lastAction = null;\n\t\t\tthis.cursor = this.value.length;\n\t\t\treturn;\n\t\t}\n\n\t\tif (kb.matches(data, \"tui.editor.cursorWordLeft\")) {\n\t\t\tthis.moveWordBackwards();\n\t\t\treturn;\n\t\t}\n\n\t\tif (kb.matches(data, \"tui.editor.cursorWordRight\")) {\n\t\t\tthis.moveWordForwards();\n\t\t\treturn;\n\t\t}\n\n\t\t// Kitty CSI-u printable character (e.g. \\x1b[97u for 'a').\n\t\t// Terminals with Kitty protocol flag 1 (disambiguate) send CSI-u for all keys,\n\t\t// including plain printable characters. Decode before the control-char check\n\t\t// since CSI-u sequences contain \\x1b which would be rejected.\n\t\tconst kittyPrintable = decodeKittyPrintable(data);\n\t\tif (kittyPrintable !== undefined) {\n\t\t\tthis.insertCharacter(kittyPrintable);\n\t\t\treturn;\n\t\t}\n\n\t\t// Regular character input - accept printable characters including Unicode,\n\t\t// but reject control characters (C0: 0x00-0x1F, DEL: 0x7F, C1: 0x80-0x9F)\n\t\tconst hasControlChars = [...data].some((ch) => {\n\t\t\tconst code = ch.charCodeAt(0);\n\t\t\treturn code < 32 || code === 0x7f || (code >= 0x80 && code <= 0x9f);\n\t\t});\n\t\tif (!hasControlChars) {\n\t\t\tthis.insertCharacter(data);\n\t\t}\n\t}\n\n\tprivate insertCharacter(char: string): void {\n\t\tif (isWhitespaceChar(char) || this.lastAction !== \"type-word\") {\n\t\t\tthis.pushUndo();\n\t\t}\n\t\tthis.lastAction = \"type-word\";\n\n\t\tthis.value = this.value.slice(0, this.cursor) + char + this.value.slice(this.cursor);\n\t\tthis.cursor += char.length;\n\t}\n\n\tprivate handleBackspace(): void {\n\t\tthis.lastAction = null;\n\t\tif (this.cursor > 0) {\n\t\t\tthis.pushUndo();\n\t\t\tconst beforeCursor = this.value.slice(0, this.cursor);\n\t\t\tconst graphemes = [...segmenter.segment(beforeCursor)];\n\t\t\tconst lastGrapheme = graphemes[graphemes.length - 1];\n\t\t\tconst graphemeLength = lastGrapheme ? lastGrapheme.segment.length : 1;\n\t\t\tthis.value = this.value.slice(0, this.cursor - graphemeLength) + this.value.slice(this.cursor);\n\t\t\tthis.cursor -= graphemeLength;\n\t\t}\n\t}\n\n\tprivate handleForwardDelete(): void {\n\t\tthis.lastAction = null;\n\t\tif (this.cursor < this.value.length) {\n\t\t\tthis.pushUndo();\n\t\t\tconst afterCursor = this.value.slice(this.cursor);\n\t\t\tconst graphemes = [...segmenter.segment(afterCursor)];\n\t\t\tconst firstGrapheme = graphemes[0];\n\t\t\tconst graphemeLength = firstGrapheme ? firstGrapheme.segment.length : 1;\n\t\t\tthis.value = this.value.slice(0, this.cursor) + this.value.slice(this.cursor + graphemeLength);\n\t\t}\n\t}\n\n\tprivate deleteToLineStart(): void {\n\t\tif (this.cursor === 0) return;\n\t\tthis.pushUndo();\n\t\tconst deletedText = this.value.slice(0, this.cursor);\n\t\tthis.killRing.push(deletedText, { prepend: true, accumulate: this.lastAction === \"kill\" });\n\t\tthis.lastAction = \"kill\";\n\t\tthis.value = this.value.slice(this.cursor);\n\t\tthis.cursor = 0;\n\t}\n\n\tprivate deleteToLineEnd(): void {\n\t\tif (this.cursor >= this.value.length) return;\n\t\tthis.pushUndo();\n\t\tconst deletedText = this.value.slice(this.cursor);\n\t\tthis.killRing.push(deletedText, { prepend: false, accumulate: this.lastAction === \"kill\" });\n\t\tthis.lastAction = \"kill\";\n\t\tthis.value = this.value.slice(0, this.cursor);\n\t}\n\n\tprivate deleteWordBackwards(): void {\n\t\tif (this.cursor === 0) return;\n\n\t\t// Save lastAction before cursor movement (moveWordBackwards resets it)\n\t\tconst wasKill = this.lastAction === \"kill\";\n\n\t\tthis.pushUndo();\n\n\t\tconst oldCursor = this.cursor;\n\t\tthis.moveWordBackwards();\n\t\tconst deleteFrom = this.cursor;\n\t\tthis.cursor = oldCursor;\n\n\t\tconst deletedText = this.value.slice(deleteFrom, this.cursor);\n\t\tthis.killRing.push(deletedText, { prepend: true, accumulate: wasKill });\n\t\tthis.lastAction = \"kill\";\n\n\t\tthis.value = this.value.slice(0, deleteFrom) + this.value.slice(this.cursor);\n\t\tthis.cursor = deleteFrom;\n\t}\n\n\tprivate deleteWordForward(): void {\n\t\tif (this.cursor >= this.value.length) return;\n\n\t\t// Save lastAction before cursor movement (moveWordForwards resets it)\n\t\tconst wasKill = this.lastAction === \"kill\";\n\n\t\tthis.pushUndo();\n\n\t\tconst oldCursor = this.cursor;\n\t\tthis.moveWordForwards();\n\t\tconst deleteTo = this.cursor;\n\t\tthis.cursor = oldCursor;\n\n\t\tconst deletedText = this.value.slice(this.cursor, deleteTo);\n\t\tthis.killRing.push(deletedText, { prepend: false, accumulate: wasKill });\n\t\tthis.lastAction = \"kill\";\n\n\t\tthis.value = this.value.slice(0, this.cursor) + this.value.slice(deleteTo);\n\t}\n\n\tprivate yank(): void {\n\t\tconst text = this.killRing.peek();\n\t\tif (!text) return;\n\n\t\tthis.pushUndo();\n\n\t\tthis.value = this.value.slice(0, this.cursor) + text + this.value.slice(this.cursor);\n\t\tthis.cursor += text.length;\n\t\tthis.lastAction = \"yank\";\n\t}\n\n\tprivate yankPop(): void {\n\t\tif (this.lastAction !== \"yank\" || this.killRing.length <= 1) return;\n\n\t\tthis.pushUndo();\n\n\t\tconst prevText = this.killRing.peek() || \"\";\n\t\tthis.value = this.value.slice(0, this.cursor - prevText.length) + this.value.slice(this.cursor);\n\t\tthis.cursor -= prevText.length;\n\n\t\tthis.killRing.rotate();\n\t\tconst text = this.killRing.peek() || \"\";\n\t\tthis.value = this.value.slice(0, this.cursor) + text + this.value.slice(this.cursor);\n\t\tthis.cursor += text.length;\n\t\tthis.lastAction = \"yank\";\n\t}\n\n\tprivate pushUndo(): void {\n\t\tthis.undoStack.push({ value: this.value, cursor: this.cursor });\n\t}\n\n\tprivate undo(): void {\n\t\tconst snapshot = this.undoStack.pop();\n\t\tif (!snapshot) return;\n\t\tthis.value = snapshot.value;\n\t\tthis.cursor = snapshot.cursor;\n\t\tthis.lastAction = null;\n\t}\n\n\tprivate moveWordBackwards(): void {\n\t\tif (this.cursor === 0) {\n\t\t\treturn;\n\t\t}\n\n\t\tthis.lastAction = null;\n\t\tconst textBeforeCursor = this.value.slice(0, this.cursor);\n\t\tconst graphemes = [...segmenter.segment(textBeforeCursor)];\n\n\t\twhile (graphemes.length > 0 && isWhitespaceChar(graphemes[graphemes.length - 1]?.segment || \"\")) {\n\t\t\tthis.cursor -= graphemes.pop()?.segment.length || 0;\n\t\t}\n\n\t\tif (graphemes.length > 0) {\n\t\t\tconst lastGrapheme = graphemes[graphemes.length - 1]?.segment || \"\";\n\t\t\tif (isPunctuationChar(lastGrapheme)) {\n\t\t\t\twhile (graphemes.length > 0 && isPunctuationChar(graphemes[graphemes.length - 1]?.segment || \"\")) {\n\t\t\t\t\tthis.cursor -= graphemes.pop()?.segment.length || 0;\n\t\t\t\t}\n\t\t\t} else {\n\t\t\t\twhile (\n\t\t\t\t\tgraphemes.length > 0 &&\n\t\t\t\t\t!isWhitespaceChar(graphemes[graphemes.length - 1]?.segment || \"\") &&\n\t\t\t\t\t!isPunctuationChar(graphemes[graphemes.length - 1]?.segment || \"\")\n\t\t\t\t) {\n\t\t\t\t\tthis.cursor -= graphemes.pop()?.segment.length || 0;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\n\tprivate moveWordForwards(): void {\n\t\tif (this.cursor >= this.value.length) {\n\t\t\treturn;\n\t\t}\n\n\t\tthis.lastAction = null;\n\t\tconst textAfterCursor = this.value.slice(this.cursor);\n\t\tconst segments = segmenter.segment(textAfterCursor);\n\t\tconst iterator = segments[Symbol.iterator]();\n\t\tlet next = iterator.next();\n\n\t\twhile (!next.done && isWhitespaceChar(next.value.segment)) {\n\t\t\tthis.cursor += next.value.segment.length;\n\t\t\tnext = iterator.next();\n\t\t}\n\n\t\tif (!next.done) {\n\t\t\tconst firstGrapheme = next.value.segment;\n\t\t\tif (isPunctuationChar(firstGrapheme)) {\n\t\t\t\twhile (!next.done && isPunctuationChar(next.value.segment)) {\n\t\t\t\t\tthis.cursor += next.value.segment.length;\n\t\t\t\t\tnext = iterator.next();\n\t\t\t\t}\n\t\t\t} else {\n\t\t\t\twhile (!next.done && !isWhitespaceChar(next.value.segment) && !isPunctuationChar(next.value.segment)) {\n\t\t\t\t\tthis.cursor += next.value.segment.length;\n\t\t\t\t\tnext = iterator.next();\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\n\tprivate handlePaste(pastedText: string): void {\n\t\tthis.lastAction = null;\n\t\tthis.pushUndo();\n\n\t\tconst cleanText = pastedText.replace(/\\r\\n/g, \"\").replace(/\\r/g, \"\").replace(/\\n/g, \"\").replace(/\\t/g, \" \");\n\n\t\tthis.value = this.value.slice(0, this.cursor) + cleanText + this.value.slice(this.cursor);\n\t\tthis.cursor += cleanText.length;\n\t}\n\n\tinvalidate(): void {}\n\n\tprivate displayState(): InputState {\n\t\tif (!this.masked) return { value: this.value, cursor: this.cursor };\n\t\t// Mask by grapheme; edits and submissions keep the original buffer.\n\t\tconst graphemes = [...segmenter.segment(this.value)];\n\t\tconst beforeCursor = [...segmenter.segment(this.value.slice(0, this.cursor))];\n\t\treturn { value: \"•\".repeat(graphemes.length), cursor: beforeCursor.length };\n\t}\n\n\trender(width: number): string[] {\n\t\tconst prompt = \"> \";\n\t\tconst availableWidth = width - prompt.length;\n\n\t\tif (availableWidth <= 0) {\n\t\t\treturn [prompt];\n\t\t}\n\n\t\tconst display = this.displayState();\n\t\tlet visibleText = \"\";\n\t\tlet cursorDisplay = display.cursor;\n\t\tconst totalWidth = visibleWidth(display.value);\n\n\t\tif (totalWidth < availableWidth) {\n\t\t\tvisibleText = display.value;\n\t\t} else {\n\t\t\tconst scrollWidth = display.cursor === display.value.length ? availableWidth - 1 : availableWidth;\n\t\t\tconst cursorCol = visibleWidth(display.value.slice(0, display.cursor));\n\n\t\t\tif (scrollWidth > 0) {\n\t\t\t\tconst halfWidth = Math.floor(scrollWidth / 2);\n\t\t\t\tlet startCol = 0;\n\n\t\t\t\tif (cursorCol < halfWidth) {\n\t\t\t\t\tstartCol = 0;\n\t\t\t\t} else if (cursorCol > totalWidth - halfWidth) {\n\t\t\t\t\tstartCol = Math.max(0, totalWidth - scrollWidth);\n\t\t\t\t} else {\n\t\t\t\t\tstartCol = Math.max(0, cursorCol - halfWidth);\n\t\t\t\t}\n\n\t\t\t\tvisibleText = sliceByColumn(display.value, startCol, scrollWidth, true);\n\t\t\t\tconst beforeCursor = sliceByColumn(display.value, startCol, Math.max(0, cursorCol - startCol), true);\n\t\t\t\tcursorDisplay = beforeCursor.length;\n\t\t\t} else {\n\t\t\t\tvisibleText = \"\";\n\t\t\t\tcursorDisplay = 0;\n\t\t\t}\n\t\t}\n\n\t\tconst graphemes = [...segmenter.segment(visibleText.slice(cursorDisplay))];\n\t\tconst cursorGrapheme = graphemes[0];\n\n\t\tconst beforeCursor = visibleText.slice(0, cursorDisplay);\n\t\tconst atCursor = cursorGrapheme?.segment ?? \" \"; // Character at cursor, or space if at end\n\t\tconst afterCursor = visibleText.slice(cursorDisplay + atCursor.length);\n\n\t\t// Hardware cursor marker (zero-width, emitted before fake cursor for IME positioning)\n\t\tconst marker = this.focused ? CURSOR_MARKER : \"\";\n\n\t\tconst cursorChar = `\\x1b[7m${atCursor}\\x1b[27m`; // ESC[7m = reverse video, ESC[27m = normal\n\t\tconst textWithCursor = beforeCursor + marker + cursorChar + afterCursor;\n\n\t\tconst visualLength = visibleWidth(textWithCursor);\n\t\tconst padding = \" \".repeat(Math.max(0, availableWidth - visualLength));\n\t\tconst line = prompt + textWithCursor + padding;\n\n\t\treturn [line];\n\t}\n}\n"]}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@ponythewhite/base-context-tui",
3
- "version": "1.0.1",
3
+ "version": "1.0.4",
4
4
  "description": "Synerise base-context terminal UI components",
5
5
  "type": "module",
6
6
  "main": "dist/index.js",