@gajae-code/tui 0.8.2 → 0.9.0
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 +3 -0
- package/dist/types/animation-scheduler.d.ts +13 -0
- package/dist/types/components/editor.d.ts +10 -1
- package/dist/types/components/loader.d.ts +10 -1
- package/dist/types/components/markdown.d.ts +14 -1
- package/dist/types/index.d.ts +1 -0
- package/dist/types/tui.d.ts +13 -4
- package/dist/types/utils.d.ts +12 -0
- package/package.json +3 -3
- package/src/animation-scheduler.ts +99 -0
- package/src/components/editor.ts +264 -138
- package/src/components/loader.ts +36 -37
- package/src/components/markdown.ts +79 -2
- package/src/index.ts +1 -0
- package/src/stdin-buffer.ts +89 -11
- package/src/tui.ts +206 -77
- package/src/utils.ts +71 -9
package/src/utils.ts
CHANGED
|
@@ -3,16 +3,31 @@ import {
|
|
|
3
3
|
type ExtractSegmentsResult,
|
|
4
4
|
extractSegments as nativeExtractSegments,
|
|
5
5
|
sliceWithWidth as nativeSliceWithWidth,
|
|
6
|
+
truncateLinesToWidth as nativeTruncateLinesToWidth,
|
|
6
7
|
truncateToWidth as nativeTruncateToWidth,
|
|
8
|
+
visibleWidths as nativeVisibleWidths,
|
|
7
9
|
wrapTextWithAnsi as nativeWrapTextWithAnsi,
|
|
8
10
|
type SliceResult,
|
|
9
11
|
} from "@gajae-code/natives";
|
|
10
|
-
import { getDefaultTabWidth, getIndentation } from "@gajae-code/utils";
|
|
12
|
+
import { getDefaultTabWidth, getIndentation, onDefaultTabWidthChange } from "@gajae-code/utils";
|
|
11
13
|
import { renderMetrics } from "./metrics";
|
|
12
14
|
|
|
13
15
|
export { Ellipsis } from "@gajae-code/natives";
|
|
14
16
|
|
|
15
17
|
export { getDefaultTabWidth, getIndentation } from "@gajae-code/utils";
|
|
18
|
+
/** Test-only performance counters for advisory baseline tests. */
|
|
19
|
+
export const __textHelperPerfCounters = {
|
|
20
|
+
truncateToWidthCalls: 0,
|
|
21
|
+
wrapTextWithAnsiCalls: 0,
|
|
22
|
+
truncateLinesToWidthCalls: 0,
|
|
23
|
+
visibleWidthsCalls: 0,
|
|
24
|
+
reset(): void {
|
|
25
|
+
this.truncateToWidthCalls = 0;
|
|
26
|
+
this.wrapTextWithAnsiCalls = 0;
|
|
27
|
+
this.truncateLinesToWidthCalls = 0;
|
|
28
|
+
this.visibleWidthsCalls = 0;
|
|
29
|
+
},
|
|
30
|
+
};
|
|
16
31
|
|
|
17
32
|
function recordTextHelper<T>(name: string, fn: () => T): T {
|
|
18
33
|
if (!renderMetrics.enabled) return fn();
|
|
@@ -24,6 +39,18 @@ function recordTextHelper<T>(name: string, fn: () => T): T {
|
|
|
24
39
|
}
|
|
25
40
|
}
|
|
26
41
|
|
|
42
|
+
let cachedTabWidth: number | undefined;
|
|
43
|
+
|
|
44
|
+
function getCachedTabWidth(): number {
|
|
45
|
+
cachedTabWidth ??= getDefaultTabWidth();
|
|
46
|
+
return cachedTabWidth;
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
export function invalidateTabWidthCache(): void {
|
|
50
|
+
cachedTabWidth = undefined;
|
|
51
|
+
}
|
|
52
|
+
onDefaultTabWidthChange(invalidateTabWidthCache);
|
|
53
|
+
|
|
27
54
|
export function isPrintableAscii(text: string): boolean {
|
|
28
55
|
for (let i = 0; i < text.length; i++) {
|
|
29
56
|
const code = text.charCodeAt(i);
|
|
@@ -33,7 +60,7 @@ export function isPrintableAscii(text: string): boolean {
|
|
|
33
60
|
}
|
|
34
61
|
|
|
35
62
|
export function sliceWithWidth(line: string, startCol: number, length: number, strict?: boolean | null): SliceResult {
|
|
36
|
-
return nativeSliceWithWidth(line, startCol, length, strict ?? null,
|
|
63
|
+
return nativeSliceWithWidth(line, startCol, length, strict ?? null, getCachedTabWidth());
|
|
37
64
|
}
|
|
38
65
|
|
|
39
66
|
export function truncateToWidth(
|
|
@@ -42,6 +69,7 @@ export function truncateToWidth(
|
|
|
42
69
|
ellipsisKind?: Ellipsis | null,
|
|
43
70
|
pad?: boolean | null,
|
|
44
71
|
): string {
|
|
72
|
+
__textHelperPerfCounters.truncateToWidthCalls += 1;
|
|
45
73
|
// Guard nullish napi inputs: napi-rs 3 on the Windows prebuilt rejects
|
|
46
74
|
// `null` for `Option<u8>` (Ellipsis) / `Option<bool>` (pad) (issue #848),
|
|
47
75
|
// and `maxWidth` is a required `u32` that throws on `null`/`undefined`
|
|
@@ -60,12 +88,34 @@ export function truncateToWidth(
|
|
|
60
88
|
safeWidth,
|
|
61
89
|
resolvedEllipsis ?? Ellipsis.Unicode,
|
|
62
90
|
pad ?? false,
|
|
63
|
-
|
|
91
|
+
getCachedTabWidth(),
|
|
92
|
+
);
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
export function truncateLinesToWidth(
|
|
96
|
+
lines: readonly string[],
|
|
97
|
+
maxWidth: number,
|
|
98
|
+
ellipsisKind?: Ellipsis | null,
|
|
99
|
+
pad?: boolean | null,
|
|
100
|
+
): string[] {
|
|
101
|
+
__textHelperPerfCounters.truncateLinesToWidthCalls += 1;
|
|
102
|
+
const safeWidth = Number.isFinite(maxWidth) ? Math.max(0, Math.trunc(maxWidth)) : 0;
|
|
103
|
+
let resolvedEllipsis: Ellipsis | null | undefined | string = ellipsisKind;
|
|
104
|
+
if (typeof resolvedEllipsis === "string") {
|
|
105
|
+
resolvedEllipsis = resolvedEllipsis === "" ? Ellipsis.Omit : Ellipsis.Unicode;
|
|
106
|
+
}
|
|
107
|
+
return nativeTruncateLinesToWidth(
|
|
108
|
+
lines.map(line => (typeof line === "string" ? line : String(line ?? ""))),
|
|
109
|
+
safeWidth,
|
|
110
|
+
resolvedEllipsis ?? Ellipsis.Unicode,
|
|
111
|
+
pad ?? false,
|
|
112
|
+
getCachedTabWidth(),
|
|
64
113
|
);
|
|
65
114
|
}
|
|
66
115
|
|
|
67
116
|
export function wrapTextWithAnsi(text: string, width: number): string[] {
|
|
68
|
-
|
|
117
|
+
__textHelperPerfCounters.wrapTextWithAnsiCalls += 1;
|
|
118
|
+
return nativeWrapTextWithAnsi(text, width, getCachedTabWidth());
|
|
69
119
|
}
|
|
70
120
|
|
|
71
121
|
export function extractSegments(
|
|
@@ -75,7 +125,7 @@ export function extractSegments(
|
|
|
75
125
|
afterLen: number,
|
|
76
126
|
strictAfter: boolean,
|
|
77
127
|
): ExtractSegmentsResult {
|
|
78
|
-
return nativeExtractSegments(line, beforeEnd, afterStart, afterLen, strictAfter,
|
|
128
|
+
return nativeExtractSegments(line, beforeEnd, afterStart, afterLen, strictAfter, getCachedTabWidth());
|
|
79
129
|
}
|
|
80
130
|
|
|
81
131
|
// Pre-allocated space buffer for padding
|
|
@@ -124,7 +174,7 @@ export function visibleWidthRaw(str: string): number {
|
|
|
124
174
|
if (str.length === 1) {
|
|
125
175
|
const code = str.charCodeAt(0);
|
|
126
176
|
if (code >= 0x20 && code <= 0x7e) return 1;
|
|
127
|
-
if (code === 9) return
|
|
177
|
+
if (code === 9) return getCachedTabWidth();
|
|
128
178
|
}
|
|
129
179
|
|
|
130
180
|
let tabCount = 0;
|
|
@@ -138,12 +188,11 @@ export function visibleWidthRaw(str: string): number {
|
|
|
138
188
|
}
|
|
139
189
|
}
|
|
140
190
|
if (isPureAscii) {
|
|
141
|
-
return str.length + tabCount * (
|
|
191
|
+
return str.length + tabCount * (getCachedTabWidth() - 1);
|
|
142
192
|
}
|
|
143
|
-
|
|
144
193
|
const normalized = normalizeForWidth(str);
|
|
145
194
|
if (tabCount === 0) return Bun.stringWidth(normalized);
|
|
146
|
-
return Bun.stringWidth(normalized.replaceAll("\t", " ".repeat(
|
|
195
|
+
return Bun.stringWidth(normalized.replaceAll("\t", " ".repeat(getCachedTabWidth())));
|
|
147
196
|
}
|
|
148
197
|
|
|
149
198
|
/**
|
|
@@ -154,6 +203,19 @@ export function visibleWidth(str: string): number {
|
|
|
154
203
|
return recordTextHelper("text.visibleWidth", () => visibleWidthRaw(str));
|
|
155
204
|
}
|
|
156
205
|
|
|
206
|
+
export function visibleWidthsNative(lines: readonly string[]): number[] {
|
|
207
|
+
__textHelperPerfCounters.visibleWidthsCalls += 1;
|
|
208
|
+
return nativeVisibleWidths(
|
|
209
|
+
lines.map(line => (typeof line === "string" ? line : String(line ?? ""))),
|
|
210
|
+
getCachedTabWidth(),
|
|
211
|
+
);
|
|
212
|
+
}
|
|
213
|
+
|
|
214
|
+
export function visibleWidths(lines: readonly string[]): number[] {
|
|
215
|
+
void visibleWidthsNative(lines);
|
|
216
|
+
return lines.map(line => visibleWidth(typeof line === "string" ? line : String(line ?? "")));
|
|
217
|
+
}
|
|
218
|
+
|
|
157
219
|
const THAI_LAO_AM_REGEX = /[\u0e33\u0eb3]/;
|
|
158
220
|
const THAI_LAO_AM_GLOBAL_REGEX = /[\u0e33\u0eb3]/g;
|
|
159
221
|
const HANGUL_JAMO_REGEX = /[\u1100-\u11ff\ua960-\ua97f\ud7b0-\ud7ff]/;
|