@gajae-code/tui 0.16.7 → 0.17.1
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/tui.d.ts +2 -0
- package/package.json +3 -3
- package/src/tui.ts +24 -9
package/CHANGELOG.md
CHANGED
|
@@ -2,6 +2,16 @@
|
|
|
2
2
|
|
|
3
3
|
## [Unreleased]
|
|
4
4
|
|
|
5
|
+
## [0.17.1] - 2026-09-17
|
|
6
|
+
|
|
7
|
+
## [0.17.0] - 2026-09-17
|
|
8
|
+
|
|
9
|
+
### Performance
|
|
10
|
+
|
|
11
|
+
- Defer resize reflow-decision scans to their consuming branch, skipping them on unchanged-width frames and viewport-only repaints; coalesced resize appends avoid that decision scan while retained-prefix validation may still measure rows, preserving rendering and settled scrollback repair.
|
|
12
|
+
|
|
13
|
+
- Skip the kitty placement scan on terminals that do not run the kitty graphics protocol, and keep the outgoing logical and raw frames by reference instead of copying them. Both removed a walk over every transcript line from every render frame; emitted bytes are unchanged.
|
|
14
|
+
|
|
5
15
|
## [0.16.7] - 2026-09-13
|
|
6
16
|
|
|
7
17
|
## [0.16.6] - 2026-09-07
|
package/dist/types/tui.d.ts
CHANGED
|
@@ -362,6 +362,8 @@ type TuiRenderCounterSnapshot = {
|
|
|
362
362
|
debugRedrawAppendWrites: number;
|
|
363
363
|
differentialGuardVisibleWidthCalls: number;
|
|
364
364
|
widthReflowScanRows: number;
|
|
365
|
+
widthReflowVisibleWidthCalls: number;
|
|
366
|
+
kittyPlacementScanRows: number;
|
|
365
367
|
};
|
|
366
368
|
/**
|
|
367
369
|
* TUI - Main class for managing terminal UI with differential rendering
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"type": "module",
|
|
3
3
|
"name": "@gajae-code/tui",
|
|
4
|
-
"version": "0.
|
|
4
|
+
"version": "0.17.1",
|
|
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.
|
|
40
|
-
"@gajae-code/utils": "0.
|
|
39
|
+
"@gajae-code/natives": "0.17.1",
|
|
40
|
+
"@gajae-code/utils": "0.17.1",
|
|
41
41
|
"lru-cache": "11.3.6",
|
|
42
42
|
"marked": "18.0.6"
|
|
43
43
|
},
|
package/src/tui.ts
CHANGED
|
@@ -819,6 +819,8 @@ type TuiRenderCounterSnapshot = {
|
|
|
819
819
|
debugRedrawAppendWrites: number;
|
|
820
820
|
differentialGuardVisibleWidthCalls: number;
|
|
821
821
|
widthReflowScanRows: number;
|
|
822
|
+
widthReflowVisibleWidthCalls: number;
|
|
823
|
+
kittyPlacementScanRows: number;
|
|
822
824
|
};
|
|
823
825
|
type RenderCommitWaiter = {
|
|
824
826
|
resolve: (committed: boolean) => void;
|
|
@@ -1183,6 +1185,8 @@ export class TUI extends Container {
|
|
|
1183
1185
|
debugRedrawAppendWrites: 0,
|
|
1184
1186
|
differentialGuardVisibleWidthCalls: 0,
|
|
1185
1187
|
widthReflowScanRows: 0,
|
|
1188
|
+
widthReflowVisibleWidthCalls: 0,
|
|
1189
|
+
kittyPlacementScanRows: 0,
|
|
1186
1190
|
};
|
|
1187
1191
|
|
|
1188
1192
|
static resetRenderCountersForTest(): void {
|
|
@@ -1191,6 +1195,8 @@ export class TUI extends Container {
|
|
|
1191
1195
|
debugRedrawAppendWrites: 0,
|
|
1192
1196
|
differentialGuardVisibleWidthCalls: 0,
|
|
1193
1197
|
widthReflowScanRows: 0,
|
|
1198
|
+
widthReflowVisibleWidthCalls: 0,
|
|
1199
|
+
kittyPlacementScanRows: 0,
|
|
1194
1200
|
};
|
|
1195
1201
|
}
|
|
1196
1202
|
|
|
@@ -4128,7 +4134,12 @@ export class TUI extends Container {
|
|
|
4128
4134
|
lines: string[],
|
|
4129
4135
|
owners: ReadonlyMap<string, KittyPlacementOwner>,
|
|
4130
4136
|
): KittyPlacementSpan[] {
|
|
4137
|
+
// encodeKittyPlacement is only reachable from renderImage's kitty branch, so a
|
|
4138
|
+
// line rendered under any other protocol cannot carry a placement and the scan
|
|
4139
|
+
// can only return empty. See the commit message for the consumers this covers.
|
|
4140
|
+
if (TERMINAL.imageProtocol !== ImageProtocol.Kitty) return [];
|
|
4131
4141
|
const placements: KittyPlacementSpan[] = [];
|
|
4142
|
+
TUI.#renderCounters.kittyPlacementScanRows += lines.length;
|
|
4132
4143
|
for (let row = 0; row < lines.length; row++) {
|
|
4133
4144
|
for (const placement of extractKittyPlacementReferences(lines[row])) {
|
|
4134
4145
|
placements.push({
|
|
@@ -4736,8 +4747,9 @@ export class TUI extends Container {
|
|
|
4736
4747
|
if (usedWindowNormalize) renderMetrics.recordLineCount("offscreenScan", diffStart);
|
|
4737
4748
|
}
|
|
4738
4749
|
const nextKittyPlacementSpans = this.#kittyPlacementSpansForLines(newLines, placementOwners);
|
|
4739
|
-
|
|
4740
|
-
const
|
|
4750
|
+
// Reassigned, never mutated in place -- a reference is the snapshot.
|
|
4751
|
+
const previousLogicalFrame = this.#latestRenderedLines;
|
|
4752
|
+
const previousRawFrame = this.#latestRaw;
|
|
4741
4753
|
const previousRenderedLength = previousLogicalFrame.length;
|
|
4742
4754
|
this.#latestRenderedLines = newLines;
|
|
4743
4755
|
this.#latestRenderedTranscriptLineCount = nextTranscriptLineCount;
|
|
@@ -5086,13 +5098,6 @@ export class TUI extends Container {
|
|
|
5086
5098
|
return;
|
|
5087
5099
|
}
|
|
5088
5100
|
const useViewportRepaintPath = this.#viewportRepaintHost();
|
|
5089
|
-
const widthReflowRequired =
|
|
5090
|
-
widthChanged &&
|
|
5091
|
-
this.#previousWidth > 0 &&
|
|
5092
|
-
rawLines.some(line => {
|
|
5093
|
-
TUI.#renderCounters.widthReflowScanRows += 1;
|
|
5094
|
-
return !TERMINAL.isImageLine(line) && visibleWidth(line) > Math.min(this.#previousWidth, width);
|
|
5095
|
-
});
|
|
5096
5101
|
if (
|
|
5097
5102
|
widthChanged &&
|
|
5098
5103
|
!this.#legacyMultiplexerFullRender &&
|
|
@@ -5176,6 +5181,16 @@ export class TUI extends Container {
|
|
|
5176
5181
|
// Width changes always need a full re-render because wrapping changes, unless
|
|
5177
5182
|
// a proven coalesced append is continuing through the durable append path.
|
|
5178
5183
|
if (widthChanged && !coalescedWidthAppend) {
|
|
5184
|
+
// Measure only where the reflow decision is consumed. Viewport-only
|
|
5185
|
+
// resize repaints return above; coalesced appends also skip this scan.
|
|
5186
|
+
const widthReflowRequired =
|
|
5187
|
+
this.#previousWidth > 0 &&
|
|
5188
|
+
rawLines.some(line => {
|
|
5189
|
+
TUI.#renderCounters.widthReflowScanRows += 1;
|
|
5190
|
+
if (TERMINAL.isImageLine(line)) return false;
|
|
5191
|
+
TUI.#renderCounters.widthReflowVisibleWidthCalls += 1;
|
|
5192
|
+
return visibleWidth(line) > Math.min(this.#previousWidth, width);
|
|
5193
|
+
});
|
|
5179
5194
|
if (!widthReflowRequired) {
|
|
5180
5195
|
this.#widthSettleRepairPending = false;
|
|
5181
5196
|
logRedraw(`terminal width changed without reflow (${this.#previousWidth} -> ${width})`);
|