@gajae-code/tui 0.12.7 → 0.12.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 +10 -0
- package/dist/types/components/editor.d.ts +1 -1
- package/dist/types/tui.d.ts +9 -25
- package/package.json +3 -3
- package/src/components/editor.ts +6 -1
- package/src/tui.ts +829 -299
package/CHANGELOG.md
CHANGED
|
@@ -2,6 +2,15 @@
|
|
|
2
2
|
|
|
3
3
|
## [Unreleased]
|
|
4
4
|
|
|
5
|
+
## [0.12.8] - 2026-08-02
|
|
6
|
+
### Fixed
|
|
7
|
+
|
|
8
|
+
- Fixed a tool block being rendered two or three times in the transcript (a pending `⏳` copy stranded above its own completed `✓` copy, with the rows between duplicated). When a block above the live viewport top grows in place — the bash tool's compact call render becoming a partial box and then a final box, with the editor/status chrome keeping it off-screen — the "commit only the changed visible suffix" path emitted rows by index even though the growth had shifted committed content down across the native-scrollback frontier, so rows already in scrollback were appended a second time under their new content. The suffix commit is now taken only when the last committed row is unchanged (a same-length off-screen substitution, such as a streaming status line); growth that shifts the committed boundary repaints the live viewport instead.
|
|
9
|
+
- Temporary TUI restarts now retain their native-scrollback admission frontier when the following viewport repaint fails, preventing newly appended rows from being duplicated on retry.
|
|
10
|
+
- Restored the `isProcessTerminal`/`shouldUseViewportRepaintForHost` gate on the width-change viewport-repaint intercept so plain terminals (non-multiplexer, non-process-terminal) use `fullRender` for width changes instead of an unconditional viewport repaint. The #3684 chain removed this gate, causing lossless Korean/CJK prose wrapping to break at narrow widths because the viewport repaint only painted the visible rows without committing the full transcript to scrollback (#1979).
|
|
11
|
+
- Restored the `fullRender` fallback for the `firstChanged < viewportTop` branch on non-viewport-repaint hosts, so above-viewport mutations replay the full frame instead of silently viewport-repainting.
|
|
12
|
+
- Propagated IME cursor write failure from `#writeRenderBufferAndReanchorImeCursor` so callers detect terminal detach when the deferred cursor write fails after the shared frame commits.
|
|
13
|
+
|
|
5
14
|
## [0.12.7] - 2026-07-31
|
|
6
15
|
|
|
7
16
|
## [0.12.6] - 2026-07-31
|
|
@@ -9,6 +18,7 @@
|
|
|
9
18
|
|
|
10
19
|
- Truncated text now shrinks horizontal padding when the viewport is narrower than the requested inset, keeping every rendered line within its width contract.
|
|
11
20
|
- Select-list no-match rows now stay within the requested render width instead of wrapping into extra terminal lines after narrow resizes (#3600).
|
|
21
|
+
- Preserve transcript rows when a resize/reflow is coalesced with appended output.
|
|
12
22
|
|
|
13
23
|
## [0.12.5] - 2026-07-30
|
|
14
24
|
|
|
@@ -54,7 +54,7 @@ export declare class Editor implements Component, Focusable {
|
|
|
54
54
|
disableSubmit: boolean;
|
|
55
55
|
constructor(theme: EditorTheme);
|
|
56
56
|
dispose(): void;
|
|
57
|
-
setAutocompleteProvider(provider: AutocompleteProvider): void;
|
|
57
|
+
setAutocompleteProvider(provider: AutocompleteProvider | undefined): void;
|
|
58
58
|
getAutocompleteProvider(): AutocompleteProvider | undefined;
|
|
59
59
|
/** Whether the autocomplete dropdown is currently open. */
|
|
60
60
|
isAutocompleteOpen(): boolean;
|
package/dist/types/tui.d.ts
CHANGED
|
@@ -279,11 +279,6 @@ export declare class TUI extends Container {
|
|
|
279
279
|
getShowHardwareCursor(): boolean;
|
|
280
280
|
setShowHardwareCursor(enabled: boolean): void;
|
|
281
281
|
getClearOnShrink(): boolean;
|
|
282
|
-
/**
|
|
283
|
-
* Set whether to trigger full re-render when content shrinks.
|
|
284
|
-
* When true (default), empty rows are cleared when content shrinks.
|
|
285
|
-
* When false, empty rows remain (reduces redraws on slower terminals).
|
|
286
|
-
*/
|
|
287
282
|
setClearOnShrink(enabled: boolean): void;
|
|
288
283
|
setFocus(component: Component | null): void;
|
|
289
284
|
/** Returns the currently focused component without exposing mutable focus state. */
|
|
@@ -306,7 +301,7 @@ export declare class TUI extends Container {
|
|
|
306
301
|
setViewportAnchorComponent(component: Component | null): void;
|
|
307
302
|
/** Returns the direct component registered as the semantic viewport anchor source. */
|
|
308
303
|
getViewportAnchorComponent(): Component | null;
|
|
309
|
-
/** Clear manual viewport ownership before replacing the transcript identity
|
|
304
|
+
/** Clear manual viewport ownership and durable history before replacing the transcript identity. */
|
|
310
305
|
resetViewportAnchorIntent(): void;
|
|
311
306
|
/** Allow one semantic-neighbor reconciliation after a definitive same-transcript rebuild. */
|
|
312
307
|
prepareViewportAnchorForTranscriptRebuild(): void;
|
|
@@ -345,24 +340,14 @@ export declare class TUI extends Container {
|
|
|
345
340
|
/**
|
|
346
341
|
* Viewport-repaint-aware resize render request.
|
|
347
342
|
*
|
|
348
|
-
* A forced
|
|
349
|
-
*
|
|
350
|
-
*
|
|
351
|
-
* `3J` escape (users navigate scrollback history), so replaying every transcript line
|
|
352
|
-
* piles it back on top of scrollback — the "top of screen scrolls down to the prompt at
|
|
353
|
-
* high speed" resize storm. Windows Terminal/ConPTY can also visibly jump to
|
|
354
|
-
* the transcript top during streaming redraws, so viewport-repaint sessions
|
|
355
|
-
* keep force off and let `#doRender` repaint only the live viewport. Set
|
|
356
|
-
* `PI_TUI_LEGACY_MULTIPLEXER_FULL_RENDER=1` to restore the legacy tmux redraw.
|
|
343
|
+
* A forced repaint resets `#previousWidth`/`#previousHeight` to -1, which makes
|
|
344
|
+
* `#doRender` treat the frame as a dimension change. Repaints stay anchored to
|
|
345
|
+
* the live viewport so native scrollback is never replayed or erased.
|
|
357
346
|
*
|
|
358
347
|
* Spurious resize events (SIGWINCH with unchanged dimensions — iTerm2 tab
|
|
359
348
|
* switches and window focus changes, the self-sent SIGWINCH after resume)
|
|
360
|
-
* must not force either:
|
|
361
|
-
*
|
|
362
|
-
* scrollback (`2J`/`H`/`3J`) and replays the whole transcript, which can
|
|
363
|
-
* park the native viewport at the transcript top. Only force when the grid
|
|
364
|
-
* size actually changed since the last committed frame; a plain diff render
|
|
365
|
-
* is a no-op otherwise.
|
|
349
|
+
* must not force either: only force when the grid size actually changed since
|
|
350
|
+
* the last committed frame.
|
|
366
351
|
*/
|
|
367
352
|
requestResizeRender(): void;
|
|
368
353
|
requestRender(force?: boolean, source?: string): void;
|
|
@@ -378,10 +363,9 @@ export declare class TUI extends Container {
|
|
|
378
363
|
/** Retry queued terminal cleanup after terminal recovery or before shutdown. */
|
|
379
364
|
flushTerminalCleanup(): void;
|
|
380
365
|
/**
|
|
381
|
-
* Register an emitter whose
|
|
382
|
-
*
|
|
383
|
-
*
|
|
384
|
-
* outside the line-based component model. Return null to emit nothing.
|
|
366
|
+
* Register an emitter whose payload is delivered after each shared render
|
|
367
|
+
* transaction. The emitter is an exempt physical overlay: its bytes are
|
|
368
|
+
* deliberately kept out of the shared transcript write.
|
|
385
369
|
*/
|
|
386
370
|
setPostRenderEmitter(emitter: (() => string | null) | undefined): void;
|
|
387
371
|
}
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"type": "module",
|
|
3
3
|
"name": "@gajae-code/tui",
|
|
4
|
-
"version": "0.12.
|
|
4
|
+
"version": "0.12.8",
|
|
5
5
|
"description": "Terminal User Interface library with differential rendering for efficient text-based applications",
|
|
6
6
|
"homepage": "https://gajae-code.com",
|
|
7
7
|
"author": "Yeachan-Heo and Gajae Code Contributors",
|
|
@@ -36,8 +36,8 @@
|
|
|
36
36
|
"fmt": "biome format --write ."
|
|
37
37
|
},
|
|
38
38
|
"dependencies": {
|
|
39
|
-
"@gajae-code/natives": "0.12.
|
|
40
|
-
"@gajae-code/utils": "0.12.
|
|
39
|
+
"@gajae-code/natives": "0.12.8",
|
|
40
|
+
"@gajae-code/utils": "0.12.8",
|
|
41
41
|
"lru-cache": "11.3.6",
|
|
42
42
|
"marked": "18.0.6"
|
|
43
43
|
},
|
package/src/components/editor.ts
CHANGED
|
@@ -522,8 +522,13 @@ export class Editor implements Component, Focusable {
|
|
|
522
522
|
this.#disposeTabWidthListener = undefined;
|
|
523
523
|
}
|
|
524
524
|
|
|
525
|
-
setAutocompleteProvider(provider: AutocompleteProvider): void {
|
|
525
|
+
setAutocompleteProvider(provider: AutocompleteProvider | undefined): void {
|
|
526
526
|
this.#autocompleteProvider = provider;
|
|
527
|
+
if (provider === undefined) {
|
|
528
|
+
this.#cancelAutocomplete();
|
|
529
|
+
this.onAutocompleteUpdate?.();
|
|
530
|
+
}
|
|
531
|
+
this.invalidate();
|
|
527
532
|
}
|
|
528
533
|
|
|
529
534
|
getAutocompleteProvider(): AutocompleteProvider | undefined {
|