@danypops/pi-packed 0.21.0 → 0.21.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.
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
import type { Component } from "malevich-tui-components";
|
|
2
|
+
|
|
3
|
+
/** Keeps a component failure inside its overlay instead of Pi's event loop. */
|
|
4
|
+
export class TuiErrorBoundary implements Component {
|
|
5
|
+
private failed = false;
|
|
6
|
+
|
|
7
|
+
constructor(
|
|
8
|
+
private readonly component: Component,
|
|
9
|
+
private readonly fallback: readonly string[],
|
|
10
|
+
private readonly onError?: () => void,
|
|
11
|
+
) {}
|
|
12
|
+
|
|
13
|
+
render(width: number): string[] {
|
|
14
|
+
if (this.failed) return this.renderFallback(width);
|
|
15
|
+
try {
|
|
16
|
+
return this.component.render(width);
|
|
17
|
+
} catch {
|
|
18
|
+
this.fail();
|
|
19
|
+
return this.renderFallback(width);
|
|
20
|
+
}
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
invalidate(): void {
|
|
24
|
+
if (this.failed) return;
|
|
25
|
+
try {
|
|
26
|
+
this.component.invalidate();
|
|
27
|
+
} catch {
|
|
28
|
+
this.fail();
|
|
29
|
+
}
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
handleInput(data: string): void {
|
|
33
|
+
if (this.failed) return;
|
|
34
|
+
try {
|
|
35
|
+
this.component.handleInput?.(data);
|
|
36
|
+
} catch {
|
|
37
|
+
this.fail();
|
|
38
|
+
}
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
private fail(): void {
|
|
42
|
+
if (this.failed) return;
|
|
43
|
+
this.failed = true;
|
|
44
|
+
this.onError?.();
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
private renderFallback(width: number): string[] {
|
|
48
|
+
const boundedWidth = Math.max(0, width);
|
|
49
|
+
return this.fallback.map((line) => line.slice(0, boundedWidth));
|
|
50
|
+
}
|
|
51
|
+
}
|
package/extension/src/tui.ts
CHANGED
|
@@ -67,6 +67,7 @@ import { createFindTab } from "./tabs/discover.js";
|
|
|
67
67
|
import { applyResourceToggle, ConfigTab } from "./tabs/resource-config.js";
|
|
68
68
|
import { SettingsTab } from "./tabs/security-tui.js";
|
|
69
69
|
import { approvePackageOperation } from "./tools.js";
|
|
70
|
+
import { TuiErrorBoundary } from "./tui-error-boundary.js";
|
|
70
71
|
|
|
71
72
|
export type PackedTabKey = "packages" | "find" | "config" | "settings";
|
|
72
73
|
|
|
@@ -859,7 +860,7 @@ function renderUnifiedPanel(
|
|
|
859
860
|
measure,
|
|
860
861
|
});
|
|
861
862
|
|
|
862
|
-
|
|
863
|
+
const panel: Component = {
|
|
863
864
|
render(width: number): string[] {
|
|
864
865
|
envelope.setContent(pendingDialog ?? packageInspector ?? tabbedContainer);
|
|
865
866
|
return envelope.render(width);
|
|
@@ -929,6 +930,7 @@ function renderUnifiedPanel(
|
|
|
929
930
|
tui.requestRender();
|
|
930
931
|
},
|
|
931
932
|
};
|
|
933
|
+
return new TuiErrorBoundary(panel, ["Packed could not render.", "Restart Pi and run /packed again."], () => tui.requestRender());
|
|
932
934
|
// Pinned to the very top (anchor:"top-center"+offsetY:1 -- a fixed row
|
|
933
935
|
// count regardless of terminal size), not row:"40%". The percentage
|
|
934
936
|
// positioning was tried instead but reverted: pi-tui's row-percentage
|