@xynogen/pix-pretty 1.15.0 → 1.16.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/package.json +1 -1
- package/src/types.ts +3 -1
- package/src/utils.test.ts +26 -0
- package/src/utils.ts +49 -0
package/package.json
CHANGED
package/src/types.ts
CHANGED
|
@@ -42,9 +42,11 @@ export type ToolContent = TextContent | ImageContent;
|
|
|
42
42
|
|
|
43
43
|
export type ToolResultLike<TDetails = unknown> = AgentToolResult<TDetails | undefined>;
|
|
44
44
|
|
|
45
|
-
type TextComponentLike = {
|
|
45
|
+
export type TextComponentLike = {
|
|
46
46
|
setText(value: string): void;
|
|
47
47
|
getText?: () => string;
|
|
48
|
+
render?: (width: number) => string[];
|
|
49
|
+
invalidate?: () => void;
|
|
48
50
|
};
|
|
49
51
|
|
|
50
52
|
export type TextComponentCtor = new (text?: string, x?: number, y?: number) => TextComponentLike;
|
package/src/utils.test.ts
CHANGED
|
@@ -4,6 +4,7 @@ import { MAX_PREVIEW_LINES } from "./config.js";
|
|
|
4
4
|
import type { FgTheme } from "./types.js";
|
|
5
5
|
import {
|
|
6
6
|
dotJoin,
|
|
7
|
+
fillToolBackground,
|
|
7
8
|
formatCollapsedToolRow,
|
|
8
9
|
formatJson,
|
|
9
10
|
hideCollapsedToolCall,
|
|
@@ -13,8 +14,33 @@ import {
|
|
|
13
14
|
renderDimPreview,
|
|
14
15
|
ruleFrame,
|
|
15
16
|
setResultDetails,
|
|
17
|
+
viewportText,
|
|
16
18
|
} from "./utils.js";
|
|
17
19
|
|
|
20
|
+
class MockTextComponent {
|
|
21
|
+
private text = "";
|
|
22
|
+
|
|
23
|
+
setText(value: string): void {
|
|
24
|
+
this.text = value;
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
render(): string[] {
|
|
28
|
+
return this.text.split("\n");
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
invalidate(): void {}
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
describe("viewportText", () => {
|
|
35
|
+
it("trims a pre-filled row to Pi's narrower fullscreen viewport", () => {
|
|
36
|
+
const text = viewportText(MockTextComponent);
|
|
37
|
+
text.setText(fillToolBackground("tool", "", 10));
|
|
38
|
+
|
|
39
|
+
expect(plain(text.render(9)[0]!)).toBe("tool".padEnd(9));
|
|
40
|
+
expect(plain(text.render(10)[0]!)).toBe("tool".padEnd(10));
|
|
41
|
+
});
|
|
42
|
+
});
|
|
43
|
+
|
|
18
44
|
// Strip ANSI escapes so assertions test content, not color codes.
|
|
19
45
|
const ANSI = /\x1b\[[0-9;]*m/g;
|
|
20
46
|
function plain(text: string): string {
|
package/src/utils.ts
CHANGED
|
@@ -14,6 +14,8 @@ import {
|
|
|
14
14
|
import { MAX_PREVIEW_LINES } from "./config.js";
|
|
15
15
|
import type {
|
|
16
16
|
FgTheme,
|
|
17
|
+
TextComponentCtor,
|
|
18
|
+
TextComponentLike,
|
|
17
19
|
ToolContent,
|
|
18
20
|
ToolImageContent,
|
|
19
21
|
ToolResultLike,
|
|
@@ -48,6 +50,53 @@ export function fillToolBackground(text: string, bg = BG_BASE, width?: number):
|
|
|
48
50
|
.join("\n");
|
|
49
51
|
}
|
|
50
52
|
|
|
53
|
+
export function viewportTextConstructor(TextComponent: TextComponentCtor): TextComponentCtor {
|
|
54
|
+
return function ViewportTextComponent(text = "") {
|
|
55
|
+
const component = viewportText(TextComponent);
|
|
56
|
+
component.setText(text);
|
|
57
|
+
return component;
|
|
58
|
+
} as unknown as TextComponentCtor;
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
export function viewportText(
|
|
62
|
+
TextComponent: TextComponentCtor,
|
|
63
|
+
): TextComponentLike & ViewportComponent {
|
|
64
|
+
return new ViewportText(new TextComponent("", 0, 0));
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
type ViewportComponent = {
|
|
68
|
+
render(width: number): string[];
|
|
69
|
+
invalidate(): void;
|
|
70
|
+
};
|
|
71
|
+
|
|
72
|
+
class ViewportText implements TextComponentLike, ViewportComponent {
|
|
73
|
+
private text = "";
|
|
74
|
+
|
|
75
|
+
constructor(private readonly component: TextComponentLike) {}
|
|
76
|
+
|
|
77
|
+
setText(value: string): void {
|
|
78
|
+
this.text = value;
|
|
79
|
+
this.component.setText(value);
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
getText(): string {
|
|
83
|
+
return this.text;
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
render(width: number): string[] {
|
|
87
|
+
const fitted = this.text
|
|
88
|
+
.split("\n")
|
|
89
|
+
.map((line) => truncateToWidth(line, width, ""))
|
|
90
|
+
.join("\n");
|
|
91
|
+
this.component.setText(fitted);
|
|
92
|
+
return this.component.render?.(width) ?? fitted.split("\n");
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
invalidate(): void {
|
|
96
|
+
this.component.invalidate?.();
|
|
97
|
+
}
|
|
98
|
+
}
|
|
99
|
+
|
|
51
100
|
export function pluralize(count: number, noun: string, plural?: string): string {
|
|
52
101
|
return `${count} ${count === 1 ? noun : (plural ?? `${noun}s`)}`;
|
|
53
102
|
}
|