pi-cc-extensions 0.8.59 → 0.8.61
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/README.en.md +2 -1
- package/README.md +2 -1
- package/extensions/config/config.ts +19 -0
- package/extensions/config/panel.ts +26 -3
- package/extensions/feature/compact-thinking.ts +211 -22
- package/extensions/feature/context.ts +150 -115
- package/extensions/renderer/compact-mode.ts +112 -43
- package/extensions/renderer/default-mode.ts +19 -2
- package/extensions/renderer/markdown-enhance.ts +40 -2
- package/extensions/renderer/mouse/hover.ts +14 -0
- package/extensions/renderer/mouse/interaction.ts +9 -1
- package/extensions/renderer/mouse/layout.ts +6 -1
- package/extensions/renderer/tool/diff/diff-component.ts +1 -0
- package/extensions/renderer/tool/diff/diff-limits.ts +15 -1
- package/extensions/renderer/tool/diff/diff-write-render.ts +62 -2
- package/extensions/renderer/tool/grouping.ts +58 -1
- package/package.json +1 -1
package/README.en.md
CHANGED
|
@@ -56,7 +56,8 @@ Run `/reload` after installation.
|
|
|
56
56
|
"diffViewMode": "auto", // diff layout: auto / split / unified
|
|
57
57
|
"diffIndicatorMode": "bars", // diff change indicators: bars / classic / none
|
|
58
58
|
"diffSplitMinWidth": 120, // min terminal width before auto layout uses side-by-side columns
|
|
59
|
-
"diffCollapsedLines": 24, // diff body lines shown when collapsed; beyond that shows the expand hint (Ctrl+O / click)
|
|
59
|
+
"diffCollapsedLines": 24, // edit/diff body lines shown when collapsed; beyond that shows the expand hint (Ctrl+O / click)
|
|
60
|
+
"writeDiffCollapsedLines": 0, // write collapsed body lines; 0 = ↳ created • expand hint (stats stay on the title)
|
|
60
61
|
"diffWordWrap": true, // whether long diff lines wrap (otherwise truncated)
|
|
61
62
|
"expandedPreviewMaxLines": 40, // max body lines for expanded output/diff
|
|
62
63
|
"useSummaryTitlesAsThinkingTitle": true, // use the latest provider summary as the active thinking title
|
package/README.md
CHANGED
|
@@ -56,7 +56,8 @@ pi install git:github.com/minuque/pi-cc-extensions
|
|
|
56
56
|
"diffViewMode": "auto", // diff 布局:auto / split / unified
|
|
57
57
|
"diffIndicatorMode": "bars", // diff 变更指示:bars / classic / none
|
|
58
58
|
"diffSplitMinWidth": 120, // 自动布局下使用左右分栏的最小终端宽度
|
|
59
|
-
"diffCollapsedLines": 24, // 折叠时展示的 diff 行数,超出显示展开提示(Ctrl+O / 点击)
|
|
59
|
+
"diffCollapsedLines": 24, // 折叠时展示的 edit/diff 行数,超出显示展开提示(Ctrl+O / 点击)
|
|
60
|
+
"writeDiffCollapsedLines": 0, // write 折叠行数;0 = ↳ created • 展开提示(统计在标题)
|
|
60
61
|
"diffWordWrap": true, // 长 diff 行是否换行(否则截断)
|
|
61
62
|
"expandedPreviewMaxLines": 40, // 展开后输出/diff 正文的最大行数
|
|
62
63
|
"useSummaryTitlesAsThinkingTitle": true, // 用最新 provider 摘要作为思考标题
|
|
@@ -16,6 +16,8 @@ export interface ToolDisplayConfig {
|
|
|
16
16
|
diffIndicatorMode: DiffIndicatorMode;
|
|
17
17
|
diffSplitMinWidth: number;
|
|
18
18
|
diffCollapsedLines: number;
|
|
19
|
+
/** Write-only collapsed body lines. 0 = `↳ created • click to show more`. */
|
|
20
|
+
writeDiffCollapsedLines: number;
|
|
19
21
|
diffWordWrap: boolean;
|
|
20
22
|
expandedPreviewMaxLines: number;
|
|
21
23
|
}
|
|
@@ -26,6 +28,11 @@ export const DEFAULT_TOOL_DISPLAY_CONFIG: ToolDisplayConfig = {
|
|
|
26
28
|
diffSplitMinWidth: 120,
|
|
27
29
|
/** Collapsed tool/diff body: ~half a typical terminal after chrome. */
|
|
28
30
|
diffCollapsedLines: 24,
|
|
31
|
+
/**
|
|
32
|
+
* Write create/overwrite collapsed body.
|
|
33
|
+
* 0 = `↳ created • click to show more` (stats stay on the title).
|
|
34
|
+
*/
|
|
35
|
+
writeDiffCollapsedLines: 0,
|
|
29
36
|
diffWordWrap: true,
|
|
30
37
|
/**
|
|
31
38
|
* Expanded tool/diff body cap. 40 ≈ one screen of content after title,
|
|
@@ -42,6 +49,7 @@ export type Config = {
|
|
|
42
49
|
diffIndicatorMode: DiffIndicatorMode;
|
|
43
50
|
diffSplitMinWidth: number;
|
|
44
51
|
diffCollapsedLines: number;
|
|
52
|
+
writeDiffCollapsedLines: number;
|
|
45
53
|
diffWordWrap: boolean;
|
|
46
54
|
expandedPreviewMaxLines: number;
|
|
47
55
|
useSummaryTitlesAsThinkingTitle: boolean;
|
|
@@ -64,6 +72,8 @@ export const DIFF_VIEW_MODES: DiffViewMode[] = ["auto", "split", "unified"];
|
|
|
64
72
|
export const DIFF_INDICATOR_MODES: DiffIndicatorMode[] = ["bars", "classic", "none"];
|
|
65
73
|
export const DIFF_SPLIT_MIN_WIDTH_VALUES = ["80", "100", "120", "140", "160", "180"];
|
|
66
74
|
export const DIFF_COLLAPSED_LINES_VALUES = ["12", "24", "36", "48", "80", "120"];
|
|
75
|
+
/** Write collapsed presets. 0 = stats only (`+N -0` + expand hint). */
|
|
76
|
+
export const WRITE_DIFF_COLLAPSED_LINES_VALUES = ["0", "4", "8", "12", "24", "36"];
|
|
67
77
|
/** Presets for expanded body height — keep low options first so cycling stays TUI-friendly. */
|
|
68
78
|
export const EXPANDED_PREVIEW_MAX_LINES_VALUES = ["40", "60", "80", "120", "200", "500", "2000"];
|
|
69
79
|
export const THINKING_PREVIEW_LINES_VALUES = ["0", "1", "3", "5", "10"];
|
|
@@ -90,6 +100,7 @@ export const DEFAULT_CONFIG: Config = {
|
|
|
90
100
|
diffIndicatorMode: DEFAULT_TOOL_DISPLAY_CONFIG.diffIndicatorMode,
|
|
91
101
|
diffSplitMinWidth: DEFAULT_TOOL_DISPLAY_CONFIG.diffSplitMinWidth,
|
|
92
102
|
diffCollapsedLines: DEFAULT_TOOL_DISPLAY_CONFIG.diffCollapsedLines,
|
|
103
|
+
writeDiffCollapsedLines: DEFAULT_TOOL_DISPLAY_CONFIG.writeDiffCollapsedLines,
|
|
93
104
|
diffWordWrap: DEFAULT_TOOL_DISPLAY_CONFIG.diffWordWrap,
|
|
94
105
|
expandedPreviewMaxLines: DEFAULT_TOOL_DISPLAY_CONFIG.expandedPreviewMaxLines,
|
|
95
106
|
useSummaryTitlesAsThinkingTitle: true,
|
|
@@ -164,6 +175,12 @@ export function normalizeConfig(input: unknown): Config {
|
|
|
164
175
|
1,
|
|
165
176
|
500,
|
|
166
177
|
),
|
|
178
|
+
writeDiffCollapsedLines: pickPositiveInt(
|
|
179
|
+
source.writeDiffCollapsedLines,
|
|
180
|
+
DEFAULT_CONFIG.writeDiffCollapsedLines,
|
|
181
|
+
0,
|
|
182
|
+
500,
|
|
183
|
+
),
|
|
167
184
|
diffWordWrap: source.diffWordWrap !== false,
|
|
168
185
|
expandedPreviewMaxLines: pickPositiveInt(
|
|
169
186
|
source.expandedPreviewMaxLines,
|
|
@@ -207,6 +224,7 @@ export function getToolDisplayConfig(source: Config = config): ToolDisplayConfig
|
|
|
207
224
|
diffIndicatorMode: source.diffIndicatorMode,
|
|
208
225
|
diffSplitMinWidth: source.diffSplitMinWidth,
|
|
209
226
|
diffCollapsedLines: source.diffCollapsedLines,
|
|
227
|
+
writeDiffCollapsedLines: source.writeDiffCollapsedLines,
|
|
210
228
|
diffWordWrap: source.diffWordWrap,
|
|
211
229
|
expandedPreviewMaxLines: source.expandedPreviewMaxLines,
|
|
212
230
|
};
|
|
@@ -224,6 +242,7 @@ export function formatConfigStatus(source: Config = config): string {
|
|
|
224
242
|
`diffIndicator=${source.diffIndicatorMode}`,
|
|
225
243
|
`diffSplitMin=${source.diffSplitMinWidth}`,
|
|
226
244
|
`diffCollapsed=${source.diffCollapsedLines}`,
|
|
245
|
+
`writeCollapsed=${source.writeDiffCollapsedLines}`,
|
|
227
246
|
`diffWordWrap=${source.diffWordWrap ? "on" : "off"}`,
|
|
228
247
|
`expandedMax=${source.expandedPreviewMaxLines}`,
|
|
229
248
|
`thinkingTitle=${source.useSummaryTitlesAsThinkingTitle ? "summary" : "default"}`,
|
|
@@ -25,6 +25,7 @@ import {
|
|
|
25
25
|
SCROLL_STEP_LINES_VALUES,
|
|
26
26
|
THINKING_ANIMATION_INTERVAL_VALUES,
|
|
27
27
|
THINKING_PREVIEW_LINES_VALUES,
|
|
28
|
+
WRITE_DIFF_COLLAPSED_LINES_VALUES,
|
|
28
29
|
updateConfig,
|
|
29
30
|
type CompactStyleMode,
|
|
30
31
|
type Config,
|
|
@@ -40,7 +41,7 @@ export type CcstylePanelHooks = {
|
|
|
40
41
|
|
|
41
42
|
function modeSettingDescription(mode: CompactStyleMode): string {
|
|
42
43
|
if (mode === "compact") {
|
|
43
|
-
return "(Experimental) One summary line per assistant round;
|
|
44
|
+
return "(Experimental) One summary line per assistant round; edit/write reuse the same Diff preview settings as on.";
|
|
44
45
|
}
|
|
45
46
|
if (mode === "off") {
|
|
46
47
|
return "Pi native tool rendering. Diff options below still apply independently.";
|
|
@@ -288,14 +289,24 @@ export async function showCcstylePanel(
|
|
|
288
289
|
};
|
|
289
290
|
const diffCollapsedSetting = {
|
|
290
291
|
id: "diffCollapsedLines",
|
|
291
|
-
label: "
|
|
292
|
+
label: "Edit collapsed lines",
|
|
292
293
|
description:
|
|
293
|
-
"How many diff body lines to show before the expand hint (Ctrl+O / click).
|
|
294
|
+
"How many edit/diff body lines to show before the expand hint (Ctrl+O / click). Write uses its own setting below.",
|
|
294
295
|
currentValue: String(config.diffCollapsedLines),
|
|
295
296
|
values: [...DIFF_COLLAPSED_LINES_VALUES],
|
|
296
297
|
submenu: (_current: string, closeSubmenu: (selected?: string) => void) =>
|
|
297
298
|
buildNumberInputSubmenu(theme, diffCollapsedSetting, closeSubmenu),
|
|
298
299
|
};
|
|
300
|
+
const writeDiffCollapsedSetting = {
|
|
301
|
+
id: "writeDiffCollapsedLines",
|
|
302
|
+
label: "Write collapsed lines",
|
|
303
|
+
description:
|
|
304
|
+
"Write-only collapsed body lines. 0 shows ↳ created + expand hint (stats stay on the title). Enter to type a custom value.",
|
|
305
|
+
currentValue: String(config.writeDiffCollapsedLines),
|
|
306
|
+
values: [...WRITE_DIFF_COLLAPSED_LINES_VALUES],
|
|
307
|
+
submenu: (_current: string, closeSubmenu: (selected?: string) => void) =>
|
|
308
|
+
buildNumberInputSubmenu(theme, writeDiffCollapsedSetting, closeSubmenu),
|
|
309
|
+
};
|
|
299
310
|
const diffWordWrapSetting = {
|
|
300
311
|
id: "diffWordWrap",
|
|
301
312
|
label: "Diff word wrap",
|
|
@@ -453,6 +464,17 @@ export async function showCcstylePanel(
|
|
|
453
464
|
});
|
|
454
465
|
diffCollapsedSetting.currentValue = String(config.diffCollapsedLines);
|
|
455
466
|
break;
|
|
467
|
+
case "writeDiffCollapsedLines":
|
|
468
|
+
updateConfig({
|
|
469
|
+
writeDiffCollapsedLines: pickPositiveInt(
|
|
470
|
+
value,
|
|
471
|
+
DEFAULT_CONFIG.writeDiffCollapsedLines,
|
|
472
|
+
0,
|
|
473
|
+
500,
|
|
474
|
+
),
|
|
475
|
+
});
|
|
476
|
+
writeDiffCollapsedSetting.currentValue = String(config.writeDiffCollapsedLines);
|
|
477
|
+
break;
|
|
456
478
|
case "diffWordWrap":
|
|
457
479
|
updateConfig({ diffWordWrap: value === "on" });
|
|
458
480
|
diffWordWrapSetting.description = config.diffWordWrap
|
|
@@ -519,6 +541,7 @@ export async function showCcstylePanel(
|
|
|
519
541
|
diffIndicatorSetting,
|
|
520
542
|
diffSplitSetting,
|
|
521
543
|
diffCollapsedSetting,
|
|
544
|
+
writeDiffCollapsedSetting,
|
|
522
545
|
diffWordWrapSetting,
|
|
523
546
|
expandedMaxSetting,
|
|
524
547
|
],
|
|
@@ -11,8 +11,14 @@ import {
|
|
|
11
11
|
type ExtensionAPI,
|
|
12
12
|
type Theme,
|
|
13
13
|
} from "@earendil-works/pi-coding-agent";
|
|
14
|
-
import {
|
|
15
|
-
|
|
14
|
+
import {
|
|
15
|
+
getKeybindings,
|
|
16
|
+
truncateToWidth,
|
|
17
|
+
visibleWidth,
|
|
18
|
+
wrapTextWithAnsi,
|
|
19
|
+
} from "@earendil-works/pi-tui";
|
|
20
|
+
import { Box, Markdown, Spacer, Text, type Component } from "@earendil-works/pi-tui";
|
|
21
|
+
import { isToolTuiFullscreen } from "../renderer/tool/show-more-hint.ts";
|
|
16
22
|
import {
|
|
17
23
|
animateCompactThinkingText,
|
|
18
24
|
formatThoughtDuration,
|
|
@@ -163,27 +169,206 @@ function getThinkingToggleHint() {
|
|
|
163
169
|
return keys.length > 0 ? `${keys.join("/")} to expand` : undefined;
|
|
164
170
|
}
|
|
165
171
|
|
|
166
|
-
|
|
172
|
+
function thinkingExpandAction(): string | undefined {
|
|
173
|
+
return isToolTuiFullscreen() ? "click to show more" : getThinkingToggleHint();
|
|
174
|
+
}
|
|
175
|
+
|
|
176
|
+
// 只 wrap 尾部窗口;缓存未着色折行,着色放到取出时做,避免主题切换命中旧 ANSI。
|
|
177
|
+
const previewCache = new Map<string, { lines: string[]; hiddenBefore: number }>();
|
|
178
|
+
const PREVIEW_CACHE_MAX = 500;
|
|
179
|
+
const PREVIEW_BUDGET_MIN_CHARS = 2_000;
|
|
180
|
+
const PREVIEW_BUDGET_SLACK_LINES = 2;
|
|
181
|
+
|
|
182
|
+
/** 按可见宽度估算折行数,不走 Text 全量 wrap。无换行长段也能计到隐藏行。 */
|
|
183
|
+
function countWrappedLines(text: string, contentWidth: number): number {
|
|
184
|
+
if (!text) return 0;
|
|
185
|
+
const width = Math.max(1, contentWidth);
|
|
186
|
+
let lines = 0;
|
|
187
|
+
for (const raw of text.replace(/\t/g, " ").split(/\r\n|\r|\n/)) {
|
|
188
|
+
const w = visibleWidth(raw);
|
|
189
|
+
lines += w === 0 ? 1 : Math.ceil(w / width);
|
|
190
|
+
}
|
|
191
|
+
return lines;
|
|
192
|
+
}
|
|
193
|
+
|
|
194
|
+
function padPreviewLine(line: string, width: number, padding: number): string {
|
|
195
|
+
const left = padding > 0 ? " ".repeat(padding) : "";
|
|
196
|
+
const right = padding > 0 ? " ".repeat(padding) : "";
|
|
197
|
+
const withMargins = left + line + right;
|
|
198
|
+
return withMargins + " ".repeat(Math.max(0, width - visibleWidth(withMargins)));
|
|
199
|
+
}
|
|
200
|
+
|
|
201
|
+
function layoutThinkingPreview(
|
|
202
|
+
text: string,
|
|
203
|
+
width: number,
|
|
204
|
+
padding: number,
|
|
205
|
+
): { visible: string[]; hiddenLines: number } {
|
|
206
|
+
if (!text || config.previewLines <= 0) return { visible: [], hiddenLines: 0 };
|
|
207
|
+
const contentWidth = Math.max(1, width - padding * 2);
|
|
208
|
+
const budget = Math.max(
|
|
209
|
+
width * (config.previewLines + PREVIEW_BUDGET_SLACK_LINES),
|
|
210
|
+
PREVIEW_BUDGET_MIN_CHARS,
|
|
211
|
+
);
|
|
212
|
+
let source = text;
|
|
213
|
+
let cut = 0;
|
|
214
|
+
if (source.length > budget) {
|
|
215
|
+
const start = source.length - budget;
|
|
216
|
+
const newline = source.indexOf("\n", start);
|
|
217
|
+
cut = newline === -1 ? start : newline + 1;
|
|
218
|
+
if (cut < source.length) source = source.slice(cut);
|
|
219
|
+
else cut = 0;
|
|
220
|
+
}
|
|
221
|
+
const cacheKey = `${width}:${padding}:${cut}:${source}`;
|
|
222
|
+
let entry = previewCache.get(cacheKey);
|
|
223
|
+
if (!entry) {
|
|
224
|
+
entry = {
|
|
225
|
+
lines: wrapTextWithAnsi(source.replace(/\t/g, " "), contentWidth),
|
|
226
|
+
hiddenBefore: cut > 0 ? countWrappedLines(text.slice(0, cut), contentWidth) : 0,
|
|
227
|
+
};
|
|
228
|
+
if (previewCache.size >= PREVIEW_CACHE_MAX) previewCache.clear();
|
|
229
|
+
previewCache.set(cacheKey, entry);
|
|
230
|
+
}
|
|
231
|
+
const hiddenLines = entry.hiddenBefore + Math.max(0, entry.lines.length - config.previewLines);
|
|
232
|
+
const visible = hiddenLines > 0 ? entry.lines.slice(-config.previewLines) : entry.lines;
|
|
233
|
+
return { visible, hiddenLines };
|
|
234
|
+
}
|
|
235
|
+
|
|
236
|
+
function hiddenPreviewHint(
|
|
237
|
+
hiddenLines: number,
|
|
238
|
+
forceExpandHint = false,
|
|
239
|
+
): { prefix: string; action: string; suffix: string } | undefined {
|
|
240
|
+
const action = thinkingExpandAction() ?? "";
|
|
241
|
+
if (hiddenLines > 0) {
|
|
242
|
+
const noun = hiddenLines === 1 ? "line" : "lines";
|
|
243
|
+
return {
|
|
244
|
+
prefix: ` • (${hiddenLines} more ${noun}${action ? ", " : ""}`,
|
|
245
|
+
action,
|
|
246
|
+
suffix: ")",
|
|
247
|
+
};
|
|
248
|
+
}
|
|
249
|
+
if (forceExpandHint && isToolTuiFullscreen()) {
|
|
250
|
+
return { prefix: " • ", action: "click to show more", suffix: "" };
|
|
251
|
+
}
|
|
252
|
+
return undefined;
|
|
253
|
+
}
|
|
254
|
+
|
|
255
|
+
const expandedThinking = new Set<number>();
|
|
256
|
+
|
|
257
|
+
/** 折叠预览 + 展开全文。fullscreen 点击 hint 展开、再点整块收起,对齐工具卡。 */
|
|
258
|
+
export class ThinkingPreviewBlock implements Component {
|
|
259
|
+
private heading: string;
|
|
167
260
|
private text: string;
|
|
168
261
|
private padding: number;
|
|
262
|
+
private messageTimestamp: number;
|
|
169
263
|
private style: (text: string) => string;
|
|
170
|
-
|
|
171
|
-
|
|
264
|
+
private theme: Theme | undefined;
|
|
265
|
+
private _expanded: boolean;
|
|
266
|
+
private hintHovered = false;
|
|
267
|
+
private expandedBody: { width: number; lines: string[] } | undefined;
|
|
268
|
+
|
|
269
|
+
constructor(
|
|
270
|
+
heading: string,
|
|
271
|
+
text: string,
|
|
272
|
+
padding: number,
|
|
273
|
+
messageTimestamp: number,
|
|
274
|
+
style: (text: string) => string,
|
|
275
|
+
theme?: Theme,
|
|
276
|
+
) {
|
|
277
|
+
this.heading = heading;
|
|
172
278
|
this.text = text;
|
|
173
279
|
this.padding = padding;
|
|
280
|
+
this.messageTimestamp = messageTimestamp;
|
|
174
281
|
this.style = style;
|
|
282
|
+
this.theme = theme;
|
|
283
|
+
this._expanded = expandedThinking.has(messageTimestamp);
|
|
175
284
|
}
|
|
176
285
|
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
286
|
+
private paint(color: string, text: string): string {
|
|
287
|
+
return this.theme && typeof this.theme.fg === "function"
|
|
288
|
+
? this.theme.fg(color as never, text)
|
|
289
|
+
: text;
|
|
290
|
+
}
|
|
180
291
|
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
292
|
+
get expanded(): boolean {
|
|
293
|
+
return this._expanded;
|
|
294
|
+
}
|
|
295
|
+
|
|
296
|
+
setExpanded(expanded: boolean): void {
|
|
297
|
+
this._expanded = expanded;
|
|
298
|
+
if (expanded) expandedThinking.add(this.messageTimestamp);
|
|
299
|
+
else {
|
|
300
|
+
expandedThinking.delete(this.messageTimestamp);
|
|
301
|
+
this.expandedBody = undefined;
|
|
302
|
+
}
|
|
303
|
+
}
|
|
304
|
+
|
|
305
|
+
setHintHovered(hovered: boolean): void {
|
|
306
|
+
this.hintHovered = hovered;
|
|
307
|
+
}
|
|
308
|
+
|
|
309
|
+
private headingLines(width: number, hiddenLines: number, padding: number): string[] {
|
|
310
|
+
const hint = this._expanded
|
|
311
|
+
? undefined
|
|
312
|
+
: hiddenPreviewHint(hiddenLines, Boolean(this.text) && config.previewLines <= 0);
|
|
313
|
+
if (!hint) return new Text(this.heading, padding, 0).render(width);
|
|
314
|
+
const rawHint = hint.prefix + hint.action + hint.suffix;
|
|
315
|
+
const contentWidth = Math.max(1, width - padding * 2);
|
|
316
|
+
const headingBudget = Math.max(0, contentWidth - visibleWidth(rawHint));
|
|
317
|
+
const clipped =
|
|
318
|
+
visibleWidth(this.heading) > headingBudget
|
|
319
|
+
? truncateToWidth(this.heading, headingBudget, "")
|
|
320
|
+
: this.heading;
|
|
321
|
+
const action = this.paint(this.hintHovered ? "text" : "dim", hint.action);
|
|
322
|
+
return new Text(
|
|
323
|
+
clipped + this.paint("dim", hint.prefix) + action + this.paint("dim", hint.suffix),
|
|
324
|
+
padding,
|
|
325
|
+
0,
|
|
326
|
+
).render(width);
|
|
327
|
+
}
|
|
328
|
+
|
|
329
|
+
private bodyLines(width: number, padding: number): { lines: string[]; hiddenLines: number } {
|
|
330
|
+
if (!this.text || (config.previewLines <= 0 && !this._expanded)) {
|
|
331
|
+
return { lines: [], hiddenLines: 0 };
|
|
332
|
+
}
|
|
333
|
+
if (this._expanded) {
|
|
334
|
+
if (this.expandedBody?.width !== width) {
|
|
335
|
+
this.expandedBody = {
|
|
336
|
+
width,
|
|
337
|
+
lines: wrapTextWithAnsi(this.text.replace(/\t/g, " "), Math.max(1, width)),
|
|
338
|
+
};
|
|
339
|
+
}
|
|
340
|
+
return { lines: this.expandedBody.lines, hiddenLines: 0 };
|
|
341
|
+
}
|
|
342
|
+
const preview = layoutThinkingPreview(this.text, width, padding);
|
|
343
|
+
return { lines: preview.visible, hiddenLines: preview.hiddenLines };
|
|
344
|
+
}
|
|
345
|
+
|
|
346
|
+
render(width: number) {
|
|
347
|
+
if (this._expanded) {
|
|
348
|
+
const innerWidth = Math.max(1, width - 2);
|
|
349
|
+
const body = this.bodyLines(innerWidth, 0);
|
|
350
|
+
const heading = this.headingLines(innerWidth, 0, 0);
|
|
351
|
+
const inner = body.lines.length
|
|
352
|
+
? [...heading, ...body.lines.map((line) => this.style(line))]
|
|
353
|
+
: heading;
|
|
354
|
+
const bgFn =
|
|
355
|
+
this.theme && typeof this.theme.bg === "function"
|
|
356
|
+
? (text: string) => this.theme!.bg("userMessageBg" as never, text)
|
|
357
|
+
: undefined;
|
|
358
|
+
const box = new Box(1, 1, bgFn);
|
|
359
|
+
box.addChild({
|
|
360
|
+
render: () => inner,
|
|
361
|
+
invalidate() {},
|
|
362
|
+
});
|
|
363
|
+
return box.render(width);
|
|
364
|
+
}
|
|
365
|
+
const body = this.bodyLines(width, this.padding);
|
|
366
|
+
const heading = this.headingLines(width, body.hiddenLines, this.padding);
|
|
367
|
+
if (!body.lines.length) return heading;
|
|
368
|
+
return [
|
|
369
|
+
...heading,
|
|
370
|
+
...body.lines.map((line) => padPreviewLine(this.style(line), width, this.padding)),
|
|
371
|
+
];
|
|
187
372
|
}
|
|
188
373
|
|
|
189
374
|
invalidate() {}
|
|
@@ -461,14 +646,17 @@ function compactThinking(pi: ExtensionAPI) {
|
|
|
461
646
|
durationText ? `Thought for ${durationText}` : (latestSummary?.title ?? "Thought"),
|
|
462
647
|
);
|
|
463
648
|
}
|
|
464
|
-
|
|
465
|
-
|
|
466
|
-
|
|
467
|
-
|
|
468
|
-
|
|
469
|
-
|
|
470
|
-
|
|
471
|
-
|
|
649
|
+
const previewSource = (latestSummary?.body ?? thinkingBlocks.join("\n\n")).trim();
|
|
650
|
+
self.contentContainer.addChild(
|
|
651
|
+
new ThinkingPreviewBlock(
|
|
652
|
+
heading,
|
|
653
|
+
previewSource,
|
|
654
|
+
self.outputPad,
|
|
655
|
+
message.timestamp,
|
|
656
|
+
thinkingStyle,
|
|
657
|
+
activeTheme,
|
|
658
|
+
),
|
|
659
|
+
);
|
|
472
660
|
|
|
473
661
|
const hasVisibleContentAfter = message.content
|
|
474
662
|
.slice(i + 1)
|
|
@@ -733,6 +921,7 @@ function compactThinking(pi: ExtensionAPI) {
|
|
|
733
921
|
latestComponentTimestamp = undefined;
|
|
734
922
|
completedDurations.clear();
|
|
735
923
|
streamingComponents.clear();
|
|
924
|
+
expandedThinking.clear();
|
|
736
925
|
if (ctx.mode === "tui") ctx.ui.setWidget(WIDGET_ID, undefined);
|
|
737
926
|
|
|
738
927
|
if (patchInstalled) {
|