@oh-my-pi/pi-tui 17.2.3 → 17.2.5
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 +13 -0
- package/package.json +3 -3
- package/src/components/loader.ts +30 -15
- package/src/terminal.ts +7 -7
package/CHANGELOG.md
CHANGED
|
@@ -2,6 +2,19 @@
|
|
|
2
2
|
|
|
3
3
|
## [Unreleased]
|
|
4
4
|
|
|
5
|
+
## [17.2.5] - 2026-08-03
|
|
6
|
+
|
|
7
|
+
### Fixed
|
|
8
|
+
|
|
9
|
+
- Fixed Kitty and Ghostty keyboard shortcuts on non-Latin keyboard layouts by requesting base-layout key reporting from the terminal.
|
|
10
|
+
|
|
11
|
+
## [17.2.4] - 2026-08-01
|
|
12
|
+
|
|
13
|
+
### Fixed
|
|
14
|
+
|
|
15
|
+
- Fixed animated Loader paints saturating a CPU core on slow WSL/ConPTY terminals by applying cost-aware cadence backpressure while preserving 30fps on cheap frames ([#7290](https://github.com/can1357/oh-my-pi/issues/7290)).
|
|
16
|
+
- Fixed interactive terminals suppressing all output and input when the host project sets `NODE_ENV=test` or `BUN_ENV=test` ([#7261](https://github.com/can1357/oh-my-pi/issues/7261)).
|
|
17
|
+
|
|
5
18
|
## [17.2.2] - 2026-07-31
|
|
6
19
|
|
|
7
20
|
### Added
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"type": "module",
|
|
3
3
|
"name": "@oh-my-pi/pi-tui",
|
|
4
|
-
"version": "17.2.
|
|
4
|
+
"version": "17.2.5",
|
|
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": "17.2.
|
|
41
|
-
"@oh-my-pi/pi-utils": "17.2.
|
|
40
|
+
"@oh-my-pi/pi-natives": "17.2.5",
|
|
41
|
+
"@oh-my-pi/pi-utils": "17.2.5",
|
|
42
42
|
"lru-cache": "11.5.2",
|
|
43
43
|
"marked": "^18.0.6"
|
|
44
44
|
},
|
package/src/components/loader.ts
CHANGED
|
@@ -4,6 +4,8 @@ import { Text } from "./text";
|
|
|
4
4
|
|
|
5
5
|
const RENDER_INTERVAL_MS = 1000 / 30;
|
|
6
6
|
const SPINNER_ADVANCE_MS = 80;
|
|
7
|
+
const MAX_RENDER_BACKPRESSURE_MS = 200;
|
|
8
|
+
const RENDER_BACKPRESSURE_MULTIPLIER = 9;
|
|
7
9
|
|
|
8
10
|
type ColorFn = (str: string) => string;
|
|
9
11
|
|
|
@@ -98,25 +100,12 @@ export class Loader extends Text {
|
|
|
98
100
|
this.#syncText();
|
|
99
101
|
this.#requestPaint();
|
|
100
102
|
const intervalMs = this.messageColorFn.animated === true ? RENDER_INTERVAL_MS : SPINNER_ADVANCE_MS;
|
|
101
|
-
this.#
|
|
102
|
-
const now = performance.now();
|
|
103
|
-
const elapsed = now - this.#lastSpinnerTick;
|
|
104
|
-
const shouldAdvanceSpinner = elapsed >= SPINNER_ADVANCE_MS;
|
|
105
|
-
if (shouldAdvanceSpinner) {
|
|
106
|
-
const steps = Math.floor(elapsed / SPINNER_ADVANCE_MS);
|
|
107
|
-
this.#currentFrame = (this.#currentFrame + steps) % this.#frames.length;
|
|
108
|
-
this.#lastSpinnerTick += steps * SPINNER_ADVANCE_MS;
|
|
109
|
-
this.#syncText();
|
|
110
|
-
}
|
|
111
|
-
if (shouldAdvanceSpinner || this.#ui?.synchronizedOutput === true) {
|
|
112
|
-
this.#requestPaint();
|
|
113
|
-
}
|
|
114
|
-
}, intervalMs);
|
|
103
|
+
this.#scheduleTick(intervalMs, intervalMs);
|
|
115
104
|
}
|
|
116
105
|
|
|
117
106
|
stop() {
|
|
118
107
|
if (this.#intervalId) {
|
|
119
|
-
|
|
108
|
+
clearTimeout(this.#intervalId);
|
|
120
109
|
this.#intervalId = undefined;
|
|
121
110
|
}
|
|
122
111
|
}
|
|
@@ -135,6 +124,32 @@ export class Loader extends Text {
|
|
|
135
124
|
this.#requestPaint();
|
|
136
125
|
}
|
|
137
126
|
|
|
127
|
+
#scheduleTick(intervalMs: number, delayMs: number): void {
|
|
128
|
+
const timer = setTimeout(() => {
|
|
129
|
+
if (this.#intervalId !== timer) return;
|
|
130
|
+
const startedAt = performance.now();
|
|
131
|
+
const elapsed = startedAt - this.#lastSpinnerTick;
|
|
132
|
+
const shouldAdvanceSpinner = elapsed >= SPINNER_ADVANCE_MS;
|
|
133
|
+
if (shouldAdvanceSpinner) {
|
|
134
|
+
const steps = Math.floor(elapsed / SPINNER_ADVANCE_MS);
|
|
135
|
+
this.#currentFrame = (this.#currentFrame + steps) % this.#frames.length;
|
|
136
|
+
this.#lastSpinnerTick += steps * SPINNER_ADVANCE_MS;
|
|
137
|
+
this.#syncText();
|
|
138
|
+
}
|
|
139
|
+
if (shouldAdvanceSpinner || this.#ui?.synchronizedOutput === true) {
|
|
140
|
+
this.#requestPaint();
|
|
141
|
+
}
|
|
142
|
+
|
|
143
|
+
const frameCostMs = performance.now() - startedAt;
|
|
144
|
+
if (this.#intervalId !== timer) return;
|
|
145
|
+
const cadenceDelayMs = Math.max(0, intervalMs - frameCostMs);
|
|
146
|
+
// Idle for nine times the paint cost to keep animation at or below
|
|
147
|
+
// 10% CPU, while cheap frames retain their original cadence.
|
|
148
|
+
const backpressureDelayMs = Math.min(MAX_RENDER_BACKPRESSURE_MS, frameCostMs * RENDER_BACKPRESSURE_MULTIPLIER);
|
|
149
|
+
this.#scheduleTick(intervalMs, Math.max(cadenceDelayMs, backpressureDelayMs));
|
|
150
|
+
}, delayMs);
|
|
151
|
+
this.#intervalId = timer;
|
|
152
|
+
}
|
|
138
153
|
/** Re-wrap the underlying Text only when its message or frame width changes. */
|
|
139
154
|
#syncText(): boolean {
|
|
140
155
|
const layoutFrame = this.#layoutFrames[this.#currentFrame];
|
package/src/terminal.ts
CHANGED
|
@@ -404,7 +404,7 @@ export interface Terminal {
|
|
|
404
404
|
// Whether Kitty keyboard protocol is active
|
|
405
405
|
get kittyProtocolActive(): boolean;
|
|
406
406
|
|
|
407
|
-
// The exact kitty keyboard push sequence in effect ("\x1b[>
|
|
407
|
+
// The exact kitty keyboard push sequence in effect ("\x1b[>5u" or "\x1b[>7u"),
|
|
408
408
|
// or null when the protocol is not active. Kitty keyboard flags are per-screen,
|
|
409
409
|
// so the TUI re-pushes this after entering the alternate screen.
|
|
410
410
|
get kittyEnableSequence(): string | null;
|
|
@@ -1100,15 +1100,15 @@ export class ProcessTerminal implements Terminal {
|
|
|
1100
1100
|
const reportedFlags = parseInt(match[1]!, 10);
|
|
1101
1101
|
this.#kittyProtocolActive = true;
|
|
1102
1102
|
setKittyProtocolActive(true);
|
|
1103
|
-
if (reportedFlags
|
|
1104
|
-
//
|
|
1105
|
-
// Push level-2 to
|
|
1103
|
+
if ((reportedFlags & 2) !== 0) {
|
|
1104
|
+
// Preserve event-type reporting already enabled by a parent app.
|
|
1105
|
+
// Push level-2 to keep its shortcuts reporting consistently.
|
|
1106
1106
|
this.#kittyEnableSeq = "\x1b[>7u";
|
|
1107
1107
|
this.#safeWrite(this.#kittyEnableSeq);
|
|
1108
1108
|
} else {
|
|
1109
|
-
//
|
|
1110
|
-
// without
|
|
1111
|
-
this.#kittyEnableSeq = "\x1b[>
|
|
1109
|
+
// Disambiguate escape codes and report base-layout keys for physical
|
|
1110
|
+
// shortcut matching, without event reporting that caused regression #3259.
|
|
1111
|
+
this.#kittyEnableSeq = "\x1b[>5u";
|
|
1112
1112
|
this.#safeWrite(this.#kittyEnableSeq);
|
|
1113
1113
|
}
|
|
1114
1114
|
return;
|