pi-cc-extensions 0.8.61 → 0.8.62
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 +1 -1
- package/README.md +1 -1
- package/extensions/config/config.ts +10 -10
- package/extensions/config/panel.ts +10 -5
- package/extensions/feature/compact-thinking.ts +72 -11
- package/extensions/feature/shell/model-status.ts +19 -0
- package/extensions/index.ts +2 -0
- package/extensions/renderer/compact-mode.ts +34 -18
- package/extensions/renderer/tool/diff/diff-component.ts +1 -1
- package/extensions/renderer/tool/diff/diff-edit-render.ts +2 -2
- package/extensions/renderer/tool/diff/diff-limits.ts +5 -5
- package/extensions/renderer/tool/grouping.ts +6 -0
- package/package.json +1 -1
package/README.en.md
CHANGED
|
@@ -56,7 +56,7 @@ 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
|
-
"
|
|
59
|
+
"editDiffCollapsedLines": 24, // Edit collapsed lines; beyond that shows the expand hint (Ctrl+O / click)
|
|
60
60
|
"writeDiffCollapsedLines": 0, // write collapsed body lines; 0 = ↳ created • expand hint (stats stay on the title)
|
|
61
61
|
"diffWordWrap": true, // whether long diff lines wrap (otherwise truncated)
|
|
62
62
|
"expandedPreviewMaxLines": 40, // max body lines for expanded output/diff
|
package/README.md
CHANGED
|
@@ -56,7 +56,7 @@ 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
|
-
"
|
|
59
|
+
"editDiffCollapsedLines": 24, // Edit 折叠行数;超出显示展开提示(Ctrl+O / 点击)
|
|
60
60
|
"writeDiffCollapsedLines": 0, // write 折叠行数;0 = ↳ created • 展开提示(统计在标题)
|
|
61
61
|
"diffWordWrap": true, // 长 diff 行是否换行(否则截断)
|
|
62
62
|
"expandedPreviewMaxLines": 40, // 展开后输出/diff 正文的最大行数
|
|
@@ -15,7 +15,7 @@ export interface ToolDisplayConfig {
|
|
|
15
15
|
diffViewMode: DiffViewMode;
|
|
16
16
|
diffIndicatorMode: DiffIndicatorMode;
|
|
17
17
|
diffSplitMinWidth: number;
|
|
18
|
-
|
|
18
|
+
editDiffCollapsedLines: number;
|
|
19
19
|
/** Write-only collapsed body lines. 0 = `↳ created • click to show more`. */
|
|
20
20
|
writeDiffCollapsedLines: number;
|
|
21
21
|
diffWordWrap: boolean;
|
|
@@ -26,8 +26,8 @@ export const DEFAULT_TOOL_DISPLAY_CONFIG: ToolDisplayConfig = {
|
|
|
26
26
|
diffViewMode: "auto",
|
|
27
27
|
diffIndicatorMode: "bars",
|
|
28
28
|
diffSplitMinWidth: 120,
|
|
29
|
-
/** Collapsed
|
|
30
|
-
|
|
29
|
+
/** Collapsed edit/diff body: ~half a typical terminal after chrome. */
|
|
30
|
+
editDiffCollapsedLines: 24,
|
|
31
31
|
/**
|
|
32
32
|
* Write create/overwrite collapsed body.
|
|
33
33
|
* 0 = `↳ created • click to show more` (stats stay on the title).
|
|
@@ -48,7 +48,7 @@ export type Config = {
|
|
|
48
48
|
diffViewMode: DiffViewMode;
|
|
49
49
|
diffIndicatorMode: DiffIndicatorMode;
|
|
50
50
|
diffSplitMinWidth: number;
|
|
51
|
-
|
|
51
|
+
editDiffCollapsedLines: number;
|
|
52
52
|
writeDiffCollapsedLines: number;
|
|
53
53
|
diffWordWrap: boolean;
|
|
54
54
|
expandedPreviewMaxLines: number;
|
|
@@ -99,7 +99,7 @@ export const DEFAULT_CONFIG: Config = {
|
|
|
99
99
|
diffViewMode: DEFAULT_TOOL_DISPLAY_CONFIG.diffViewMode,
|
|
100
100
|
diffIndicatorMode: DEFAULT_TOOL_DISPLAY_CONFIG.diffIndicatorMode,
|
|
101
101
|
diffSplitMinWidth: DEFAULT_TOOL_DISPLAY_CONFIG.diffSplitMinWidth,
|
|
102
|
-
|
|
102
|
+
editDiffCollapsedLines: DEFAULT_TOOL_DISPLAY_CONFIG.editDiffCollapsedLines,
|
|
103
103
|
writeDiffCollapsedLines: DEFAULT_TOOL_DISPLAY_CONFIG.writeDiffCollapsedLines,
|
|
104
104
|
diffWordWrap: DEFAULT_TOOL_DISPLAY_CONFIG.diffWordWrap,
|
|
105
105
|
expandedPreviewMaxLines: DEFAULT_TOOL_DISPLAY_CONFIG.expandedPreviewMaxLines,
|
|
@@ -169,9 +169,9 @@ export function normalizeConfig(input: unknown): Config {
|
|
|
169
169
|
40,
|
|
170
170
|
300,
|
|
171
171
|
),
|
|
172
|
-
|
|
173
|
-
source.diffCollapsedLines,
|
|
174
|
-
DEFAULT_CONFIG.
|
|
172
|
+
editDiffCollapsedLines: pickPositiveInt(
|
|
173
|
+
source.editDiffCollapsedLines ?? source.diffCollapsedLines,
|
|
174
|
+
DEFAULT_CONFIG.editDiffCollapsedLines,
|
|
175
175
|
1,
|
|
176
176
|
500,
|
|
177
177
|
),
|
|
@@ -223,7 +223,7 @@ export function getToolDisplayConfig(source: Config = config): ToolDisplayConfig
|
|
|
223
223
|
diffViewMode: source.diffViewMode,
|
|
224
224
|
diffIndicatorMode: source.diffIndicatorMode,
|
|
225
225
|
diffSplitMinWidth: source.diffSplitMinWidth,
|
|
226
|
-
|
|
226
|
+
editDiffCollapsedLines: source.editDiffCollapsedLines,
|
|
227
227
|
writeDiffCollapsedLines: source.writeDiffCollapsedLines,
|
|
228
228
|
diffWordWrap: source.diffWordWrap,
|
|
229
229
|
expandedPreviewMaxLines: source.expandedPreviewMaxLines,
|
|
@@ -241,7 +241,7 @@ export function formatConfigStatus(source: Config = config): string {
|
|
|
241
241
|
`diffView=${source.diffViewMode}`,
|
|
242
242
|
`diffIndicator=${source.diffIndicatorMode}`,
|
|
243
243
|
`diffSplitMin=${source.diffSplitMinWidth}`,
|
|
244
|
-
`
|
|
244
|
+
`editCollapsed=${source.editDiffCollapsedLines}`,
|
|
245
245
|
`writeCollapsed=${source.writeDiffCollapsedLines}`,
|
|
246
246
|
`diffWordWrap=${source.diffWordWrap ? "on" : "off"}`,
|
|
247
247
|
`expandedMax=${source.expandedPreviewMaxLines}`,
|
|
@@ -288,11 +288,11 @@ export async function showCcstylePanel(
|
|
|
288
288
|
buildNumberInputSubmenu(theme, diffSplitSetting, closeSubmenu),
|
|
289
289
|
};
|
|
290
290
|
const diffCollapsedSetting = {
|
|
291
|
-
id: "
|
|
291
|
+
id: "editDiffCollapsedLines",
|
|
292
292
|
label: "Edit collapsed lines",
|
|
293
293
|
description:
|
|
294
294
|
"How many edit/diff body lines to show before the expand hint (Ctrl+O / click). Write uses its own setting below.",
|
|
295
|
-
currentValue: String(config.
|
|
295
|
+
currentValue: String(config.editDiffCollapsedLines),
|
|
296
296
|
values: [...DIFF_COLLAPSED_LINES_VALUES],
|
|
297
297
|
submenu: (_current: string, closeSubmenu: (selected?: string) => void) =>
|
|
298
298
|
buildNumberInputSubmenu(theme, diffCollapsedSetting, closeSubmenu),
|
|
@@ -458,11 +458,16 @@ export async function showCcstylePanel(
|
|
|
458
458
|
});
|
|
459
459
|
diffSplitSetting.currentValue = String(config.diffSplitMinWidth);
|
|
460
460
|
break;
|
|
461
|
-
case "
|
|
461
|
+
case "editDiffCollapsedLines":
|
|
462
462
|
updateConfig({
|
|
463
|
-
|
|
463
|
+
editDiffCollapsedLines: pickPositiveInt(
|
|
464
|
+
value,
|
|
465
|
+
DEFAULT_CONFIG.editDiffCollapsedLines,
|
|
466
|
+
1,
|
|
467
|
+
500,
|
|
468
|
+
),
|
|
464
469
|
});
|
|
465
|
-
diffCollapsedSetting.currentValue = String(config.
|
|
470
|
+
diffCollapsedSetting.currentValue = String(config.editDiffCollapsedLines);
|
|
466
471
|
break;
|
|
467
472
|
case "writeDiffCollapsedLines":
|
|
468
473
|
updateConfig({
|
|
@@ -174,11 +174,38 @@ function thinkingExpandAction(): string | undefined {
|
|
|
174
174
|
}
|
|
175
175
|
|
|
176
176
|
// 只 wrap 尾部窗口;缓存未着色折行,着色放到取出时做,避免主题切换命中旧 ANSI。
|
|
177
|
-
|
|
178
|
-
const
|
|
177
|
+
type PreviewCacheEntry = { lines: string[]; hiddenBefore: number };
|
|
178
|
+
const previewCache = new Map<string, PreviewCacheEntry>();
|
|
179
|
+
export const THINKING_PREVIEW_CACHE_MAX = 2_048;
|
|
179
180
|
const PREVIEW_BUDGET_MIN_CHARS = 2_000;
|
|
180
181
|
const PREVIEW_BUDGET_SLACK_LINES = 2;
|
|
181
182
|
|
|
183
|
+
function getCachedPreview(key: string): PreviewCacheEntry | undefined {
|
|
184
|
+
const entry = previewCache.get(key);
|
|
185
|
+
if (!entry) return undefined;
|
|
186
|
+
previewCache.delete(key);
|
|
187
|
+
previewCache.set(key, entry);
|
|
188
|
+
return entry;
|
|
189
|
+
}
|
|
190
|
+
|
|
191
|
+
function cachePreview(key: string, entry: PreviewCacheEntry): void {
|
|
192
|
+
previewCache.delete(key);
|
|
193
|
+
while (previewCache.size >= THINKING_PREVIEW_CACHE_MAX) {
|
|
194
|
+
const oldest = previewCache.keys().next().value;
|
|
195
|
+
if (oldest === undefined) break;
|
|
196
|
+
previewCache.delete(oldest);
|
|
197
|
+
}
|
|
198
|
+
previewCache.set(key, entry);
|
|
199
|
+
}
|
|
200
|
+
|
|
201
|
+
export function clearThinkingPreviewCache(): void {
|
|
202
|
+
previewCache.clear();
|
|
203
|
+
}
|
|
204
|
+
|
|
205
|
+
export function thinkingPreviewCacheSize(): number {
|
|
206
|
+
return previewCache.size;
|
|
207
|
+
}
|
|
208
|
+
|
|
182
209
|
/** 按可见宽度估算折行数,不走 Text 全量 wrap。无换行长段也能计到隐藏行。 */
|
|
183
210
|
function countWrappedLines(text: string, contentWidth: number): number {
|
|
184
211
|
if (!text) return 0;
|
|
@@ -219,14 +246,13 @@ function layoutThinkingPreview(
|
|
|
219
246
|
else cut = 0;
|
|
220
247
|
}
|
|
221
248
|
const cacheKey = `${width}:${padding}:${cut}:${source}`;
|
|
222
|
-
let entry =
|
|
249
|
+
let entry = getCachedPreview(cacheKey);
|
|
223
250
|
if (!entry) {
|
|
224
251
|
entry = {
|
|
225
252
|
lines: wrapTextWithAnsi(source.replace(/\t/g, " "), contentWidth),
|
|
226
253
|
hiddenBefore: cut > 0 ? countWrappedLines(text.slice(0, cut), contentWidth) : 0,
|
|
227
254
|
};
|
|
228
|
-
|
|
229
|
-
previewCache.set(cacheKey, entry);
|
|
255
|
+
cachePreview(cacheKey, entry);
|
|
230
256
|
}
|
|
231
257
|
const hiddenLines = entry.hiddenBefore + Math.max(0, entry.lines.length - config.previewLines);
|
|
232
258
|
const visible = hiddenLines > 0 ? entry.lines.slice(-config.previewLines) : entry.lines;
|
|
@@ -265,6 +291,15 @@ export class ThinkingPreviewBlock implements Component {
|
|
|
265
291
|
private _expanded: boolean;
|
|
266
292
|
private hintHovered = false;
|
|
267
293
|
private expandedBody: { width: number; lines: string[] } | undefined;
|
|
294
|
+
private collapsedMemo:
|
|
295
|
+
| {
|
|
296
|
+
width: number;
|
|
297
|
+
previewLines: number;
|
|
298
|
+
hintHovered: boolean;
|
|
299
|
+
expandAction: string | undefined;
|
|
300
|
+
lines: string[];
|
|
301
|
+
}
|
|
302
|
+
| undefined;
|
|
268
303
|
|
|
269
304
|
constructor(
|
|
270
305
|
heading: string,
|
|
@@ -294,6 +329,7 @@ export class ThinkingPreviewBlock implements Component {
|
|
|
294
329
|
}
|
|
295
330
|
|
|
296
331
|
setExpanded(expanded: boolean): void {
|
|
332
|
+
if (this._expanded !== expanded) this.collapsedMemo = undefined;
|
|
297
333
|
this._expanded = expanded;
|
|
298
334
|
if (expanded) expandedThinking.add(this.messageTimestamp);
|
|
299
335
|
else {
|
|
@@ -303,6 +339,7 @@ export class ThinkingPreviewBlock implements Component {
|
|
|
303
339
|
}
|
|
304
340
|
|
|
305
341
|
setHintHovered(hovered: boolean): void {
|
|
342
|
+
if (this.hintHovered !== hovered) this.collapsedMemo = undefined;
|
|
306
343
|
this.hintHovered = hovered;
|
|
307
344
|
}
|
|
308
345
|
|
|
@@ -362,16 +399,39 @@ export class ThinkingPreviewBlock implements Component {
|
|
|
362
399
|
});
|
|
363
400
|
return box.render(width);
|
|
364
401
|
}
|
|
402
|
+
|
|
403
|
+
const expandAction = thinkingExpandAction();
|
|
404
|
+
if (
|
|
405
|
+
this.collapsedMemo?.width === width &&
|
|
406
|
+
this.collapsedMemo.previewLines === config.previewLines &&
|
|
407
|
+
this.collapsedMemo.hintHovered === this.hintHovered &&
|
|
408
|
+
this.collapsedMemo.expandAction === expandAction
|
|
409
|
+
) {
|
|
410
|
+
return this.collapsedMemo.lines;
|
|
411
|
+
}
|
|
412
|
+
|
|
365
413
|
const body = this.bodyLines(width, this.padding);
|
|
366
414
|
const heading = this.headingLines(width, body.hiddenLines, this.padding);
|
|
367
|
-
|
|
368
|
-
|
|
369
|
-
|
|
370
|
-
|
|
371
|
-
|
|
415
|
+
const lines = body.lines.length
|
|
416
|
+
? [
|
|
417
|
+
...heading,
|
|
418
|
+
...body.lines.map((line) => padPreviewLine(this.style(line), width, this.padding)),
|
|
419
|
+
]
|
|
420
|
+
: heading;
|
|
421
|
+
this.collapsedMemo = {
|
|
422
|
+
width,
|
|
423
|
+
previewLines: config.previewLines,
|
|
424
|
+
hintHovered: this.hintHovered,
|
|
425
|
+
expandAction,
|
|
426
|
+
lines,
|
|
427
|
+
};
|
|
428
|
+
return lines;
|
|
372
429
|
}
|
|
373
430
|
|
|
374
|
-
invalidate() {
|
|
431
|
+
invalidate() {
|
|
432
|
+
this.collapsedMemo = undefined;
|
|
433
|
+
this.expandedBody = undefined;
|
|
434
|
+
}
|
|
375
435
|
}
|
|
376
436
|
|
|
377
437
|
function parseSummaryPart(text: string): SummaryPart | undefined {
|
|
@@ -922,6 +982,7 @@ function compactThinking(pi: ExtensionAPI) {
|
|
|
922
982
|
completedDurations.clear();
|
|
923
983
|
streamingComponents.clear();
|
|
924
984
|
expandedThinking.clear();
|
|
985
|
+
clearThinkingPreviewCache();
|
|
925
986
|
if (ctx.mode === "tui") ctx.ui.setWidget(WIDGET_ID, undefined);
|
|
926
987
|
|
|
927
988
|
if (patchInstalled) {
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
import type { ExtensionAPI } from "@earendil-works/pi-coding-agent";
|
|
2
|
+
|
|
3
|
+
function modelLabel(model: any): string | undefined {
|
|
4
|
+
if (!model) return undefined;
|
|
5
|
+
const name = model.name || model.id;
|
|
6
|
+
if (!name) return undefined;
|
|
7
|
+
return model.provider ? `${model.provider} · ${name}` : name;
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
function apply(ctx: any): void {
|
|
11
|
+
if (!ctx?.hasUI) return;
|
|
12
|
+
ctx.ui?.setStatus?.("model", modelLabel(ctx.model));
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
/** 用 setStatus 挂模型名,不 setFooter,不接管原生 footer。 */
|
|
16
|
+
export default function (pi: ExtensionAPI): void {
|
|
17
|
+
pi.on("session_start", async (_event, ctx) => apply(ctx));
|
|
18
|
+
pi.on("model_select", async (_event, ctx) => apply(ctx));
|
|
19
|
+
}
|
package/extensions/index.ts
CHANGED
|
@@ -5,6 +5,7 @@ import { config } from "./config/config.ts";
|
|
|
5
5
|
import piAliases from "./feature/shell/aliases.ts";
|
|
6
6
|
import piStartupHeader from "./feature/shell/startup-header.ts";
|
|
7
7
|
import workingMessage from "./feature/shell/working-message.ts";
|
|
8
|
+
import modelStatus from "./feature/shell/model-status.ts";
|
|
8
9
|
|
|
9
10
|
// feature
|
|
10
11
|
import agentAutocomplete from "./feature/reference/subagent.ts";
|
|
@@ -22,6 +23,7 @@ export default function (pi: ExtensionAPI): void {
|
|
|
22
23
|
if (config.enableAliases) piAliases(pi);
|
|
23
24
|
piStartupHeader(pi);
|
|
24
25
|
if (config.enableWorkingMessage) workingMessage(pi);
|
|
26
|
+
modelStatus(pi);
|
|
25
27
|
|
|
26
28
|
// render stack:thinking controller 直接交给 style 作 query
|
|
27
29
|
markdownEnhance(pi);
|
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
* (`Ran for 8s, bash×2, read×2`),edit/write 独立标题行(`✓ write <path> (+25 -0)`),
|
|
4
4
|
* 普通工具折叠时不显示独立行;展开(Ctrl+O / fullscreen 点击)在单个工具卡中恢复
|
|
5
5
|
* compact-thinking/Pi 原生或专用 renderer。edit/write 复用 mode=on 的 rich diff
|
|
6
|
-
* 与 `
|
|
6
|
+
* 与 `editDiffCollapsedLines` / `writeDiffCollapsedLines` / `expandedPreviewMaxLines`。
|
|
7
7
|
* Agent/Task 族:调用只进摘要计数,tool 卡始终折叠(避免 pending→完成高度闪动)。
|
|
8
8
|
* 底部 Agents/Tasks 面板由 pi-subagents/pi-tasks 独立 widget 负责,不经 tool 卡外置。
|
|
9
9
|
*
|
|
@@ -526,6 +526,12 @@ function compactEditWriteLine(
|
|
|
526
526
|
return ["", truncateToWidth(line, width, "")];
|
|
527
527
|
}
|
|
528
528
|
|
|
529
|
+
/** expanded 写进 rich diff 闭包,折叠/展开分槽缓存,避免每帧 parseDiff。 */
|
|
530
|
+
const compactRichDiffCache = new WeakMap<
|
|
531
|
+
object,
|
|
532
|
+
{ result: unknown; collapsed?: unknown; expanded?: unknown }
|
|
533
|
+
>();
|
|
534
|
+
|
|
529
535
|
/**
|
|
530
536
|
* compact edit/write:标题行 + mode=on 同一套 rich diff。
|
|
531
537
|
* 折叠/展开都走 `renderRichToolResult`,limits 不另开一套。
|
|
@@ -540,23 +546,33 @@ function compactEditWriteLines(
|
|
|
540
546
|
const expanded = component.expanded === true;
|
|
541
547
|
const isError = result?.isError === true;
|
|
542
548
|
const isPending = !result || component.isPartial === true;
|
|
543
|
-
|
|
544
|
-
|
|
545
|
-
|
|
546
|
-
|
|
547
|
-
|
|
548
|
-
|
|
549
|
-
|
|
550
|
-
|
|
551
|
-
|
|
552
|
-
|
|
553
|
-
|
|
554
|
-
|
|
555
|
-
|
|
556
|
-
|
|
557
|
-
|
|
558
|
-
|
|
559
|
-
|
|
549
|
+
let candidate: unknown;
|
|
550
|
+
if (!isPending && writeMetadata) {
|
|
551
|
+
let entry = compactRichDiffCache.get(component);
|
|
552
|
+
if (!entry || entry.result !== result) {
|
|
553
|
+
entry = { result };
|
|
554
|
+
compactRichDiffCache.set(component, entry);
|
|
555
|
+
}
|
|
556
|
+
const slot = expanded ? "expanded" : "collapsed";
|
|
557
|
+
candidate = entry[slot];
|
|
558
|
+
if (!isRichDiffComponent(candidate)) {
|
|
559
|
+
candidate = renderRichToolResult(
|
|
560
|
+
String(component.toolName ?? ""),
|
|
561
|
+
result,
|
|
562
|
+
{
|
|
563
|
+
expanded,
|
|
564
|
+
isPartial: component.isPartial === true,
|
|
565
|
+
isError,
|
|
566
|
+
isHovered: () => isToolCallHovered(component.toolCallId),
|
|
567
|
+
},
|
|
568
|
+
theme,
|
|
569
|
+
component,
|
|
570
|
+
writeMetadata,
|
|
571
|
+
getToolDisplayConfig,
|
|
572
|
+
);
|
|
573
|
+
if (isRichDiffComponent(candidate)) entry[slot] = candidate;
|
|
574
|
+
}
|
|
575
|
+
}
|
|
560
576
|
const hasRich = isRichDiffComponent(candidate);
|
|
561
577
|
if (hasRich) {
|
|
562
578
|
component.resultRendererComponent = candidate;
|
|
@@ -39,7 +39,7 @@ export function displayConfigCacheKey(config: ToolDisplayConfig): string {
|
|
|
39
39
|
config.diffViewMode,
|
|
40
40
|
config.diffIndicatorMode,
|
|
41
41
|
String(config.diffSplitMinWidth),
|
|
42
|
-
String(config.
|
|
42
|
+
String(config.editDiffCollapsedLines),
|
|
43
43
|
String(config.writeDiffCollapsedLines),
|
|
44
44
|
config.diffWordWrap ? "1" : "0",
|
|
45
45
|
String(config.expandedPreviewMaxLines),
|
|
@@ -143,7 +143,7 @@ export function renderEditDiffResult(
|
|
|
143
143
|
const headerRows = renderHeaderRows(parsed.stats, mode, safeWidth, theme);
|
|
144
144
|
const displayLimit = resolveDiffDisplayLimit(
|
|
145
145
|
options.expanded,
|
|
146
|
-
live.
|
|
146
|
+
live.editDiffCollapsedLines,
|
|
147
147
|
live.expandedPreviewMaxLines,
|
|
148
148
|
);
|
|
149
149
|
const processBudget = resolveDiffProcessBudget(displayLimit, wordWrap);
|
|
@@ -177,7 +177,7 @@ export function renderEditDiffResult(
|
|
|
177
177
|
bodyRows,
|
|
178
178
|
safeWidth,
|
|
179
179
|
options.expanded,
|
|
180
|
-
live.
|
|
180
|
+
live.editDiffCollapsedLines,
|
|
181
181
|
live.expandedPreviewMaxLines,
|
|
182
182
|
parsed.stats.hunks,
|
|
183
183
|
theme,
|
|
@@ -41,20 +41,20 @@ export function resolveDiffDisplayLimit(
|
|
|
41
41
|
: DEFAULT_TOOL_DISPLAY_CONFIG.expandedPreviewMaxLines;
|
|
42
42
|
const collapsedLimit = Number.isFinite(maxCollapsedLines)
|
|
43
43
|
? maxCollapsedLines
|
|
44
|
-
: DEFAULT_TOOL_DISPLAY_CONFIG.
|
|
44
|
+
: DEFAULT_TOOL_DISPLAY_CONFIG.editDiffCollapsedLines;
|
|
45
45
|
return expanded ? Math.max(0, expandedLimit) : Math.max(1, collapsedLimit);
|
|
46
46
|
}
|
|
47
47
|
|
|
48
|
-
/** Write collapsed body limit. Missing/NaN falls back to edit's `
|
|
48
|
+
/** Write collapsed body limit. Missing/NaN falls back to edit's `editDiffCollapsedLines`. */
|
|
49
49
|
export function resolveWriteCollapsedLimit(
|
|
50
|
-
config: Pick<ToolDisplayConfig, "writeDiffCollapsedLines" | "
|
|
50
|
+
config: Pick<ToolDisplayConfig, "writeDiffCollapsedLines" | "editDiffCollapsedLines">,
|
|
51
51
|
): number {
|
|
52
52
|
const value = config.writeDiffCollapsedLines;
|
|
53
53
|
if (Number.isFinite(value)) {
|
|
54
54
|
return Math.max(0, value);
|
|
55
55
|
}
|
|
56
|
-
const fallback = Number.isFinite(config.
|
|
57
|
-
? config.
|
|
56
|
+
const fallback = Number.isFinite(config.editDiffCollapsedLines)
|
|
57
|
+
? config.editDiffCollapsedLines
|
|
58
58
|
: DEFAULT_TOOL_DISPLAY_CONFIG.writeDiffCollapsedLines;
|
|
59
59
|
return Math.max(0, fallback);
|
|
60
60
|
}
|
|
@@ -180,11 +180,13 @@ export class ToolGroupComponent extends Container {
|
|
|
180
180
|
}
|
|
181
181
|
|
|
182
182
|
addTool(tool: any): void {
|
|
183
|
+
this.settledCache = undefined;
|
|
183
184
|
this.children.push(tool);
|
|
184
185
|
tool[PARENT_KEY] = this;
|
|
185
186
|
}
|
|
186
187
|
|
|
187
188
|
releaseTools(): any[] {
|
|
189
|
+
this.settledCache = undefined;
|
|
188
190
|
const tools = [...this.children];
|
|
189
191
|
this.children.length = 0;
|
|
190
192
|
this.patch.groups.delete(this);
|
|
@@ -192,18 +194,21 @@ export class ToolGroupComponent extends Container {
|
|
|
192
194
|
}
|
|
193
195
|
|
|
194
196
|
removeTool(tool: any): void {
|
|
197
|
+
this.settledCache = undefined;
|
|
195
198
|
const index = this.children.indexOf(tool);
|
|
196
199
|
if (index >= 0) this.children.splice(index, 1);
|
|
197
200
|
if (tool?.[PARENT_KEY] === this) delete tool[PARENT_KEY];
|
|
198
201
|
}
|
|
199
202
|
|
|
200
203
|
setExpanded(expanded: boolean): void {
|
|
204
|
+
if (this._expanded !== expanded) this.settledCache = undefined;
|
|
201
205
|
this._expanded = expanded;
|
|
202
206
|
for (const tool of this.children)
|
|
203
207
|
(tool as Component & { setExpanded?: (expanded: boolean) => void }).setExpanded?.(expanded);
|
|
204
208
|
}
|
|
205
209
|
|
|
206
210
|
setHintHovered(hovered: boolean): void {
|
|
211
|
+
if (this.hintHovered !== hovered) this.settledCache = undefined;
|
|
207
212
|
this.hintHovered = hovered;
|
|
208
213
|
}
|
|
209
214
|
|
|
@@ -232,6 +237,7 @@ export class ToolGroupComponent extends Container {
|
|
|
232
237
|
}
|
|
233
238
|
|
|
234
239
|
invalidate(): void {
|
|
240
|
+
this.settledCache = undefined;
|
|
235
241
|
for (const tool of this.children) tool.invalidate?.();
|
|
236
242
|
}
|
|
237
243
|
|