@anthodev/pi-tools-style 0.1.2 → 0.1.3
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 +7 -2
- package/src/render-decorator.ts +68 -8
package/package.json
CHANGED
|
@@ -1,8 +1,13 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@anthodev/pi-tools-style",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.3",
|
|
4
4
|
"description": "Presentation-only boxes for Pi tool calls and shell commands",
|
|
5
|
-
"keywords": [
|
|
5
|
+
"keywords": [
|
|
6
|
+
"pi-package",
|
|
7
|
+
"pi-extension",
|
|
8
|
+
"tui",
|
|
9
|
+
"tools"
|
|
10
|
+
],
|
|
6
11
|
"type": "module",
|
|
7
12
|
"license": "MIT",
|
|
8
13
|
"repository": {
|
package/src/render-decorator.ts
CHANGED
|
@@ -34,6 +34,23 @@ interface StoredConfig extends Omit<RenderDecoratorConfig, "enabled"> {
|
|
|
34
34
|
enabled: boolean;
|
|
35
35
|
}
|
|
36
36
|
|
|
37
|
+
interface ResolvedFrameOptions {
|
|
38
|
+
options: FrameOptions;
|
|
39
|
+
styleSignature: string | undefined;
|
|
40
|
+
title: string | undefined;
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
interface RenderCacheEntry {
|
|
44
|
+
config: StoredConfig;
|
|
45
|
+
output: string[];
|
|
46
|
+
rendered: readonly string[];
|
|
47
|
+
styleSignature: string | undefined;
|
|
48
|
+
title: string | undefined;
|
|
49
|
+
width: number;
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
const BORDER_STYLE_PROBE = "╭─╮│╰─╯";
|
|
53
|
+
|
|
37
54
|
export function installRenderDecorator<T extends Renderable>(
|
|
38
55
|
component: RenderableConstructor<T>,
|
|
39
56
|
config: RenderDecoratorConfig<T>,
|
|
@@ -96,6 +113,8 @@ function createDecoratedRenderer(
|
|
|
96
113
|
key: symbol,
|
|
97
114
|
renderOriginal: RenderFunction,
|
|
98
115
|
): RenderFunction {
|
|
116
|
+
const cache = new WeakMap<Renderable, RenderCacheEntry>();
|
|
117
|
+
|
|
99
118
|
return function decoratedRender(width: number): string[] {
|
|
100
119
|
const current = readConfig(key);
|
|
101
120
|
if (!current?.enabled) return renderOriginal.call(this, width);
|
|
@@ -109,22 +128,38 @@ function createDecoratedRenderer(
|
|
|
109
128
|
}
|
|
110
129
|
|
|
111
130
|
try {
|
|
112
|
-
|
|
131
|
+
const resolved = resolveFrameOptions(this, current);
|
|
132
|
+
const cached = cache.get(this);
|
|
133
|
+
if (
|
|
134
|
+
cached?.config === current &&
|
|
135
|
+
cached.width === width &&
|
|
136
|
+
cached.title === resolved.title &&
|
|
137
|
+
cached.styleSignature === resolved.styleSignature &&
|
|
138
|
+
linesEqual(cached.rendered, rendered)
|
|
139
|
+
) {
|
|
140
|
+
return cached.output;
|
|
141
|
+
}
|
|
142
|
+
|
|
143
|
+
const output = decorateLines(rendered, width, current, resolved.options);
|
|
144
|
+
cache.set(this, {
|
|
145
|
+
config: current,
|
|
146
|
+
output,
|
|
147
|
+
rendered: [...rendered],
|
|
148
|
+
styleSignature: resolved.styleSignature,
|
|
149
|
+
title: resolved.title,
|
|
150
|
+
width,
|
|
151
|
+
});
|
|
152
|
+
return output;
|
|
113
153
|
} catch {
|
|
114
154
|
return renderOriginal.call(this, width);
|
|
115
155
|
}
|
|
116
156
|
};
|
|
117
157
|
}
|
|
118
158
|
|
|
119
|
-
function
|
|
159
|
+
function resolveFrameOptions(
|
|
120
160
|
instance: Renderable,
|
|
121
|
-
rendered: readonly string[],
|
|
122
|
-
width: number,
|
|
123
161
|
config: StoredConfig,
|
|
124
|
-
):
|
|
125
|
-
const lines = config.trimOuterRules
|
|
126
|
-
? trimOuterRules(rendered)
|
|
127
|
-
: [...rendered];
|
|
162
|
+
): ResolvedFrameOptions {
|
|
128
163
|
const title = config.title?.(instance);
|
|
129
164
|
const options: FrameOptions = {};
|
|
130
165
|
|
|
@@ -137,9 +172,34 @@ function decorateLines(
|
|
|
137
172
|
}
|
|
138
173
|
if (title) options.title = title;
|
|
139
174
|
|
|
175
|
+
return {
|
|
176
|
+
options,
|
|
177
|
+
// Theme providers can change border output without changing component content.
|
|
178
|
+
styleSignature: styleBorder?.(BORDER_STYLE_PROBE),
|
|
179
|
+
title,
|
|
180
|
+
};
|
|
181
|
+
}
|
|
182
|
+
|
|
183
|
+
function decorateLines(
|
|
184
|
+
rendered: readonly string[],
|
|
185
|
+
width: number,
|
|
186
|
+
config: StoredConfig,
|
|
187
|
+
options: FrameOptions,
|
|
188
|
+
): string[] {
|
|
189
|
+
const lines = config.trimOuterRules
|
|
190
|
+
? trimOuterRules(rendered)
|
|
191
|
+
: [...rendered];
|
|
192
|
+
|
|
140
193
|
return frameLines(lines, width, options);
|
|
141
194
|
}
|
|
142
195
|
|
|
196
|
+
function linesEqual(left: readonly string[], right: readonly string[]): boolean {
|
|
197
|
+
return (
|
|
198
|
+
left.length === right.length &&
|
|
199
|
+
left.every((line, index) => line === right[index])
|
|
200
|
+
);
|
|
201
|
+
}
|
|
202
|
+
|
|
143
203
|
function storeConfig<T extends Renderable>(
|
|
144
204
|
config: RenderDecoratorConfig<T>,
|
|
145
205
|
): void {
|