pi-zentui 0.25.0 → 0.25.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.
|
@@ -149,20 +149,36 @@ export class AgentDurationClock {
|
|
|
149
149
|
}
|
|
150
150
|
}
|
|
151
151
|
|
|
152
|
-
|
|
152
|
+
// Creating an `Intl.Segmenter` per call is very expensive (ICU init). The working
|
|
153
|
+
// line segments the same row for every animation frame, so reuse one instance.
|
|
154
|
+
let sharedGraphemeSegmenter: Intl.Segmenter | undefined;
|
|
155
|
+
let sharedGraphemeSegmenterResolved = false;
|
|
156
|
+
|
|
157
|
+
function getSharedGraphemeSegmenter(): Intl.Segmenter | undefined {
|
|
158
|
+
if (sharedGraphemeSegmenterResolved) return sharedGraphemeSegmenter;
|
|
159
|
+
sharedGraphemeSegmenterResolved = true;
|
|
153
160
|
try {
|
|
154
161
|
const Segmenter = Intl.Segmenter;
|
|
155
162
|
if (typeof Segmenter === "function") {
|
|
156
|
-
|
|
157
|
-
return {
|
|
158
|
-
*[Symbol.iterator]() {
|
|
159
|
-
for (const part of segments) yield part.segment;
|
|
160
|
-
},
|
|
161
|
-
};
|
|
163
|
+
sharedGraphemeSegmenter = new Segmenter(undefined, { granularity: "grapheme" });
|
|
162
164
|
}
|
|
163
165
|
} catch {
|
|
164
|
-
|
|
166
|
+
sharedGraphemeSegmenter = undefined;
|
|
167
|
+
}
|
|
168
|
+
return sharedGraphemeSegmenter;
|
|
169
|
+
}
|
|
170
|
+
|
|
171
|
+
function segmentGraphemes(value: string): Iterable<string> {
|
|
172
|
+
const segmenter = getSharedGraphemeSegmenter();
|
|
173
|
+
if (segmenter !== undefined) {
|
|
174
|
+
const segments = segmenter.segment(value);
|
|
175
|
+
return {
|
|
176
|
+
*[Symbol.iterator]() {
|
|
177
|
+
for (const part of segments) yield part.segment;
|
|
178
|
+
},
|
|
179
|
+
};
|
|
165
180
|
}
|
|
181
|
+
// Without Intl.Segmenter, treat the complete value as one conservative grapheme.
|
|
166
182
|
return [value];
|
|
167
183
|
}
|
|
168
184
|
|
|
@@ -775,6 +791,41 @@ function renderWorkingLineSchedule(
|
|
|
775
791
|
const frameStates: WorkingLineFrameState[] = [];
|
|
776
792
|
let codeUnits = 0;
|
|
777
793
|
const scheduleOrigin = definition.stateAt(scheduleStartFrame);
|
|
794
|
+
// `row` is invariant across the whole schedule; segment it once instead of per frame.
|
|
795
|
+
const rowCells = graphemeCells(row).cells;
|
|
796
|
+
// Many frames of the schedule share the same textTick/spinnerTick. Render each
|
|
797
|
+
// distinct value once and reuse — this dominates on slow CPUs (e.g. a Pi).
|
|
798
|
+
const textRenderCache = new Map<number, string>();
|
|
799
|
+
const renderTextForTick = (tick: number): string => {
|
|
800
|
+
let cachedText = textRenderCache.get(tick);
|
|
801
|
+
if (cachedText === undefined) {
|
|
802
|
+
cachedText = renderAnimatedText(
|
|
803
|
+
theme,
|
|
804
|
+
config,
|
|
805
|
+
colors,
|
|
806
|
+
rowCells,
|
|
807
|
+
width,
|
|
808
|
+
tick,
|
|
809
|
+
config.textAnimation,
|
|
810
|
+
);
|
|
811
|
+
textRenderCache.set(tick, cachedText);
|
|
812
|
+
}
|
|
813
|
+
return cachedText;
|
|
814
|
+
};
|
|
815
|
+
const spinnerRenderCache = new Map<number, string>();
|
|
816
|
+
const renderSpinnerForTick = (tick: number): string => {
|
|
817
|
+
// Key by the glyph index, not the raw tick: the glyph only repeats every
|
|
818
|
+
// `spinner.frames.length` ticks, so keying raw under-caches badly.
|
|
819
|
+
const frameCount = spinner.frames.length;
|
|
820
|
+
const index = ((tick % frameCount) + frameCount) % frameCount;
|
|
821
|
+
let cachedSpinner = spinnerRenderCache.get(index);
|
|
822
|
+
if (cachedSpinner === undefined) {
|
|
823
|
+
const glyph = spinner.frames[index] ?? spinner.frames[0];
|
|
824
|
+
cachedSpinner = renderTier(theme, config, colors, "high", glyph);
|
|
825
|
+
spinnerRenderCache.set(index, cachedSpinner);
|
|
826
|
+
}
|
|
827
|
+
return cachedSpinner;
|
|
828
|
+
};
|
|
778
829
|
for (let index = 0; index < definition.frameCount; index += 1) {
|
|
779
830
|
const scheduled = definition.stateAt(scheduleStartFrame + index);
|
|
780
831
|
const state = {
|
|
@@ -796,15 +847,7 @@ function renderWorkingLineSchedule(
|
|
|
796
847
|
state.textTick,
|
|
797
848
|
config.textAnimation,
|
|
798
849
|
)}${SGR_RESET}`
|
|
799
|
-
: `${
|
|
800
|
-
theme,
|
|
801
|
-
config,
|
|
802
|
-
colors,
|
|
803
|
-
graphemeCells(row).cells,
|
|
804
|
-
width,
|
|
805
|
-
state.textTick,
|
|
806
|
-
config.textAnimation,
|
|
807
|
-
)}${SGR_RESET}`;
|
|
850
|
+
: `${renderSpinnerForTick(state.spinnerTick)} ${renderTextForTick(state.textTick)}${SGR_RESET}`;
|
|
808
851
|
codeUnits += frame.length;
|
|
809
852
|
if (codeUnits > MAX_WORKING_LINE_FRAME_CODE_UNITS) return undefined;
|
|
810
853
|
frames.push(frame);
|