@oh-my-pi/pi-tui 16.4.5 → 16.4.8

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.
package/CHANGELOG.md CHANGED
@@ -2,6 +2,18 @@
2
2
 
3
3
  ## [Unreleased]
4
4
 
5
+ ## [16.4.7] - 2026-07-12
6
+
7
+ ### Fixed
8
+
9
+ - Fixed keyboard navigation paying an extra frame of input latency after idle; the queue-drain grace now applies only to Ctrl+C and Escape double-press gestures.
10
+
11
+ ## [16.4.6] - 2026-07-12
12
+
13
+ ### Added
14
+
15
+ - Added support for width-changing editor text decorators on standalone presentation lines, with decorated output safely truncated to the available content width.
16
+
5
17
  ## [16.4.5] - 2026-07-11
6
18
 
7
19
  ### Added
@@ -31,9 +31,9 @@ export declare class Editor implements Component, Focusable {
31
31
  cursorOverride: string | undefined;
32
32
  /** Display width of the cursorOverride glyph (needed because override may contain ANSI escapes). */
33
33
  cursorOverrideWidth: number | undefined;
34
- /** Optional hook that styles displayed input text with zero-width ANSI escapes.
35
- * MUST preserve visible width (may only add SGR codes, never glyphs). Applied per
36
- * layout line to the user-text segments never to the cursor glyph or inline hint. */
34
+ /** Optional hook that decorates displayed user text after source-text layout.
35
+ * Width-changing output is allowed on lines without the cursor; it is truncated
36
+ * to the content width rather than reflowed. Cursor glyphs and inline hints are excluded. */
37
37
  decorateText: ((text: string) => string) | undefined;
38
38
  borderColor: (str: string) => string;
39
39
  onAutocompleteUpdate?: () => void;
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "type": "module",
3
3
  "name": "@oh-my-pi/pi-tui",
4
- "version": "16.4.5",
4
+ "version": "16.4.8",
5
5
  "description": "Terminal User Interface library with differential rendering for efficient text-based applications",
6
6
  "homepage": "https://omp.sh",
7
7
  "author": "Can Boluk",
@@ -37,8 +37,8 @@
37
37
  "fmt": "biome format --write ."
38
38
  },
39
39
  "dependencies": {
40
- "@oh-my-pi/pi-natives": "16.4.5",
41
- "@oh-my-pi/pi-utils": "16.4.5",
40
+ "@oh-my-pi/pi-natives": "16.4.8",
41
+ "@oh-my-pi/pi-utils": "16.4.8",
42
42
  "lru-cache": "11.5.1",
43
43
  "marked": "^18.0.5"
44
44
  },
@@ -387,9 +387,9 @@ export class Editor implements Component, Focusable {
387
387
  cursorOverride: string | undefined;
388
388
  /** Display width of the cursorOverride glyph (needed because override may contain ANSI escapes). */
389
389
  cursorOverrideWidth: number | undefined;
390
- /** Optional hook that styles displayed input text with zero-width ANSI escapes.
391
- * MUST preserve visible width (may only add SGR codes, never glyphs). Applied per
392
- * layout line to the user-text segments never to the cursor glyph or inline hint. */
390
+ /** Optional hook that decorates displayed user text after source-text layout.
391
+ * Width-changing output is allowed on lines without the cursor; it is truncated
392
+ * to the content width rather than reflowed. Cursor glyphs and inline hints are excluded. */
393
393
  decorateText: ((text: string) => string) | undefined;
394
394
  #promptGutter: string | undefined;
395
395
 
@@ -1001,6 +1001,13 @@ export class Editor implements Component, Focusable {
1001
1001
  if (!decorated) {
1002
1002
  displayText = this.#decorate(displayText);
1003
1003
  }
1004
+ if (!hasCursor) {
1005
+ displayWidth = visibleWidth(displayText);
1006
+ if (displayWidth > lineContentWidth) {
1007
+ displayText = truncateToWidth(displayText, lineContentWidth);
1008
+ displayWidth = visibleWidth(displayText);
1009
+ }
1010
+ }
1004
1011
 
1005
1012
  const linePad = padding(Math.max(0, lineContentWidth - displayWidth));
1006
1013
 
package/src/tui.ts CHANGED
@@ -2239,12 +2239,12 @@ export class TUI extends Container {
2239
2239
  }
2240
2240
 
2241
2241
  #handleInput(data: string): void {
2242
- // Raw-mode Ctrl+C/Esc arrive as stdin data, not process signals. If the
2243
- // first key in a double-key gesture schedules an immediate slow repaint,
2244
- // the queued second key can sit behind that repaint long enough for the
2245
- // app-level double-press window to expire. Give the input queue one frame
2246
- // before ordinary paints; forced repaints still bypass this path.
2247
- this.#inputRenderGraceUntilMs = this.#renderScheduler.now() + TUI.#INPUT_RENDER_GRACE_MS;
2242
+ // Ctrl+C/Esc use app-level double-press windows. Give those gestures one
2243
+ // frame to drain queued input before an ordinary repaint; delaying every
2244
+ // key would make idle navigation pay a full frame of latency.
2245
+ if (matchesKey(data, "ctrl+c") || matchesKey(data, "escape")) {
2246
+ this.#inputRenderGraceUntilMs = this.#renderScheduler.now() + TUI.#INPUT_RENDER_GRACE_MS;
2247
+ }
2248
2248
  if (this.#inputListeners.size > 0) {
2249
2249
  let current = data;
2250
2250
  for (const listener of this.#inputListeners) {