@mariozechner/pi-tui 0.7.15 → 0.7.17

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.
@@ -6,9 +6,12 @@ export declare class Input implements Component {
6
6
  private value;
7
7
  private cursor;
8
8
  onSubmit?: (value: string) => void;
9
+ private pasteBuffer;
10
+ private isInPaste;
9
11
  getValue(): string;
10
12
  setValue(value: string): void;
11
13
  handleInput(data: string): void;
14
+ private handlePaste;
12
15
  render(width: number): string[];
13
16
  }
14
17
  //# sourceMappingURL=input.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"input.d.ts","sourceRoot":"","sources":["../../src/components/input.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,WAAW,CAAC;AAG3C;;GAEG;AACH,qBAAa,KAAM,YAAW,SAAS;IACtC,OAAO,CAAC,KAAK,CAAc;IAC3B,OAAO,CAAC,MAAM,CAAa;IACpB,QAAQ,CAAC,EAAE,CAAC,KAAK,EAAE,MAAM,KAAK,IAAI,CAAC;IAE1C,QAAQ,IAAI,MAAM,CAEjB;IAED,QAAQ,CAAC,KAAK,EAAE,MAAM,GAAG,IAAI,CAG5B;IAED,WAAW,CAAC,IAAI,EAAE,MAAM,GAAG,IAAI,CA4D9B;IAED,MAAM,CAAC,KAAK,EAAE,MAAM,GAAG,MAAM,EAAE,CAqD9B;CACD","sourcesContent":["import type { Component } from \"../tui.js\";\nimport { visibleWidth } from \"../utils.js\";\n\n/**\n * Input component - single-line text input with horizontal scrolling\n */\nexport class Input implements Component {\n\tprivate value: string = \"\";\n\tprivate cursor: number = 0; // Cursor position in the value\n\tpublic onSubmit?: (value: string) => void;\n\n\tgetValue(): string {\n\t\treturn this.value;\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\t// Handle special keys\n\t\tif (data === \"\\r\" || data === \"\\n\") {\n\t\t\t// Enter - submit\n\t\t\tif (this.onSubmit) {\n\t\t\t\tthis.onSubmit(this.value);\n\t\t\t}\n\t\t\treturn;\n\t\t}\n\n\t\tif (data === \"\\x7f\" || data === \"\\x08\") {\n\t\t\t// Backspace\n\t\t\tif (this.cursor > 0) {\n\t\t\t\tthis.value = this.value.slice(0, this.cursor - 1) + this.value.slice(this.cursor);\n\t\t\t\tthis.cursor--;\n\t\t\t}\n\t\t\treturn;\n\t\t}\n\n\t\tif (data === \"\\x1b[D\") {\n\t\t\t// Left arrow\n\t\t\tif (this.cursor > 0) {\n\t\t\t\tthis.cursor--;\n\t\t\t}\n\t\t\treturn;\n\t\t}\n\n\t\tif (data === \"\\x1b[C\") {\n\t\t\t// Right arrow\n\t\t\tif (this.cursor < this.value.length) {\n\t\t\t\tthis.cursor++;\n\t\t\t}\n\t\t\treturn;\n\t\t}\n\n\t\tif (data === \"\\x1b[3~\") {\n\t\t\t// Delete\n\t\t\tif (this.cursor < this.value.length) {\n\t\t\t\tthis.value = this.value.slice(0, this.cursor) + this.value.slice(this.cursor + 1);\n\t\t\t}\n\t\t\treturn;\n\t\t}\n\n\t\tif (data === \"\\x01\") {\n\t\t\t// Ctrl+A - beginning of line\n\t\t\tthis.cursor = 0;\n\t\t\treturn;\n\t\t}\n\n\t\tif (data === \"\\x05\") {\n\t\t\t// Ctrl+E - end of line\n\t\t\tthis.cursor = this.value.length;\n\t\t\treturn;\n\t\t}\n\n\t\t// Regular character input\n\t\tif (data.length === 1 && data >= \" \" && data <= \"~\") {\n\t\t\tthis.value = this.value.slice(0, this.cursor) + data + this.value.slice(this.cursor);\n\t\t\tthis.cursor++;\n\t\t}\n\t}\n\n\trender(width: number): string[] {\n\t\t// Calculate visible window\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\n\t\tif (this.value.length < availableWidth) {\n\t\t\t// Everything fits (leave room for cursor at end)\n\t\t\tvisibleText = this.value;\n\t\t} else {\n\t\t\t// Need horizontal scrolling\n\t\t\t// Reserve one character for cursor if it's at the end\n\t\t\tconst scrollWidth = this.cursor === this.value.length ? availableWidth - 1 : availableWidth;\n\t\t\tconst halfWidth = Math.floor(scrollWidth / 2);\n\n\t\t\tif (this.cursor < halfWidth) {\n\t\t\t\t// Cursor near start\n\t\t\t\tvisibleText = this.value.slice(0, scrollWidth);\n\t\t\t\tcursorDisplay = this.cursor;\n\t\t\t} else if (this.cursor > this.value.length - halfWidth) {\n\t\t\t\t// Cursor near end\n\t\t\t\tvisibleText = this.value.slice(this.value.length - scrollWidth);\n\t\t\t\tcursorDisplay = scrollWidth - (this.value.length - this.cursor);\n\t\t\t} else {\n\t\t\t\t// Cursor in middle\n\t\t\t\tconst start = this.cursor - halfWidth;\n\t\t\t\tvisibleText = this.value.slice(start, start + scrollWidth);\n\t\t\t\tcursorDisplay = halfWidth;\n\t\t\t}\n\t\t}\n\n\t\t// Build line with fake cursor\n\t\t// Insert cursor character at cursor position\n\t\tconst beforeCursor = visibleText.slice(0, cursorDisplay);\n\t\tconst atCursor = visibleText[cursorDisplay] || \" \"; // Character at cursor, or space if at end\n\t\tconst afterCursor = visibleText.slice(cursorDisplay + 1);\n\n\t\t// Use inverse video to show cursor\n\t\tconst cursorChar = `\\x1b[7m${atCursor}\\x1b[27m`; // ESC[7m = reverse video, ESC[27m = normal\n\t\tconst textWithCursor = beforeCursor + cursorChar + afterCursor;\n\n\t\t// Calculate visual width\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":"AAAA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,WAAW,CAAC;AAG3C;;GAEG;AACH,qBAAa,KAAM,YAAW,SAAS;IACtC,OAAO,CAAC,KAAK,CAAc;IAC3B,OAAO,CAAC,MAAM,CAAa;IACpB,QAAQ,CAAC,EAAE,CAAC,KAAK,EAAE,MAAM,KAAK,IAAI,CAAC;IAG1C,OAAO,CAAC,WAAW,CAAc;IACjC,OAAO,CAAC,SAAS,CAAkB;IAEnC,QAAQ,IAAI,MAAM,CAEjB;IAED,QAAQ,CAAC,KAAK,EAAE,MAAM,GAAG,IAAI,CAG5B;IAED,WAAW,CAAC,IAAI,EAAE,MAAM,GAAG,IAAI,CAgG9B;IAED,OAAO,CAAC,WAAW;IASnB,MAAM,CAAC,KAAK,EAAE,MAAM,GAAG,MAAM,EAAE,CAqD9B;CACD","sourcesContent":["import type { Component } from \"../tui.js\";\nimport { visibleWidth } from \"../utils.js\";\n\n/**\n * Input component - single-line text input with horizontal scrolling\n */\nexport class Input implements Component {\n\tprivate value: string = \"\";\n\tprivate cursor: number = 0; // Cursor position in the value\n\tpublic onSubmit?: (value: string) => void;\n\n\t// Bracketed paste mode buffering\n\tprivate pasteBuffer: string = \"\";\n\tprivate isInPaste: boolean = false;\n\n\tgetValue(): string {\n\t\treturn this.value;\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\t// Handle bracketed paste mode\n\t\t// Start of paste: \\x1b[200~\n\t\t// End of paste: \\x1b[201~\n\n\t\t// Check if we're starting a bracketed paste\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\t// If we're in a paste, buffer the data\n\t\tif (this.isInPaste) {\n\t\t\t// Check if this chunk contains the end marker\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\t// Extract the pasted content\n\t\t\t\tconst pasteContent = this.pasteBuffer.substring(0, endIndex);\n\n\t\t\t\t// Process the complete paste\n\t\t\t\tthis.handlePaste(pasteContent);\n\n\t\t\t\t// Reset paste state\n\t\t\t\tthis.isInPaste = false;\n\n\t\t\t\t// Handle any remaining input after the paste marker\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\t\t// Handle special keys\n\t\tif (data === \"\\r\" || data === \"\\n\") {\n\t\t\t// Enter - submit\n\t\t\tif (this.onSubmit) {\n\t\t\t\tthis.onSubmit(this.value);\n\t\t\t}\n\t\t\treturn;\n\t\t}\n\n\t\tif (data === \"\\x7f\" || data === \"\\x08\") {\n\t\t\t// Backspace\n\t\t\tif (this.cursor > 0) {\n\t\t\t\tthis.value = this.value.slice(0, this.cursor - 1) + this.value.slice(this.cursor);\n\t\t\t\tthis.cursor--;\n\t\t\t}\n\t\t\treturn;\n\t\t}\n\n\t\tif (data === \"\\x1b[D\") {\n\t\t\t// Left arrow\n\t\t\tif (this.cursor > 0) {\n\t\t\t\tthis.cursor--;\n\t\t\t}\n\t\t\treturn;\n\t\t}\n\n\t\tif (data === \"\\x1b[C\") {\n\t\t\t// Right arrow\n\t\t\tif (this.cursor < this.value.length) {\n\t\t\t\tthis.cursor++;\n\t\t\t}\n\t\t\treturn;\n\t\t}\n\n\t\tif (data === \"\\x1b[3~\") {\n\t\t\t// Delete\n\t\t\tif (this.cursor < this.value.length) {\n\t\t\t\tthis.value = this.value.slice(0, this.cursor) + this.value.slice(this.cursor + 1);\n\t\t\t}\n\t\t\treturn;\n\t\t}\n\n\t\tif (data === \"\\x01\") {\n\t\t\t// Ctrl+A - beginning of line\n\t\t\tthis.cursor = 0;\n\t\t\treturn;\n\t\t}\n\n\t\tif (data === \"\\x05\") {\n\t\t\t// Ctrl+E - end of line\n\t\t\tthis.cursor = this.value.length;\n\t\t\treturn;\n\t\t}\n\n\t\t// Regular character input\n\t\tif (data.length === 1 && data >= \" \" && data <= \"~\") {\n\t\t\tthis.value = this.value.slice(0, this.cursor) + data + this.value.slice(this.cursor);\n\t\t\tthis.cursor++;\n\t\t}\n\t}\n\n\tprivate handlePaste(pastedText: string): void {\n\t\t// Clean the pasted text - remove newlines and carriage returns\n\t\tconst cleanText = pastedText.replace(/\\r\\n/g, \"\").replace(/\\r/g, \"\").replace(/\\n/g, \"\");\n\n\t\t// Insert at cursor position\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\trender(width: number): string[] {\n\t\t// Calculate visible window\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\n\t\tif (this.value.length < availableWidth) {\n\t\t\t// Everything fits (leave room for cursor at end)\n\t\t\tvisibleText = this.value;\n\t\t} else {\n\t\t\t// Need horizontal scrolling\n\t\t\t// Reserve one character for cursor if it's at the end\n\t\t\tconst scrollWidth = this.cursor === this.value.length ? availableWidth - 1 : availableWidth;\n\t\t\tconst halfWidth = Math.floor(scrollWidth / 2);\n\n\t\t\tif (this.cursor < halfWidth) {\n\t\t\t\t// Cursor near start\n\t\t\t\tvisibleText = this.value.slice(0, scrollWidth);\n\t\t\t\tcursorDisplay = this.cursor;\n\t\t\t} else if (this.cursor > this.value.length - halfWidth) {\n\t\t\t\t// Cursor near end\n\t\t\t\tvisibleText = this.value.slice(this.value.length - scrollWidth);\n\t\t\t\tcursorDisplay = scrollWidth - (this.value.length - this.cursor);\n\t\t\t} else {\n\t\t\t\t// Cursor in middle\n\t\t\t\tconst start = this.cursor - halfWidth;\n\t\t\t\tvisibleText = this.value.slice(start, start + scrollWidth);\n\t\t\t\tcursorDisplay = halfWidth;\n\t\t\t}\n\t\t}\n\n\t\t// Build line with fake cursor\n\t\t// Insert cursor character at cursor position\n\t\tconst beforeCursor = visibleText.slice(0, cursorDisplay);\n\t\tconst atCursor = visibleText[cursorDisplay] || \" \"; // Character at cursor, or space if at end\n\t\tconst afterCursor = visibleText.slice(cursorDisplay + 1);\n\n\t\t// Use inverse video to show cursor\n\t\tconst cursorChar = `\\x1b[7m${atCursor}\\x1b[27m`; // ESC[7m = reverse video, ESC[27m = normal\n\t\tconst textWithCursor = beforeCursor + cursorChar + afterCursor;\n\n\t\t// Calculate visual width\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"]}
@@ -6,6 +6,9 @@ export class Input {
6
6
  value = "";
7
7
  cursor = 0; // Cursor position in the value
8
8
  onSubmit;
9
+ // Bracketed paste mode buffering
10
+ pasteBuffer = "";
11
+ isInPaste = false;
9
12
  getValue() {
10
13
  return this.value;
11
14
  }
@@ -14,6 +17,36 @@ export class Input {
14
17
  this.cursor = Math.min(this.cursor, value.length);
15
18
  }
16
19
  handleInput(data) {
20
+ // Handle bracketed paste mode
21
+ // Start of paste: \x1b[200~
22
+ // End of paste: \x1b[201~
23
+ // Check if we're starting a bracketed paste
24
+ if (data.includes("\x1b[200~")) {
25
+ this.isInPaste = true;
26
+ this.pasteBuffer = "";
27
+ data = data.replace("\x1b[200~", "");
28
+ }
29
+ // If we're in a paste, buffer the data
30
+ if (this.isInPaste) {
31
+ // Check if this chunk contains the end marker
32
+ this.pasteBuffer += data;
33
+ const endIndex = this.pasteBuffer.indexOf("\x1b[201~");
34
+ if (endIndex !== -1) {
35
+ // Extract the pasted content
36
+ const pasteContent = this.pasteBuffer.substring(0, endIndex);
37
+ // Process the complete paste
38
+ this.handlePaste(pasteContent);
39
+ // Reset paste state
40
+ this.isInPaste = false;
41
+ // Handle any remaining input after the paste marker
42
+ const remaining = this.pasteBuffer.substring(endIndex + 6); // 6 = length of \x1b[201~
43
+ this.pasteBuffer = "";
44
+ if (remaining) {
45
+ this.handleInput(remaining);
46
+ }
47
+ }
48
+ return;
49
+ }
17
50
  // Handle special keys
18
51
  if (data === "\r" || data === "\n") {
19
52
  // Enter - submit
@@ -67,6 +100,13 @@ export class Input {
67
100
  this.cursor++;
68
101
  }
69
102
  }
103
+ handlePaste(pastedText) {
104
+ // Clean the pasted text - remove newlines and carriage returns
105
+ const cleanText = pastedText.replace(/\r\n/g, "").replace(/\r/g, "").replace(/\n/g, "");
106
+ // Insert at cursor position
107
+ this.value = this.value.slice(0, this.cursor) + cleanText + this.value.slice(this.cursor);
108
+ this.cursor += cleanText.length;
109
+ }
70
110
  render(width) {
71
111
  // Calculate visible window
72
112
  const prompt = "> ";
@@ -1 +1 @@
1
- {"version":3,"file":"input.js","sourceRoot":"","sources":["../../src/components/input.ts"],"names":[],"mappings":"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","sourcesContent":["import type { Component } from \"../tui.js\";\nimport { visibleWidth } from \"../utils.js\";\n\n/**\n * Input component - single-line text input with horizontal scrolling\n */\nexport class Input implements Component {\n\tprivate value: string = \"\";\n\tprivate cursor: number = 0; // Cursor position in the value\n\tpublic onSubmit?: (value: string) => void;\n\n\tgetValue(): string {\n\t\treturn this.value;\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\t// Handle special keys\n\t\tif (data === \"\\r\" || data === \"\\n\") {\n\t\t\t// Enter - submit\n\t\t\tif (this.onSubmit) {\n\t\t\t\tthis.onSubmit(this.value);\n\t\t\t}\n\t\t\treturn;\n\t\t}\n\n\t\tif (data === \"\\x7f\" || data === \"\\x08\") {\n\t\t\t// Backspace\n\t\t\tif (this.cursor > 0) {\n\t\t\t\tthis.value = this.value.slice(0, this.cursor - 1) + this.value.slice(this.cursor);\n\t\t\t\tthis.cursor--;\n\t\t\t}\n\t\t\treturn;\n\t\t}\n\n\t\tif (data === \"\\x1b[D\") {\n\t\t\t// Left arrow\n\t\t\tif (this.cursor > 0) {\n\t\t\t\tthis.cursor--;\n\t\t\t}\n\t\t\treturn;\n\t\t}\n\n\t\tif (data === \"\\x1b[C\") {\n\t\t\t// Right arrow\n\t\t\tif (this.cursor < this.value.length) {\n\t\t\t\tthis.cursor++;\n\t\t\t}\n\t\t\treturn;\n\t\t}\n\n\t\tif (data === \"\\x1b[3~\") {\n\t\t\t// Delete\n\t\t\tif (this.cursor < this.value.length) {\n\t\t\t\tthis.value = this.value.slice(0, this.cursor) + this.value.slice(this.cursor + 1);\n\t\t\t}\n\t\t\treturn;\n\t\t}\n\n\t\tif (data === \"\\x01\") {\n\t\t\t// Ctrl+A - beginning of line\n\t\t\tthis.cursor = 0;\n\t\t\treturn;\n\t\t}\n\n\t\tif (data === \"\\x05\") {\n\t\t\t// Ctrl+E - end of line\n\t\t\tthis.cursor = this.value.length;\n\t\t\treturn;\n\t\t}\n\n\t\t// Regular character input\n\t\tif (data.length === 1 && data >= \" \" && data <= \"~\") {\n\t\t\tthis.value = this.value.slice(0, this.cursor) + data + this.value.slice(this.cursor);\n\t\t\tthis.cursor++;\n\t\t}\n\t}\n\n\trender(width: number): string[] {\n\t\t// Calculate visible window\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\n\t\tif (this.value.length < availableWidth) {\n\t\t\t// Everything fits (leave room for cursor at end)\n\t\t\tvisibleText = this.value;\n\t\t} else {\n\t\t\t// Need horizontal scrolling\n\t\t\t// Reserve one character for cursor if it's at the end\n\t\t\tconst scrollWidth = this.cursor === this.value.length ? availableWidth - 1 : availableWidth;\n\t\t\tconst halfWidth = Math.floor(scrollWidth / 2);\n\n\t\t\tif (this.cursor < halfWidth) {\n\t\t\t\t// Cursor near start\n\t\t\t\tvisibleText = this.value.slice(0, scrollWidth);\n\t\t\t\tcursorDisplay = this.cursor;\n\t\t\t} else if (this.cursor > this.value.length - halfWidth) {\n\t\t\t\t// Cursor near end\n\t\t\t\tvisibleText = this.value.slice(this.value.length - scrollWidth);\n\t\t\t\tcursorDisplay = scrollWidth - (this.value.length - this.cursor);\n\t\t\t} else {\n\t\t\t\t// Cursor in middle\n\t\t\t\tconst start = this.cursor - halfWidth;\n\t\t\t\tvisibleText = this.value.slice(start, start + scrollWidth);\n\t\t\t\tcursorDisplay = halfWidth;\n\t\t\t}\n\t\t}\n\n\t\t// Build line with fake cursor\n\t\t// Insert cursor character at cursor position\n\t\tconst beforeCursor = visibleText.slice(0, cursorDisplay);\n\t\tconst atCursor = visibleText[cursorDisplay] || \" \"; // Character at cursor, or space if at end\n\t\tconst afterCursor = visibleText.slice(cursorDisplay + 1);\n\n\t\t// Use inverse video to show cursor\n\t\tconst cursorChar = `\\x1b[7m${atCursor}\\x1b[27m`; // ESC[7m = reverse video, ESC[27m = normal\n\t\tconst textWithCursor = beforeCursor + cursorChar + afterCursor;\n\n\t\t// Calculate visual width\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 type { Component } from \"../tui.js\";\nimport { visibleWidth } from \"../utils.js\";\n\n/**\n * Input component - single-line text input with horizontal scrolling\n */\nexport class Input implements Component {\n\tprivate value: string = \"\";\n\tprivate cursor: number = 0; // Cursor position in the value\n\tpublic onSubmit?: (value: string) => void;\n\n\t// Bracketed paste mode buffering\n\tprivate pasteBuffer: string = \"\";\n\tprivate isInPaste: boolean = false;\n\n\tgetValue(): string {\n\t\treturn this.value;\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\t// Handle bracketed paste mode\n\t\t// Start of paste: \\x1b[200~\n\t\t// End of paste: \\x1b[201~\n\n\t\t// Check if we're starting a bracketed paste\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\t// If we're in a paste, buffer the data\n\t\tif (this.isInPaste) {\n\t\t\t// Check if this chunk contains the end marker\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\t// Extract the pasted content\n\t\t\t\tconst pasteContent = this.pasteBuffer.substring(0, endIndex);\n\n\t\t\t\t// Process the complete paste\n\t\t\t\tthis.handlePaste(pasteContent);\n\n\t\t\t\t// Reset paste state\n\t\t\t\tthis.isInPaste = false;\n\n\t\t\t\t// Handle any remaining input after the paste marker\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\t\t// Handle special keys\n\t\tif (data === \"\\r\" || data === \"\\n\") {\n\t\t\t// Enter - submit\n\t\t\tif (this.onSubmit) {\n\t\t\t\tthis.onSubmit(this.value);\n\t\t\t}\n\t\t\treturn;\n\t\t}\n\n\t\tif (data === \"\\x7f\" || data === \"\\x08\") {\n\t\t\t// Backspace\n\t\t\tif (this.cursor > 0) {\n\t\t\t\tthis.value = this.value.slice(0, this.cursor - 1) + this.value.slice(this.cursor);\n\t\t\t\tthis.cursor--;\n\t\t\t}\n\t\t\treturn;\n\t\t}\n\n\t\tif (data === \"\\x1b[D\") {\n\t\t\t// Left arrow\n\t\t\tif (this.cursor > 0) {\n\t\t\t\tthis.cursor--;\n\t\t\t}\n\t\t\treturn;\n\t\t}\n\n\t\tif (data === \"\\x1b[C\") {\n\t\t\t// Right arrow\n\t\t\tif (this.cursor < this.value.length) {\n\t\t\t\tthis.cursor++;\n\t\t\t}\n\t\t\treturn;\n\t\t}\n\n\t\tif (data === \"\\x1b[3~\") {\n\t\t\t// Delete\n\t\t\tif (this.cursor < this.value.length) {\n\t\t\t\tthis.value = this.value.slice(0, this.cursor) + this.value.slice(this.cursor + 1);\n\t\t\t}\n\t\t\treturn;\n\t\t}\n\n\t\tif (data === \"\\x01\") {\n\t\t\t// Ctrl+A - beginning of line\n\t\t\tthis.cursor = 0;\n\t\t\treturn;\n\t\t}\n\n\t\tif (data === \"\\x05\") {\n\t\t\t// Ctrl+E - end of line\n\t\t\tthis.cursor = this.value.length;\n\t\t\treturn;\n\t\t}\n\n\t\t// Regular character input\n\t\tif (data.length === 1 && data >= \" \" && data <= \"~\") {\n\t\t\tthis.value = this.value.slice(0, this.cursor) + data + this.value.slice(this.cursor);\n\t\t\tthis.cursor++;\n\t\t}\n\t}\n\n\tprivate handlePaste(pastedText: string): void {\n\t\t// Clean the pasted text - remove newlines and carriage returns\n\t\tconst cleanText = pastedText.replace(/\\r\\n/g, \"\").replace(/\\r/g, \"\").replace(/\\n/g, \"\");\n\n\t\t// Insert at cursor position\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\trender(width: number): string[] {\n\t\t// Calculate visible window\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\n\t\tif (this.value.length < availableWidth) {\n\t\t\t// Everything fits (leave room for cursor at end)\n\t\t\tvisibleText = this.value;\n\t\t} else {\n\t\t\t// Need horizontal scrolling\n\t\t\t// Reserve one character for cursor if it's at the end\n\t\t\tconst scrollWidth = this.cursor === this.value.length ? availableWidth - 1 : availableWidth;\n\t\t\tconst halfWidth = Math.floor(scrollWidth / 2);\n\n\t\t\tif (this.cursor < halfWidth) {\n\t\t\t\t// Cursor near start\n\t\t\t\tvisibleText = this.value.slice(0, scrollWidth);\n\t\t\t\tcursorDisplay = this.cursor;\n\t\t\t} else if (this.cursor > this.value.length - halfWidth) {\n\t\t\t\t// Cursor near end\n\t\t\t\tvisibleText = this.value.slice(this.value.length - scrollWidth);\n\t\t\t\tcursorDisplay = scrollWidth - (this.value.length - this.cursor);\n\t\t\t} else {\n\t\t\t\t// Cursor in middle\n\t\t\t\tconst start = this.cursor - halfWidth;\n\t\t\t\tvisibleText = this.value.slice(start, start + scrollWidth);\n\t\t\t\tcursorDisplay = halfWidth;\n\t\t\t}\n\t\t}\n\n\t\t// Build line with fake cursor\n\t\t// Insert cursor character at cursor position\n\t\tconst beforeCursor = visibleText.slice(0, cursorDisplay);\n\t\tconst atCursor = visibleText[cursorDisplay] || \" \"; // Character at cursor, or space if at end\n\t\tconst afterCursor = visibleText.slice(cursorDisplay + 1);\n\n\t\t// Use inverse video to show cursor\n\t\tconst cursorChar = `\\x1b[7m${atCursor}\\x1b[27m`; // ESC[7m = reverse video, ESC[27m = normal\n\t\tconst textWithCursor = beforeCursor + cursorChar + afterCursor;\n\n\t\t// Calculate visual width\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": "@mariozechner/pi-tui",
3
- "version": "0.7.15",
3
+ "version": "0.7.17",
4
4
  "description": "Terminal User Interface library with differential rendering for efficient text-based applications",
5
5
  "type": "module",
6
6
  "main": "dist/index.js",