@quandev104/pi-style 0.1.1 → 0.1.2
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/CHANGELOG.md +10 -0
- package/dist/extensions/pi-style.js +568 -261
- package/dist/extensions/pi-style.js.map +1 -1
- package/extension-src/pi-style/features/messages/boxed-block.ts +16 -20
- package/extension-src/pi-style/features/messages/index.ts +95 -32
- package/extension-src/pi-style/features/messages/special-blocks.ts +3 -3
- package/extension-src/pi-style/features/startup/index.ts +4 -4
- package/extension-src/pi-style/features/tools/boxed/bash.ts +11 -19
- package/extension-src/pi-style/features/tools/boxed/edit.ts +39 -23
- package/extension-src/pi-style/features/tools/boxed/fallback.ts +10 -8
- package/extension-src/pi-style/features/tools/boxed/quick-edit.ts +45 -24
- package/extension-src/pi-style/pi/session-coordinator.ts +9 -1
- package/extension-src/pi-style/shared/ansi.ts +3 -0
- package/extension-src/pi-style/shared/box.ts +175 -68
- package/extension-src/pi-style/shared/split-diff.ts +395 -86
- package/package.json +1 -1
|
@@ -1491,6 +1491,7 @@ function stripAnsi(value) {
|
|
|
1491
1491
|
break;
|
|
1492
1492
|
}
|
|
1493
1493
|
}
|
|
1494
|
+
if (i + 1 < value.length && value.charCodeAt(i + 1) === 7) i++;
|
|
1494
1495
|
}
|
|
1495
1496
|
}
|
|
1496
1497
|
return output;
|
|
@@ -2059,7 +2060,7 @@ function renderSystemContextPanel(resolved, items, minTotalWidth) {
|
|
|
2059
2060
|
"\u2500".repeat(pathWidth)
|
|
2060
2061
|
)}${divider}${resolved.apply("dim", "\u2500".repeat(metricWidth))}`;
|
|
2061
2062
|
const lines = [
|
|
2062
|
-
renderPanelBorder(resolved, "\
|
|
2063
|
+
renderPanelBorder(resolved, "\u256D", "\u256E", panelWidth),
|
|
2063
2064
|
renderPanelLine(resolved, titleLine, panelWidth),
|
|
2064
2065
|
renderPanelLine(resolved, header, panelWidth),
|
|
2065
2066
|
renderPanelLine(resolved, separator, panelWidth)
|
|
@@ -2081,7 +2082,7 @@ function renderSystemContextPanel(resolved, items, minTotalWidth) {
|
|
|
2081
2082
|
)
|
|
2082
2083
|
);
|
|
2083
2084
|
}
|
|
2084
|
-
lines.push(renderPanelBorder(resolved, "\
|
|
2085
|
+
lines.push(renderPanelBorder(resolved, "\u2570", "\u256F", panelWidth));
|
|
2085
2086
|
return lines;
|
|
2086
2087
|
}
|
|
2087
2088
|
function groupToolDetails(tools) {
|
|
@@ -2130,7 +2131,7 @@ function renderToolsPanel(resolved, tools, minTotalWidth) {
|
|
|
2130
2131
|
"\u2500".repeat(countWidth)
|
|
2131
2132
|
)}${divider}${resolved.apply("dim", "\u2500".repeat(toolsWidth))}`;
|
|
2132
2133
|
const lines = [
|
|
2133
|
-
renderPanelBorder(resolved, "\
|
|
2134
|
+
renderPanelBorder(resolved, "\u256D", "\u256E", panelWidth),
|
|
2134
2135
|
renderPanelLine(resolved, titleLine, panelWidth),
|
|
2135
2136
|
renderPanelLine(resolved, header, panelWidth),
|
|
2136
2137
|
renderPanelLine(resolved, separator, panelWidth)
|
|
@@ -2152,7 +2153,7 @@ function renderToolsPanel(resolved, tools, minTotalWidth) {
|
|
|
2152
2153
|
)
|
|
2153
2154
|
);
|
|
2154
2155
|
}
|
|
2155
|
-
lines.push(renderPanelBorder(resolved, "\
|
|
2156
|
+
lines.push(renderPanelBorder(resolved, "\u2570", "\u256F", panelWidth));
|
|
2156
2157
|
return lines;
|
|
2157
2158
|
}
|
|
2158
2159
|
var STARTUP_INDENT = " ";
|
|
@@ -3754,6 +3755,12 @@ import { relative, resolve as resolve2 } from "path";
|
|
|
3754
3755
|
|
|
3755
3756
|
// extension-src/pi-style/shared/elapsed.ts
|
|
3756
3757
|
var ELAPSED_KEY = "__elapsedMs";
|
|
3758
|
+
function formatElapsedMs(ms) {
|
|
3759
|
+
if (typeof ms !== "number" || !Number.isFinite(ms)) return "";
|
|
3760
|
+
if (ms < 1e3) return `${Math.round(ms)}ms`;
|
|
3761
|
+
const s = ms / 1e3;
|
|
3762
|
+
return s < 10 ? `${s.toFixed(1)}s` : `${Math.round(s)}s`;
|
|
3763
|
+
}
|
|
3757
3764
|
function getElapsedMs(result) {
|
|
3758
3765
|
if (!result || typeof result.details !== "object" || result.details === null) return void 0;
|
|
3759
3766
|
const elapsed = result.details[ELAPSED_KEY];
|
|
@@ -4114,16 +4121,19 @@ function formatCompactCount(value) {
|
|
|
4114
4121
|
return `${Math.round(value / 1e6)}M`;
|
|
4115
4122
|
}
|
|
4116
4123
|
function formatBoxedWords(text) {
|
|
4117
|
-
return
|
|
4124
|
+
return `~${formatCompactCount(countWords2(text))} words`;
|
|
4118
4125
|
}
|
|
4119
4126
|
var BOX_HORIZONTAL = "\u2500";
|
|
4120
4127
|
var BOX_VERTICAL = "\u2502";
|
|
4121
4128
|
var BOX_SIDE_PADDING = 2;
|
|
4122
4129
|
var BOX_MIN_WIDTH = 12;
|
|
4123
|
-
var
|
|
4124
|
-
var
|
|
4125
|
-
var
|
|
4126
|
-
var
|
|
4130
|
+
var BOX_ROUND_TOP_LEFT = "\u256D";
|
|
4131
|
+
var BOX_ROUND_TOP_RIGHT = "\u256E";
|
|
4132
|
+
var BOX_ROUND_BOTTOM_LEFT = "\u2570";
|
|
4133
|
+
var BOX_ROUND_BOTTOM_RIGHT = "\u256F";
|
|
4134
|
+
var BOX_DIVIDER_LEFT = "\u251C";
|
|
4135
|
+
var BOX_DIVIDER_RIGHT = "\u2524";
|
|
4136
|
+
var BOX_LABELED_RIGHT_DASH_MIN = 3;
|
|
4127
4137
|
function boxWidth(width) {
|
|
4128
4138
|
return Math.max(BOX_MIN_WIDTH, width);
|
|
4129
4139
|
}
|
|
@@ -4216,19 +4226,8 @@ function formatBoxedStatusIcon(theme, isError) {
|
|
|
4216
4226
|
}
|
|
4217
4227
|
function formatBoxedToolTitle(theme, name, isError) {
|
|
4218
4228
|
const rawTitle = `\u2794 ${name}`;
|
|
4219
|
-
const coloredTitle = `${colorFromExtra(theme, "bashPromptColor", "bashMode", rawTitle)} ${formatBoxedStatusIcon(theme,
|
|
4220
|
-
|
|
4221
|
-
return `${title} ${boxText(theme, "|")}`;
|
|
4222
|
-
}
|
|
4223
|
-
function formatCompactBoxedToolTitle(theme, name, isError) {
|
|
4224
|
-
const paddedName = padVisibleRight(name, COMPACT_TOOL_NAME_WIDTH);
|
|
4225
|
-
const rawTitle = `\u2794 ${paddedName}`;
|
|
4226
|
-
const coloredTitle = `${colorFromExtra(theme, "bashPromptColor", "bashMode", rawTitle)} ${formatBoxedStatusIcon(theme, isError)}`;
|
|
4227
|
-
const title = typeof theme?.bold === "function" ? theme.bold(coloredTitle) : coloredTitle;
|
|
4228
|
-
return `${title} ${boxText(theme, "|")}`;
|
|
4229
|
-
}
|
|
4230
|
-
function boxText(theme, text) {
|
|
4231
|
-
return `${RESET_INTENSITY}${theme.fg("borderMuted", text)}`;
|
|
4229
|
+
const coloredTitle = isError ? theme.fg("error", `${rawTitle} \u2717`) : `${colorFromExtra(theme, "bashPromptColor", "bashMode", rawTitle)} ${formatBoxedStatusIcon(theme, false)}`;
|
|
4230
|
+
return typeof theme?.bold === "function" ? theme.bold(coloredTitle) : coloredTitle;
|
|
4232
4231
|
}
|
|
4233
4232
|
function boxFrameText(theme, text) {
|
|
4234
4233
|
return `${RESET_INTENSITY}${theme.fg("border", text)}`;
|
|
@@ -4238,23 +4237,41 @@ function boxBorder(theme, left, right, width) {
|
|
|
4238
4237
|
const innerWidth = renderedWidth - 2;
|
|
4239
4238
|
return boxFrameText(theme, `${left}${BOX_HORIZONTAL.repeat(innerWidth)}${right}`);
|
|
4240
4239
|
}
|
|
4241
|
-
function
|
|
4242
|
-
return `${text}${" ".repeat(Math.max(0, width - safeVisibleWidth(text)))}`;
|
|
4243
|
-
}
|
|
4244
|
-
function boxLineWithRight(theme, left, right, width) {
|
|
4240
|
+
function boxLabeledBorder(theme, start, end, leftLabel, rightLabel, width) {
|
|
4245
4241
|
const renderedWidth = boxWidth(width);
|
|
4246
|
-
|
|
4247
|
-
const
|
|
4248
|
-
|
|
4242
|
+
let left = leftLabel ?? "";
|
|
4243
|
+
const right = rightLabel ?? "";
|
|
4244
|
+
let leftWidth = safeVisibleWidth(left);
|
|
4249
4245
|
const rightWidth = safeVisibleWidth(right);
|
|
4246
|
+
const leftOverhead = left ? 3 : 0;
|
|
4247
|
+
const rightOverhead = right ? 2 : 0;
|
|
4248
|
+
let rightFill = right ? BOX_LABELED_RIGHT_DASH_MIN : 0;
|
|
4249
|
+
let fill = renderedWidth - start.length - end.length - leftOverhead - leftWidth - rightOverhead - rightWidth - rightFill;
|
|
4250
|
+
if (right && fill < 0) {
|
|
4251
|
+
rightFill = 1;
|
|
4252
|
+
fill = renderedWidth - start.length - end.length - leftOverhead - leftWidth - rightOverhead - rightWidth - rightFill;
|
|
4253
|
+
}
|
|
4254
|
+
if (fill < 0) {
|
|
4255
|
+
const reserved = start.length + end.length + leftOverhead + (right ? rightOverhead + rightWidth + rightFill : 0) + 1;
|
|
4256
|
+
const maxLeft = renderedWidth - reserved;
|
|
4257
|
+
left = maxLeft > 0 ? safeTruncateToWidth(left, maxLeft, "\u2026") : "";
|
|
4258
|
+
leftWidth = safeVisibleWidth(left);
|
|
4259
|
+
fill = renderedWidth - start.length - end.length - (left ? leftWidth + leftOverhead : 0) - (right ? rightOverhead + rightWidth + rightFill : 0);
|
|
4260
|
+
}
|
|
4261
|
+
const parts = [boxFrameText(theme, `${start}${left ? "\u2500 " : ""}`)];
|
|
4262
|
+
if (left) parts.push(left);
|
|
4263
|
+
parts.push(boxFrameText(theme, `${left ? " " : ""}${BOX_HORIZONTAL.repeat(Math.max(0, fill))}`));
|
|
4264
|
+
if (right) {
|
|
4265
|
+
parts.push(boxFrameText(theme, " "), right, boxFrameText(theme, ` ${BOX_HORIZONTAL.repeat(rightFill)}`));
|
|
4266
|
+
}
|
|
4267
|
+
parts.push(boxFrameText(theme, end));
|
|
4268
|
+
return parts.join("");
|
|
4269
|
+
}
|
|
4270
|
+
function boxBlankLine(theme, width) {
|
|
4271
|
+
const renderedWidth = boxWidth(width);
|
|
4272
|
+
const contentWidth = boxInnerWidth(renderedWidth);
|
|
4250
4273
|
const sidePad = " ".repeat(BOX_SIDE_PADDING);
|
|
4251
|
-
|
|
4252
|
-
return boxLine(theme, right || left, renderedWidth);
|
|
4253
|
-
}
|
|
4254
|
-
const maxLeftWidth = Math.max(1, contentWidth - dividerWidth - rightWidth - 1);
|
|
4255
|
-
const truncatedLeft = safeTruncateToWidth(left, maxLeftWidth, "\u2026");
|
|
4256
|
-
const gap = " ".repeat(Math.max(1, contentWidth - safeVisibleWidth(truncatedLeft) - dividerWidth - rightWidth));
|
|
4257
|
-
return `${boxFrameText(theme, BOX_VERTICAL)}${sidePad}${truncatedLeft}${gap}${divider}${right}${sidePad}${boxFrameText(theme, BOX_VERTICAL)}`;
|
|
4274
|
+
return `${boxFrameText(theme, BOX_VERTICAL)}${sidePad}${" ".repeat(contentWidth)}${sidePad}${boxFrameText(theme, BOX_VERTICAL)}`;
|
|
4258
4275
|
}
|
|
4259
4276
|
function boxLine(theme, content, width) {
|
|
4260
4277
|
const renderedWidth = boxWidth(width);
|
|
@@ -4269,12 +4286,6 @@ function boxLine(theme, content, width) {
|
|
|
4269
4286
|
const fill = " ".repeat(Math.max(0, contentWidth - safeVisibleWidth(truncated)));
|
|
4270
4287
|
return `${boxFrameText(theme, BOX_VERTICAL)}${sidePad}${truncated}${fill}${sidePad}${boxFrameText(theme, BOX_VERTICAL)}`;
|
|
4271
4288
|
}
|
|
4272
|
-
function boxInsetDivider(theme, width) {
|
|
4273
|
-
const renderedWidth = boxWidth(width);
|
|
4274
|
-
const lineWidth = boxInnerWidth(renderedWidth);
|
|
4275
|
-
const sidePad = " ".repeat(BOX_SIDE_PADDING);
|
|
4276
|
-
return `${boxFrameText(theme, BOX_VERTICAL)}${sidePad}${boxText(theme, BOX_HORIZONTAL.repeat(lineWidth))}${sidePad}${boxFrameText(theme, BOX_VERTICAL)}`;
|
|
4277
|
-
}
|
|
4278
4289
|
function boxedWrappedLines(theme, content, width) {
|
|
4279
4290
|
return safeWrapTextWithAnsi(content, boxInnerWidth(width)).map((line) => boxLine(theme, line, width));
|
|
4280
4291
|
}
|
|
@@ -4327,20 +4338,28 @@ function renderBoxedToolCall(theme, toolName, detailLines, options = {}) {
|
|
|
4327
4338
|
render(width) {
|
|
4328
4339
|
if (cache?.width === width) return cache.lines;
|
|
4329
4340
|
const title = formatBoxedToolTitle(theme, toolName, options.isError);
|
|
4341
|
+
const headerLabel = options.headerDetail ? `${title} \xB7 ${options.headerDetail}` : title;
|
|
4330
4342
|
const renderedWidth = boxWidth(width);
|
|
4331
4343
|
const lines = [
|
|
4332
|
-
|
|
4333
|
-
|
|
4334
|
-
boxInsetDivider(theme, renderedWidth),
|
|
4344
|
+
boxLabeledBorder(theme, BOX_ROUND_TOP_LEFT, BOX_ROUND_TOP_RIGHT, headerLabel, void 0, renderedWidth),
|
|
4345
|
+
boxBlankLine(theme, renderedWidth),
|
|
4335
4346
|
...detailLines.flatMap((line) => boxedWrappedLines(theme, line, renderedWidth))
|
|
4336
4347
|
];
|
|
4337
4348
|
if (options.isPending) {
|
|
4338
4349
|
const pendingText = options.pendingText ?? "Waiting for output\u2026";
|
|
4339
4350
|
lines.push(
|
|
4340
|
-
|
|
4341
|
-
|
|
4342
|
-
|
|
4351
|
+
boxBlankLine(theme, renderedWidth),
|
|
4352
|
+
boxLabeledBorder(
|
|
4353
|
+
theme,
|
|
4354
|
+
BOX_ROUND_BOTTOM_LEFT,
|
|
4355
|
+
BOX_ROUND_BOTTOM_RIGHT,
|
|
4356
|
+
theme.fg("dim", `\u2026 ${pendingText}`),
|
|
4357
|
+
void 0,
|
|
4358
|
+
renderedWidth
|
|
4359
|
+
)
|
|
4343
4360
|
);
|
|
4361
|
+
} else {
|
|
4362
|
+
lines.push(boxBlankLine(theme, renderedWidth));
|
|
4344
4363
|
}
|
|
4345
4364
|
cache = { width, lines };
|
|
4346
4365
|
return lines;
|
|
@@ -4362,25 +4381,39 @@ function renderCompactBoxedToolCall(theme, toolName, detailLine, options = {}) {
|
|
|
4362
4381
|
},
|
|
4363
4382
|
render(width) {
|
|
4364
4383
|
const renderedWidth = boxWidth(width);
|
|
4365
|
-
const title =
|
|
4384
|
+
const title = formatBoxedToolTitle(theme, toolName, options.isError);
|
|
4385
|
+
const headerLabel = detailLine ? `${title} \xB7 ${detailLine}` : title;
|
|
4366
4386
|
const compactFooter = typeof options.state?.[COMPACT_FOOTER_KEY] === "string" ? options.state[COMPACT_FOOTER_KEY] : "";
|
|
4367
4387
|
const _footerIsError = Boolean(options.state?.[COMPACT_FOOTER_ERROR_KEY]);
|
|
4368
4388
|
const _footerIsPartial = Boolean(options.state?.[COMPACT_FOOTER_PARTIAL_KEY]);
|
|
4389
|
+
const lines = [
|
|
4390
|
+
boxLabeledBorder(theme, BOX_ROUND_TOP_LEFT, BOX_ROUND_TOP_RIGHT, headerLabel, void 0, renderedWidth),
|
|
4391
|
+
boxBlankLine(theme, renderedWidth)
|
|
4392
|
+
];
|
|
4369
4393
|
if (compactFooter) {
|
|
4370
|
-
|
|
4371
|
-
|
|
4372
|
-
|
|
4373
|
-
|
|
4374
|
-
|
|
4375
|
-
|
|
4376
|
-
|
|
4377
|
-
|
|
4394
|
+
lines.push(
|
|
4395
|
+
boxLabeledBorder(
|
|
4396
|
+
theme,
|
|
4397
|
+
BOX_ROUND_BOTTOM_LEFT,
|
|
4398
|
+
BOX_ROUND_BOTTOM_RIGHT,
|
|
4399
|
+
compactFooter,
|
|
4400
|
+
void 0,
|
|
4401
|
+
renderedWidth
|
|
4402
|
+
)
|
|
4403
|
+
);
|
|
4404
|
+
} else if (options.isPending) {
|
|
4378
4405
|
const pendingText = options.pendingText ?? "Waiting for output\u2026";
|
|
4379
4406
|
lines.push(
|
|
4380
|
-
|
|
4381
|
-
|
|
4382
|
-
|
|
4407
|
+
boxLabeledBorder(
|
|
4408
|
+
theme,
|
|
4409
|
+
BOX_ROUND_BOTTOM_LEFT,
|
|
4410
|
+
BOX_ROUND_BOTTOM_RIGHT,
|
|
4411
|
+
theme.fg("dim", `\u2026 ${pendingText}`),
|
|
4412
|
+
void 0,
|
|
4413
|
+
renderedWidth
|
|
4414
|
+
)
|
|
4383
4415
|
);
|
|
4416
|
+
} else {
|
|
4384
4417
|
}
|
|
4385
4418
|
return lines;
|
|
4386
4419
|
}
|
|
@@ -4400,46 +4433,50 @@ function renderBoxedToolResult(theme, body, options = {}) {
|
|
|
4400
4433
|
const bodyLines = typeof body === "function" ? body(maxContentWidth) : body.render(maxContentWidth);
|
|
4401
4434
|
const errorPrefix = options.isError ? [theme.fg("error", "\u2717 Error")] : [];
|
|
4402
4435
|
const outputLines = bodyLines.length > 0 ? [...errorPrefix, ...bodyLines] : [theme.fg("muted", `\u2205 ${options.emptyText ?? "(no output)"}`)];
|
|
4403
|
-
const
|
|
4404
|
-
const
|
|
4436
|
+
const footerText = (options.footerLines ?? []).join(" \xB7 ");
|
|
4437
|
+
const dividerText = typeof options.dividerLabel === "function" ? options.dividerLabel(renderedWidth) : options.dividerLabel ?? "Response";
|
|
4405
4438
|
const rendered = [
|
|
4406
|
-
|
|
4439
|
+
boxLabeledBorder(
|
|
4440
|
+
theme,
|
|
4441
|
+
BOX_DIVIDER_LEFT,
|
|
4442
|
+
BOX_DIVIDER_RIGHT,
|
|
4443
|
+
theme.fg("dim", dividerText),
|
|
4444
|
+
options.dividerRightLabel ? theme.fg("dim", options.dividerRightLabel) : void 0,
|
|
4445
|
+
renderedWidth
|
|
4446
|
+
),
|
|
4447
|
+
boxBlankLine(theme, renderedWidth),
|
|
4407
4448
|
...renderBoxedOutputLines(theme, outputLines, renderedWidth, options.renderLineBudget ?? outputLines.length),
|
|
4408
|
-
|
|
4409
|
-
|
|
4449
|
+
boxBlankLine(theme, renderedWidth),
|
|
4450
|
+
boxLabeledBorder(
|
|
4451
|
+
theme,
|
|
4452
|
+
BOX_ROUND_BOTTOM_LEFT,
|
|
4453
|
+
BOX_ROUND_BOTTOM_RIGHT,
|
|
4454
|
+
footerText,
|
|
4455
|
+
options.expandHint ? theme.fg("dim", options.expandHint) : void 0,
|
|
4456
|
+
renderedWidth
|
|
4457
|
+
)
|
|
4410
4458
|
];
|
|
4411
4459
|
cache = { width, lines: rendered };
|
|
4412
4460
|
return rendered;
|
|
4413
4461
|
}
|
|
4414
4462
|
};
|
|
4415
4463
|
}
|
|
4416
|
-
function formatBoxedFooterFromValues(theme, elapsedMs, output, extraParts = []
|
|
4464
|
+
function formatBoxedFooterFromValues(theme, elapsedMs, output, extraParts = []) {
|
|
4417
4465
|
const wall = elapsedMs === void 0 ? "--" : `${(elapsedMs / 1e3).toFixed(2)}s`;
|
|
4418
|
-
const elapsedPart =
|
|
4466
|
+
const elapsedPart = theme.fg("text", wall);
|
|
4419
4467
|
const extraPartList = extraParts.filter(Boolean).map((part) => theme.fg("dim", part));
|
|
4420
4468
|
const wordsPart = theme.fg("dim", formatBoxedWords(output));
|
|
4421
|
-
|
|
4422
|
-
padVisibleRight(elapsedPart, COMPACT_FOOTER_ELAPSED_WIDTH),
|
|
4423
|
-
...extraPartList.map((part) => padVisibleRight(part, COMPACT_FOOTER_EXTRA_WIDTH)),
|
|
4424
|
-
padVisibleRight(wordsPart, COMPACT_FOOTER_WORDS_WIDTH)
|
|
4425
|
-
] : [elapsedPart, ...extraPartList, wordsPart];
|
|
4426
|
-
return parts.join(theme.fg("dim", " \xB7 "));
|
|
4469
|
+
return [elapsedPart, ...extraPartList, wordsPart].join(theme.fg("dim", " \xB7 "));
|
|
4427
4470
|
}
|
|
4428
|
-
function formatBoxedFooterParts(theme, result, extraParts = [],
|
|
4429
|
-
return formatBoxedFooterFromValues(
|
|
4430
|
-
theme,
|
|
4431
|
-
elapsedMs ?? getElapsedMs(result),
|
|
4432
|
-
getTextOutput(result),
|
|
4433
|
-
extraParts,
|
|
4434
|
-
fixedColumns
|
|
4435
|
-
);
|
|
4471
|
+
function formatBoxedFooterParts(theme, result, extraParts = [], elapsedMs) {
|
|
4472
|
+
return formatBoxedFooterFromValues(theme, elapsedMs ?? getElapsedMs(result), getTextOutput(result), extraParts);
|
|
4436
4473
|
}
|
|
4437
4474
|
function formatBoxedFooter(theme, result, extraParts = [], elapsedMs) {
|
|
4438
|
-
return formatBoxedFooterParts(theme, result, extraParts,
|
|
4475
|
+
return formatBoxedFooterParts(theme, result, extraParts, elapsedMs);
|
|
4439
4476
|
}
|
|
4440
4477
|
function renderCompactBoxedFooter(theme, result, options = {}) {
|
|
4441
4478
|
if (options.state && typeof options.state === "object") {
|
|
4442
|
-
options.state[COMPACT_FOOTER_KEY] = formatBoxedFooterParts(theme, result, [],
|
|
4479
|
+
options.state[COMPACT_FOOTER_KEY] = formatBoxedFooterParts(theme, result, [], options.elapsedMs);
|
|
4443
4480
|
options.state[COMPACT_FOOTER_ERROR_KEY] = Boolean(options.isError);
|
|
4444
4481
|
options.state[COMPACT_FOOTER_PARTIAL_KEY] = Boolean(options.isPartial);
|
|
4445
4482
|
return { invalidate() {
|
|
@@ -4451,8 +4488,14 @@ function renderCompactBoxedFooter(theme, result, options = {}) {
|
|
|
4451
4488
|
render(width) {
|
|
4452
4489
|
const renderedWidth = boxWidth(width);
|
|
4453
4490
|
return [
|
|
4454
|
-
|
|
4455
|
-
|
|
4491
|
+
boxLabeledBorder(
|
|
4492
|
+
theme,
|
|
4493
|
+
BOX_ROUND_BOTTOM_LEFT,
|
|
4494
|
+
BOX_ROUND_BOTTOM_RIGHT,
|
|
4495
|
+
formatBoxedFooterParts(theme, result, [], options.elapsedMs),
|
|
4496
|
+
void 0,
|
|
4497
|
+
renderedWidth
|
|
4498
|
+
)
|
|
4456
4499
|
];
|
|
4457
4500
|
}
|
|
4458
4501
|
};
|
|
@@ -4516,12 +4559,12 @@ ${hint}`);
|
|
|
4516
4559
|
|
|
4517
4560
|
// extension-src/pi-style/features/messages/boxed-block.ts
|
|
4518
4561
|
function formatMessageBlockTitle(theme, kind, title, icon = "\u2794") {
|
|
4519
|
-
const rawTitle = title ? `${icon} ${kind}
|
|
4562
|
+
const rawTitle = title ? `${icon} ${kind} \xB7 ${title}` : `${icon} ${kind}`;
|
|
4520
4563
|
const coloredTitle = theme.fg("accent", rawTitle);
|
|
4521
4564
|
return typeof theme?.bold === "function" ? theme.bold(coloredTitle) : coloredTitle;
|
|
4522
4565
|
}
|
|
4523
4566
|
function renderBoxedMessageBlock(theme, options) {
|
|
4524
|
-
const { kind, title, right, body, icon = "\u2794",
|
|
4567
|
+
const { kind, title, right, body, icon = "\u2794", cache: shouldCache = true } = options;
|
|
4525
4568
|
let cache = null;
|
|
4526
4569
|
return {
|
|
4527
4570
|
invalidate() {
|
|
@@ -4532,23 +4575,18 @@ function renderBoxedMessageBlock(theme, options) {
|
|
|
4532
4575
|
const renderedWidth = boxWidth(width);
|
|
4533
4576
|
const contentWidth = boxInnerWidth(renderedWidth);
|
|
4534
4577
|
const titleLine = formatMessageBlockTitle(theme, kind, title, icon);
|
|
4535
|
-
const
|
|
4536
|
-
lines
|
|
4578
|
+
const bodyLines = body(contentWidth);
|
|
4579
|
+
const lines = [
|
|
4580
|
+
boxLabeledBorder(theme, "\u256D", "\u256E", titleLine, void 0, renderedWidth),
|
|
4581
|
+
boxBlankLine(theme, renderedWidth),
|
|
4582
|
+
...bodyLines.map((line) => boxLine(theme, line, renderedWidth))
|
|
4583
|
+
];
|
|
4584
|
+
if (bodyLines.length > 0) lines.push(boxBlankLine(theme, renderedWidth));
|
|
4537
4585
|
if (right) {
|
|
4538
|
-
|
|
4539
|
-
lines.push(boxLineWithRight(theme, titleLine, rightStyled, renderedWidth));
|
|
4586
|
+
lines.push(boxLabeledBorder(theme, "\u2570", "\u256F", "", theme.fg("dim", right), renderedWidth));
|
|
4540
4587
|
} else {
|
|
4541
|
-
lines.push(
|
|
4542
|
-
}
|
|
4543
|
-
const bodyLines = body(contentWidth);
|
|
4544
|
-
const showDivider = hasDivider === "auto" ? bodyLines.length > 0 : hasDivider;
|
|
4545
|
-
if (showDivider) {
|
|
4546
|
-
lines.push(boxInsetDivider(theme, renderedWidth));
|
|
4588
|
+
lines.push(boxBorder(theme, "\u2570", "\u256F", renderedWidth));
|
|
4547
4589
|
}
|
|
4548
|
-
for (const line of bodyLines) {
|
|
4549
|
-
lines.push(boxLine(theme, line, renderedWidth));
|
|
4550
|
-
}
|
|
4551
|
-
lines.push(boxBorder(theme, "\u2514", "\u2518", renderedWidth));
|
|
4552
4590
|
if (shouldCache) cache = { width, lines };
|
|
4553
4591
|
return lines;
|
|
4554
4592
|
}
|
|
@@ -4594,7 +4632,7 @@ function patchCompaction(instance, _original, theme) {
|
|
|
4594
4632
|
const block = renderBoxedMessageBlock(theme, {
|
|
4595
4633
|
kind: "Compaction",
|
|
4596
4634
|
title: `${tokenStr} tokens`,
|
|
4597
|
-
...expanded ? {} : { right:
|
|
4635
|
+
...expanded ? {} : { right: expandHint() },
|
|
4598
4636
|
body,
|
|
4599
4637
|
icon: "\u229F",
|
|
4600
4638
|
hasDivider: expanded
|
|
@@ -4614,7 +4652,7 @@ function patchSkill(instance, _original, theme) {
|
|
|
4614
4652
|
const block = renderBoxedMessageBlock(theme, {
|
|
4615
4653
|
kind: "Skill",
|
|
4616
4654
|
title: skillName,
|
|
4617
|
-
...expanded ? {} : { right:
|
|
4655
|
+
...expanded ? {} : { right: expandHint() },
|
|
4618
4656
|
body,
|
|
4619
4657
|
icon: "\u229F",
|
|
4620
4658
|
hasDivider: expanded
|
|
@@ -4632,7 +4670,7 @@ function patchBranch(instance, _original, theme) {
|
|
|
4632
4670
|
const body = expanded && summary && markdownTheme ? createMarkdownBody(summary, markdownTheme, theme) : () => [];
|
|
4633
4671
|
const block = renderBoxedMessageBlock(theme, {
|
|
4634
4672
|
kind: "Branch",
|
|
4635
|
-
...expanded ? {} : { right:
|
|
4673
|
+
...expanded ? {} : { right: expandHint() },
|
|
4636
4674
|
body,
|
|
4637
4675
|
icon: "\u229F",
|
|
4638
4676
|
hasDivider: expanded
|
|
@@ -4788,34 +4826,70 @@ function extractOscEnvelope(line) {
|
|
|
4788
4826
|
if (bodyEnd < 0 || !line.endsWith(OSC133_ZONE_FINAL)) return void 0;
|
|
4789
4827
|
return { start: OSC133_ZONE_START, body: line.slice(OSC133_ZONE_START.length, bodyEnd), end: line.slice(bodyEnd) };
|
|
4790
4828
|
}
|
|
4791
|
-
|
|
4829
|
+
var BG_RESET = "\x1B[49m";
|
|
4830
|
+
function splitLeadingMarkers(line) {
|
|
4792
4831
|
let index = 0;
|
|
4832
|
+
while (line.startsWith("\x1B]", index)) {
|
|
4833
|
+
const bel = line.indexOf("\x07", index + 2);
|
|
4834
|
+
const st = line.indexOf("\x1B\\", index + 2);
|
|
4835
|
+
const end = bel === -1 ? st : st === -1 ? bel : Math.min(bel, st);
|
|
4836
|
+
if (end === -1) break;
|
|
4837
|
+
index = end + 1;
|
|
4838
|
+
}
|
|
4839
|
+
return { head: line.slice(0, index), rest: line.slice(index) };
|
|
4840
|
+
}
|
|
4841
|
+
function leadingSgr(line) {
|
|
4842
|
+
if (!line.startsWith("\x1B[")) return "";
|
|
4843
|
+
let index = 2;
|
|
4793
4844
|
while (index < line.length) {
|
|
4794
|
-
|
|
4795
|
-
|
|
4796
|
-
|
|
4797
|
-
if (index < line.length) index++;
|
|
4798
|
-
continue;
|
|
4799
|
-
}
|
|
4800
|
-
if (/\s/u.test(line[index] ?? "")) {
|
|
4801
|
-
index++;
|
|
4802
|
-
continue;
|
|
4803
|
-
}
|
|
4804
|
-
break;
|
|
4845
|
+
const code = line.charCodeAt(index);
|
|
4846
|
+
if (code >= 64 && code <= 126) return line.slice(0, index + 1);
|
|
4847
|
+
index++;
|
|
4805
4848
|
}
|
|
4806
|
-
return
|
|
4849
|
+
return "";
|
|
4807
4850
|
}
|
|
4808
|
-
function
|
|
4851
|
+
function isBackgroundSgr(sequence) {
|
|
4852
|
+
if (!sequence.startsWith("\x1B[") || !sequence.endsWith("m")) return false;
|
|
4853
|
+
for (const code of sequence.slice(2, -1).split(";")) {
|
|
4854
|
+
const value = Number(code);
|
|
4855
|
+
if (value === 48 || value === 49) return true;
|
|
4856
|
+
if (value >= 40 && value <= 47) return true;
|
|
4857
|
+
if (value >= 100 && value <= 107) return true;
|
|
4858
|
+
}
|
|
4859
|
+
return false;
|
|
4860
|
+
}
|
|
4861
|
+
function rebuildAtWidth(line, width, lead) {
|
|
4862
|
+
const { head, rest } = splitLeadingMarkers(line);
|
|
4863
|
+
const bgAnsi = leadingSgr(rest);
|
|
4864
|
+
if (bgAnsi && isBackgroundSgr(bgAnsi) && rest.endsWith(BG_RESET)) {
|
|
4865
|
+
const body = rest.slice(bgAnsi.length, rest.length - BG_RESET.length);
|
|
4866
|
+
const pad = " ".repeat(Math.max(0, width - visibleWidth3(lead) - visibleWidth3(body)));
|
|
4867
|
+
return `${head}${bgAnsi}${lead}${body}${pad}${BG_RESET}`;
|
|
4868
|
+
}
|
|
4869
|
+
const padded = `${lead}${line}`;
|
|
4870
|
+
return `${padded}${" ".repeat(Math.max(0, width - visibleWidth3(padded)))}`;
|
|
4871
|
+
}
|
|
4872
|
+
function decorateMessageLine(line, index, lastIndex, contentIndex, width, options) {
|
|
4809
4873
|
const { firstEnvelope, firstHasStart, multilineEnvelope, prefix } = options;
|
|
4810
4874
|
const prefixWidth = visibleWidth3(prefix);
|
|
4875
|
+
const lead = index === contentIndex ? prefix : index > contentIndex ? " ".repeat(prefixWidth) : "";
|
|
4811
4876
|
if (index === contentIndex && firstEnvelope)
|
|
4812
|
-
return `${firstEnvelope.start}${
|
|
4877
|
+
return `${firstEnvelope.start}${rebuildAtWidth(firstEnvelope.body, width, prefix)}${firstEnvelope.end}`;
|
|
4813
4878
|
if (index === contentIndex && firstHasStart)
|
|
4814
|
-
return `${OSC133_ZONE_START}${
|
|
4879
|
+
return `${OSC133_ZONE_START}${rebuildAtWidth(line.slice(OSC133_ZONE_START.length), width, prefix)}`;
|
|
4815
4880
|
if (index === lastIndex && multilineEnvelope && index !== contentIndex)
|
|
4816
|
-
return `${OSC133_ZONE_END}${OSC133_ZONE_FINAL}${
|
|
4817
|
-
|
|
4818
|
-
|
|
4881
|
+
return `${OSC133_ZONE_END}${OSC133_ZONE_FINAL}${rebuildAtWidth(
|
|
4882
|
+
line.slice((OSC133_ZONE_END + OSC133_ZONE_FINAL).length),
|
|
4883
|
+
width,
|
|
4884
|
+
lead
|
|
4885
|
+
)}`;
|
|
4886
|
+
if (index === contentIndex && index === lastIndex && multilineEnvelope && line.startsWith(OSC133_ZONE_END + OSC133_ZONE_FINAL))
|
|
4887
|
+
return `${OSC133_ZONE_END}${OSC133_ZONE_FINAL}${rebuildAtWidth(
|
|
4888
|
+
line.slice((OSC133_ZONE_END + OSC133_ZONE_FINAL).length),
|
|
4889
|
+
width,
|
|
4890
|
+
prefix
|
|
4891
|
+
)}`;
|
|
4892
|
+
return rebuildAtWidth(line, width, lead);
|
|
4819
4893
|
}
|
|
4820
4894
|
function contentText(line) {
|
|
4821
4895
|
let output = "";
|
|
@@ -4849,23 +4923,21 @@ function prefixNative(lines, width, prefix) {
|
|
|
4849
4923
|
const first = nativeLines[0] ?? "";
|
|
4850
4924
|
const last = nativeLines.at(-1) ?? "";
|
|
4851
4925
|
const multilineEnvelope = nativeLines.length > 1 && last.startsWith(OSC133_ZONE_END + OSC133_ZONE_FINAL);
|
|
4852
|
-
const firstContentIndex = nativeLines.findIndex(
|
|
4853
|
-
(
|
|
4854
|
-
|
|
4926
|
+
const firstContentIndex = nativeLines.findIndex((line, index) => {
|
|
4927
|
+
if (index !== nativeLines.length - 1 || !multilineEnvelope) return hasContent(line);
|
|
4928
|
+
return !nativeLines.slice(0, index).some((earlier) => hasContent(earlier)) && hasContent(line);
|
|
4929
|
+
});
|
|
4855
4930
|
if (firstContentIndex < 0) return nativeLines;
|
|
4856
4931
|
const firstEnvelope = firstContentIndex === 0 ? extractOscEnvelope(first) : void 0;
|
|
4857
4932
|
const firstHasStart = firstContentIndex === 0 && first.startsWith(OSC133_ZONE_START);
|
|
4858
|
-
const decorated = nativeLines.map(
|
|
4859
|
-
|
|
4860
|
-
|
|
4861
|
-
|
|
4862
|
-
|
|
4863
|
-
|
|
4864
|
-
|
|
4865
|
-
|
|
4866
|
-
if (index > firstContentIndex && hasContent(line)) return `${" ".repeat(prefixWidth)}${line}`;
|
|
4867
|
-
return line;
|
|
4868
|
-
});
|
|
4933
|
+
const decorated = nativeLines.map(
|
|
4934
|
+
(line, index) => decorateMessageLine(line, index, nativeLines.length - 1, firstContentIndex, width, {
|
|
4935
|
+
firstEnvelope,
|
|
4936
|
+
firstHasStart,
|
|
4937
|
+
multilineEnvelope,
|
|
4938
|
+
prefix
|
|
4939
|
+
})
|
|
4940
|
+
);
|
|
4869
4941
|
if (!decorated.every((line) => visibleWidth3(line) <= width)) return void 0;
|
|
4870
4942
|
if (!nativeLines.every((line) => visibleWidth3(line) <= bodyWidth)) return void 0;
|
|
4871
4943
|
return decorated;
|
|
@@ -4956,7 +5028,6 @@ function matchLimitReached(result) {
|
|
|
4956
5028
|
}
|
|
4957
5029
|
|
|
4958
5030
|
// extension-src/pi-style/features/tools/boxed/bash.ts
|
|
4959
|
-
var MAX_BASH_PREVIEW_LINES = 5;
|
|
4960
5031
|
var MAX_LINE_CHARS = 2e3;
|
|
4961
5032
|
var ESC2 = "\x1B";
|
|
4962
5033
|
var BASH_TOOL_NOTICE_PATTERN = /^\[Showing (?:last|lines)\b.*\. Full output: .+\]$/;
|
|
@@ -5085,13 +5156,16 @@ function formatTimeout(context) {
|
|
|
5085
5156
|
const timeout = context?.args?.timeout ?? 300;
|
|
5086
5157
|
return `${timeout}s`;
|
|
5087
5158
|
}
|
|
5088
|
-
function renderBoxedBashResult(theme, inner, result, context) {
|
|
5159
|
+
function renderBoxedBashResult(theme, inner, result, context, expandHint2) {
|
|
5089
5160
|
const rawCommand = String(context?.args?.command ?? "...");
|
|
5090
5161
|
const referenceLines = rawCommand.split("\n").map((line, index) => `${index === 0 ? "$ " : "> "}${line}`);
|
|
5091
5162
|
return renderBoxedToolResult(theme, inner, {
|
|
5092
5163
|
widthKey: bashWidthKey(rawCommand, context?.args?.timeout),
|
|
5093
5164
|
referenceLines,
|
|
5094
|
-
footerLines: [
|
|
5165
|
+
footerLines: [
|
|
5166
|
+
formatBoxedFooter(theme, result, [`timeout ${formatTimeout(context)}`], getElapsed(context))
|
|
5167
|
+
],
|
|
5168
|
+
...expandHint2 ? { expandHint: expandHint2 } : {},
|
|
5095
5169
|
isError: context.isError,
|
|
5096
5170
|
isPartial: Boolean(context.isPartial)
|
|
5097
5171
|
});
|
|
@@ -5099,7 +5173,7 @@ function renderBoxedBashResult(theme, inner, result, context) {
|
|
|
5099
5173
|
function getElapsed(context) {
|
|
5100
5174
|
return getStateElapsedMs(context.state);
|
|
5101
5175
|
}
|
|
5102
|
-
function createBashResultPreview(theme, text, options, color
|
|
5176
|
+
function createBashResultPreview(theme, text, options, color) {
|
|
5103
5177
|
let cacheKey = "";
|
|
5104
5178
|
let cacheLines = null;
|
|
5105
5179
|
return {
|
|
@@ -5114,7 +5188,7 @@ function createBashResultPreview(theme, text, options, color, extraLinesBefore =
|
|
|
5114
5188
|
const cacheId = `${bodyWidth}|${expanded ? 1 : 0}|${cfg.maxExpandedLines}|${cfg.dimOutput ? 1 : 0}`;
|
|
5115
5189
|
if (cacheLines && cacheKey === cacheId) return cacheLines;
|
|
5116
5190
|
if (!expanded) {
|
|
5117
|
-
const needed =
|
|
5191
|
+
const needed = cfg.maxCollapsedLines;
|
|
5118
5192
|
let totalNewlines = 0;
|
|
5119
5193
|
let scanFrom = 0;
|
|
5120
5194
|
for (let i = text.length - 1; i >= 0; i--) {
|
|
@@ -5143,15 +5217,8 @@ function createBashResultPreview(theme, text, options, color, extraLinesBefore =
|
|
|
5143
5217
|
if (color === "error") return formatToolOutputLine(theme, truncated, "error");
|
|
5144
5218
|
return cfg.dimOutput ? formatToolOutputLine(theme, truncated) : formatToolOutputLine(theme, truncated, "text");
|
|
5145
5219
|
});
|
|
5146
|
-
const remaining = extraLinesBefore + (scanFrom > 0 ? countNewlines(text, 0, scanFrom) : 0);
|
|
5147
|
-
if (remaining <= 0) {
|
|
5148
|
-
cacheKey = cacheId;
|
|
5149
|
-
cacheLines = truncatedShown;
|
|
5150
|
-
return cacheLines;
|
|
5151
|
-
}
|
|
5152
|
-
const hint = safeTruncateToWidth(`... ${remaining} more lines, press Ctrl+o to expand`, bodyWidth, "\u2026");
|
|
5153
5220
|
cacheKey = cacheId;
|
|
5154
|
-
cacheLines =
|
|
5221
|
+
cacheLines = truncatedShown;
|
|
5155
5222
|
return cacheLines;
|
|
5156
5223
|
}
|
|
5157
5224
|
const normalized = replaceTabs(text);
|
|
@@ -5189,7 +5256,7 @@ var bashTool = {
|
|
|
5189
5256
|
const raw = getTextOutput(result);
|
|
5190
5257
|
const outputColor = context.isError ? "error" : "toolOutput";
|
|
5191
5258
|
if (!options.expanded) {
|
|
5192
|
-
const scanLines =
|
|
5259
|
+
const scanLines = getToolsRenderConfig().maxCollapsedLines + 10;
|
|
5193
5260
|
let nlCount = 0;
|
|
5194
5261
|
let tailStart = 0;
|
|
5195
5262
|
for (let i = raw.length - 1; i >= 0; i--) {
|
|
@@ -5203,18 +5270,17 @@ var bashTool = {
|
|
|
5203
5270
|
}
|
|
5204
5271
|
const tail = stripBashToolNoticeLines(stripAnsi(raw.slice(tailStart)));
|
|
5205
5272
|
const totalLinesBefore = tailStart > 0 ? countNewlines(raw, 0, tailStart) : 0;
|
|
5206
|
-
const inner2 = createBashResultPreview(theme, tail, options, outputColor
|
|
5207
|
-
return renderBoxedBashResult(theme, inner2, result, context);
|
|
5273
|
+
const inner2 = createBashResultPreview(theme, tail, options, outputColor);
|
|
5274
|
+
return renderBoxedBashResult(theme, inner2, result, context, totalLinesBefore > 0 ? "Ctrl+O for more" : void 0);
|
|
5208
5275
|
}
|
|
5209
5276
|
const output = stripBashToolNoticeLines(stripAnsi(raw));
|
|
5210
|
-
const inner = createBashResultPreview(theme, output, options, outputColor
|
|
5277
|
+
const inner = createBashResultPreview(theme, output, options, outputColor);
|
|
5211
5278
|
return renderBoxedBashResult(theme, inner, result, context);
|
|
5212
5279
|
}
|
|
5213
5280
|
};
|
|
5214
5281
|
|
|
5215
5282
|
// extension-src/pi-style/features/tools/boxed/edit.ts
|
|
5216
5283
|
import { getLanguageFromPath } from "@earendil-works/pi-coding-agent";
|
|
5217
|
-
import { Text } from "@earendil-works/pi-tui";
|
|
5218
5284
|
|
|
5219
5285
|
// extension-src/pi-style/shared/split-diff.ts
|
|
5220
5286
|
import { highlightCode as highlightCode2 } from "@earendil-works/pi-coding-agent";
|
|
@@ -5225,6 +5291,9 @@ var ADD_ROW_BACKGROUND_MIX_RATIO = 0.24;
|
|
|
5225
5291
|
var REMOVE_ROW_BACKGROUND_MIX_RATIO = 0.12;
|
|
5226
5292
|
var ADD_INLINE_EMPHASIS_MIX_RATIO = 0.44;
|
|
5227
5293
|
var REMOVE_INLINE_EMPHASIS_MIX_RATIO = 0.26;
|
|
5294
|
+
var CONTEXT_KEEP_DEFAULT = 2;
|
|
5295
|
+
var CONTEXT_RUN_SHOW_MAX = 4;
|
|
5296
|
+
var SPLIT_DIFF_MIN_WIDTH = 114;
|
|
5228
5297
|
function ansi256ToRgb(code) {
|
|
5229
5298
|
if (code <= 15) {
|
|
5230
5299
|
const base16 = [
|
|
@@ -5490,15 +5559,6 @@ function countDiffStats(diff) {
|
|
|
5490
5559
|
}
|
|
5491
5560
|
return { additions, removals };
|
|
5492
5561
|
}
|
|
5493
|
-
function renderDiffMeter(theme, additions, removals, width = 20) {
|
|
5494
|
-
const total = additions + removals;
|
|
5495
|
-
if (total <= 0) return "";
|
|
5496
|
-
const addBlocks = Math.round(additions / total * width);
|
|
5497
|
-
const removeBlocks = Math.max(0, width - addBlocks);
|
|
5498
|
-
const addBar = addBlocks > 0 ? theme.fg("toolDiffAdded", "\u2501".repeat(addBlocks)) : "";
|
|
5499
|
-
const removeBar = removeBlocks > 0 ? theme.fg("toolDiffRemoved", "\u2501".repeat(removeBlocks)) : "";
|
|
5500
|
-
return `${theme.fg("dim", "[")}${addBar}${removeBar}${theme.fg("dim", "]")}`;
|
|
5501
|
-
}
|
|
5502
5562
|
function extractEditedPath(message) {
|
|
5503
5563
|
const m = message.match(/Successfully replaced (?:text|\d+ block\(s\)|lines L\d+-\d+) in (.+)\.$/);
|
|
5504
5564
|
return m?.[1];
|
|
@@ -5511,11 +5571,85 @@ function firstText(content) {
|
|
|
5511
5571
|
}
|
|
5512
5572
|
return "";
|
|
5513
5573
|
}
|
|
5514
|
-
|
|
5515
|
-
|
|
5574
|
+
function longestChangedLineWidth(rows) {
|
|
5575
|
+
let longest = 0;
|
|
5576
|
+
for (const row of rows) {
|
|
5577
|
+
const candidates = [];
|
|
5578
|
+
if (row.kind === "changed") {
|
|
5579
|
+
if (row.left) candidates.push(row.left.line);
|
|
5580
|
+
if (row.right) candidates.push(row.right.line);
|
|
5581
|
+
} else if (row.kind === "added" && row.right) {
|
|
5582
|
+
candidates.push(row.right.line);
|
|
5583
|
+
} else if (row.kind === "removed" && row.left) {
|
|
5584
|
+
candidates.push(row.left.line);
|
|
5585
|
+
}
|
|
5586
|
+
for (const candidate of candidates) {
|
|
5587
|
+
longest = Math.max(longest, safeVisibleWidth(candidate));
|
|
5588
|
+
}
|
|
5589
|
+
}
|
|
5590
|
+
return longest;
|
|
5591
|
+
}
|
|
5592
|
+
function pickDiffMode(stats, rows, width) {
|
|
5593
|
+
if (stats.additions <= 0 || stats.removals <= 0) return "unified";
|
|
5594
|
+
if (width < SPLIT_DIFF_MIN_WIDTH) return "unified";
|
|
5595
|
+
if (longestChangedLineWidth(rows) > width / 2) return "unified";
|
|
5596
|
+
return "split";
|
|
5597
|
+
}
|
|
5598
|
+
function collapseContextRows(rows, options) {
|
|
5599
|
+
const keep = options.keep;
|
|
5600
|
+
const runShowMax = options.runShowMax ?? CONTEXT_RUN_SHOW_MAX;
|
|
5601
|
+
const out = [];
|
|
5602
|
+
let i = 0;
|
|
5603
|
+
while (i < rows.length) {
|
|
5604
|
+
const row = rows[i];
|
|
5605
|
+
if (row?.kind !== "context") {
|
|
5606
|
+
if (row) out.push({ kind: "row", row });
|
|
5607
|
+
i++;
|
|
5608
|
+
continue;
|
|
5609
|
+
}
|
|
5610
|
+
let j = i;
|
|
5611
|
+
while (j < rows.length && rows[j]?.kind === "context") j++;
|
|
5612
|
+
const run = j - i;
|
|
5613
|
+
if (run <= runShowMax) {
|
|
5614
|
+
for (let k = i; k < j; k++) out.push({ kind: "row", row: rows[k] });
|
|
5615
|
+
} else {
|
|
5616
|
+
const leading = i === 0;
|
|
5617
|
+
const trailing = j >= rows.length;
|
|
5618
|
+
const keepHead = leading ? 0 : Math.min(keep, run);
|
|
5619
|
+
const keepTail = trailing ? 0 : Math.min(keep, Math.max(0, run - keepHead));
|
|
5620
|
+
const hidden = Math.max(0, run - keepHead - keepTail);
|
|
5621
|
+
if (keepHead > 0) {
|
|
5622
|
+
for (let k = i; k < i + keepHead; k++) out.push({ kind: "row", row: rows[k] });
|
|
5623
|
+
}
|
|
5624
|
+
if (hidden > 0) out.push({ kind: "gap", hidden });
|
|
5625
|
+
if (keepTail > 0) {
|
|
5626
|
+
for (let k = j - keepTail; k < j; k++) out.push({ kind: "row", row: rows[k] });
|
|
5627
|
+
}
|
|
5628
|
+
}
|
|
5629
|
+
i = j;
|
|
5630
|
+
}
|
|
5631
|
+
return out;
|
|
5632
|
+
}
|
|
5633
|
+
function planEntries(rows, maxRows) {
|
|
5634
|
+
const budget = Math.max(1, maxRows);
|
|
5635
|
+
let entries = collapseContextRows(rows, { keep: CONTEXT_KEEP_DEFAULT });
|
|
5636
|
+
if (entries.length <= budget) return entries;
|
|
5637
|
+
entries = collapseContextRows(rows, { keep: 0, runShowMax: 0 });
|
|
5638
|
+
if (entries.length <= budget) return entries;
|
|
5639
|
+
const kept = entries.slice(0, Math.max(1, budget - 1));
|
|
5640
|
+
const omitted = Math.max(0, entries.length - kept.length);
|
|
5641
|
+
if (omitted <= 0) return kept;
|
|
5642
|
+
return [...kept, { kind: "omitted", count: omitted }];
|
|
5643
|
+
}
|
|
5644
|
+
function formatGapLabel(hidden) {
|
|
5645
|
+
return `\u22EF ${hidden} unchanged ${hidden === 1 ? "line" : "lines"} hidden`;
|
|
5646
|
+
}
|
|
5647
|
+
function formatOmittedLabel(count) {
|
|
5648
|
+
return `\u22EF ${count} ${count === 1 ? "line" : "lines"} omitted \xB7 Ctrl+O to show full diff`;
|
|
5649
|
+
}
|
|
5650
|
+
var DiffRenderContext = class {
|
|
5651
|
+
constructor(theme, rows, language) {
|
|
5516
5652
|
this.theme = theme;
|
|
5517
|
-
this.rows = rows;
|
|
5518
|
-
this.maxRows = maxRows;
|
|
5519
5653
|
this.language = language;
|
|
5520
5654
|
let maxDigits = 3;
|
|
5521
5655
|
for (const row of rows) {
|
|
@@ -5533,16 +5667,129 @@ var SplitDiffComponent = class {
|
|
|
5533
5667
|
this.containerBgAnsi = theme.getBgAnsi?.("toolSuccessBg") ?? "";
|
|
5534
5668
|
}
|
|
5535
5669
|
theme;
|
|
5536
|
-
rows;
|
|
5537
|
-
maxRows;
|
|
5538
5670
|
language;
|
|
5539
|
-
cacheWidth;
|
|
5540
|
-
cacheLines;
|
|
5541
5671
|
lineNumberWidth;
|
|
5542
|
-
highlightCache = /* @__PURE__ */ new Map();
|
|
5543
|
-
inlineHighlights = /* @__PURE__ */ new WeakMap();
|
|
5544
5672
|
palette;
|
|
5545
5673
|
containerBgAnsi;
|
|
5674
|
+
highlightCache = /* @__PURE__ */ new Map();
|
|
5675
|
+
inlineHighlights = /* @__PURE__ */ new WeakMap();
|
|
5676
|
+
fg(color, text) {
|
|
5677
|
+
return this.theme.fg(color, text);
|
|
5678
|
+
}
|
|
5679
|
+
inlineSpans(line) {
|
|
5680
|
+
return this.inlineHighlights.get(line) ?? [];
|
|
5681
|
+
}
|
|
5682
|
+
syntaxHighlight(line) {
|
|
5683
|
+
if (!this.language) return stripInlineBreaksPreserveAnsi(line);
|
|
5684
|
+
const safeLine = sanitizeSingleLineText(line);
|
|
5685
|
+
const key = `${this.language}
|
|
5686
|
+
${safeLine}`;
|
|
5687
|
+
const cached = this.highlightCache.get(key);
|
|
5688
|
+
if (cached) return cached;
|
|
5689
|
+
let highlighted = safeLine;
|
|
5690
|
+
try {
|
|
5691
|
+
highlighted = highlightCode2(safeLine, this.language)[0] ?? safeLine;
|
|
5692
|
+
highlighted = stripInlineBreaksPreserveAnsi(highlighted).replace(BG_ANSI_PATTERN2, "");
|
|
5693
|
+
} catch {
|
|
5694
|
+
highlighted = safeLine;
|
|
5695
|
+
}
|
|
5696
|
+
this.highlightCache.set(key, highlighted);
|
|
5697
|
+
return highlighted;
|
|
5698
|
+
}
|
|
5699
|
+
};
|
|
5700
|
+
var UnifiedDiffRenderer = class {
|
|
5701
|
+
constructor(ctx, entries) {
|
|
5702
|
+
this.ctx = ctx;
|
|
5703
|
+
this.entries = entries;
|
|
5704
|
+
}
|
|
5705
|
+
ctx;
|
|
5706
|
+
entries;
|
|
5707
|
+
gapLine(entry, width) {
|
|
5708
|
+
return padRenderedLineWidth(this.ctx.fg("muted", formatGapLabel(entry.hidden)), width);
|
|
5709
|
+
}
|
|
5710
|
+
omittedLine(entry, width) {
|
|
5711
|
+
return padRenderedLineWidth(this.ctx.fg("muted", formatOmittedLabel(entry.count)), width);
|
|
5712
|
+
}
|
|
5713
|
+
render(width) {
|
|
5714
|
+
const safeWidth = Math.max(20, width);
|
|
5715
|
+
const prefixWidth = 1 + 1 + this.ctx.lineNumberWidth + 2;
|
|
5716
|
+
const codeWidth = Math.max(1, safeWidth - prefixWidth);
|
|
5717
|
+
const lines = [];
|
|
5718
|
+
for (const entry of this.entries) {
|
|
5719
|
+
if (entry.kind === "gap") {
|
|
5720
|
+
lines.push(this.gapLine(entry, safeWidth));
|
|
5721
|
+
continue;
|
|
5722
|
+
}
|
|
5723
|
+
if (entry.kind === "omitted") {
|
|
5724
|
+
lines.push(this.omittedLine(entry, safeWidth));
|
|
5725
|
+
continue;
|
|
5726
|
+
}
|
|
5727
|
+
lines.push(...this.rowLines(entry.row, codeWidth, safeWidth));
|
|
5728
|
+
}
|
|
5729
|
+
return lines;
|
|
5730
|
+
}
|
|
5731
|
+
rowLines(row, codeWidth, width) {
|
|
5732
|
+
const segments = [];
|
|
5733
|
+
if (row.kind === "changed") {
|
|
5734
|
+
if (row.left) segments.push({ kind: "remove", line: row.left });
|
|
5735
|
+
if (row.right) segments.push({ kind: "add", line: row.right });
|
|
5736
|
+
} else if (row.kind === "added" && row.right) {
|
|
5737
|
+
segments.push({ kind: "add", line: row.right });
|
|
5738
|
+
} else if (row.kind === "removed" && row.left) {
|
|
5739
|
+
segments.push({ kind: "remove", line: row.left });
|
|
5740
|
+
} else {
|
|
5741
|
+
const line = row.left ?? row.right;
|
|
5742
|
+
if (line) segments.push({ kind: "context", line });
|
|
5743
|
+
}
|
|
5744
|
+
const out = [];
|
|
5745
|
+
for (const segment2 of segments) {
|
|
5746
|
+
out.push(...this.segmentLines(segment2.kind, segment2.line, codeWidth, width));
|
|
5747
|
+
}
|
|
5748
|
+
return out;
|
|
5749
|
+
}
|
|
5750
|
+
segmentLines(kind, line, codeWidth, width) {
|
|
5751
|
+
const isAdd = kind === "add";
|
|
5752
|
+
const isRemove = kind === "remove";
|
|
5753
|
+
const blank = line.line === "";
|
|
5754
|
+
const visualKind = kind === "context" || blank ? "context" : kind;
|
|
5755
|
+
const markerChar = kind === "context" ? " " : isAdd ? "+" : "-";
|
|
5756
|
+
const markerColor = isAdd ? "toolDiffAdded" : isRemove ? "toolDiffRemoved" : "dim";
|
|
5757
|
+
const gutterColor = visualKind === "context" ? "dim" : isAdd ? "toolDiffAdded" : "toolDiffRemoved";
|
|
5758
|
+
const gutter = line.lineNumber.trim().padStart(this.ctx.lineNumberWidth, " ");
|
|
5759
|
+
const firstPrefixAnsi = `${this.ctx.fg(markerColor, markerChar)} ${this.ctx.fg(gutterColor, gutter)} `;
|
|
5760
|
+
const firstPrefixPlain = `${markerChar} ${gutter} `;
|
|
5761
|
+
const contPrefixAnsi = `${this.ctx.fg("dim", " ")} ${this.ctx.fg("dim", " ".repeat(this.ctx.lineNumberWidth))} `;
|
|
5762
|
+
const contPrefixPlain = ` ${" ".repeat(1 + this.ctx.lineNumberWidth)} `;
|
|
5763
|
+
const rowBg = visualKind === "add" ? this.ctx.palette.addRowBgAnsi : visualKind === "remove" ? this.ctx.palette.removeRowBgAnsi : void 0;
|
|
5764
|
+
const plainSegments = wrapPlainText(line.line, codeWidth);
|
|
5765
|
+
const out = [];
|
|
5766
|
+
for (let i = 0; i < plainSegments.length; i++) {
|
|
5767
|
+
const prefixAnsi = i === 0 ? firstPrefixAnsi : contPrefixAnsi;
|
|
5768
|
+
const prefixPlain = i === 0 ? firstPrefixPlain : contPrefixPlain;
|
|
5769
|
+
const plainSegment = plainSegments[i] ?? "";
|
|
5770
|
+
let segment2 = this.ctx.syntaxHighlight(plainSegment);
|
|
5771
|
+
segment2 = fitToWidth(segment2, codeWidth);
|
|
5772
|
+
let rendered = prefixAnsi + segment2;
|
|
5773
|
+
const expectedWidth = safeVisibleWidth(prefixPlain) + codeWidth;
|
|
5774
|
+
const currentWidth = safeVisibleWidth(stripAnsi(rendered));
|
|
5775
|
+
if (currentWidth < expectedWidth) {
|
|
5776
|
+
rendered += " ".repeat(expectedWidth - currentWidth);
|
|
5777
|
+
}
|
|
5778
|
+
if (rowBg) {
|
|
5779
|
+
rendered = `${rowBg}${keepBackgroundAcrossResets(rendered, rowBg)}${this.ctx.containerBgAnsi}`;
|
|
5780
|
+
}
|
|
5781
|
+
out.push(padRenderedLineWidth(rendered, width));
|
|
5782
|
+
}
|
|
5783
|
+
return out;
|
|
5784
|
+
}
|
|
5785
|
+
};
|
|
5786
|
+
var SplitDiffRenderer = class {
|
|
5787
|
+
constructor(ctx, entries) {
|
|
5788
|
+
this.ctx = ctx;
|
|
5789
|
+
this.entries = entries;
|
|
5790
|
+
}
|
|
5791
|
+
ctx;
|
|
5792
|
+
entries;
|
|
5546
5793
|
getCellLineKind(kind, side) {
|
|
5547
5794
|
if (kind === "changed") return side === "left" ? "remove" : "add";
|
|
5548
5795
|
if (kind === "removed" && side === "left") return "remove";
|
|
@@ -5562,23 +5809,23 @@ var SplitDiffComponent = class {
|
|
|
5562
5809
|
return "dim";
|
|
5563
5810
|
}
|
|
5564
5811
|
getRowBackground(lineKind) {
|
|
5565
|
-
if (lineKind === "add") return this.palette.addRowBgAnsi;
|
|
5566
|
-
if (lineKind === "remove") return this.palette.removeRowBgAnsi;
|
|
5812
|
+
if (lineKind === "add") return this.ctx.palette.addRowBgAnsi;
|
|
5813
|
+
if (lineKind === "remove") return this.ctx.palette.removeRowBgAnsi;
|
|
5567
5814
|
return void 0;
|
|
5568
5815
|
}
|
|
5569
5816
|
getEmphasisBackground(lineKind) {
|
|
5570
|
-
if (lineKind === "add") return this.palette.addEmphasisBgAnsi;
|
|
5571
|
-
if (lineKind === "remove") return this.palette.removeEmphasisBgAnsi;
|
|
5817
|
+
if (lineKind === "add") return this.ctx.palette.addEmphasisBgAnsi;
|
|
5818
|
+
if (lineKind === "remove") return this.ctx.palette.removeEmphasisBgAnsi;
|
|
5572
5819
|
return void 0;
|
|
5573
5820
|
}
|
|
5574
5821
|
getCellFillBackground(kind, side) {
|
|
5575
5822
|
switch (kind) {
|
|
5576
5823
|
case "changed":
|
|
5577
|
-
return side === "left" ? this.palette.removeRowBgAnsi : this.palette.addRowBgAnsi;
|
|
5824
|
+
return side === "left" ? this.ctx.palette.removeRowBgAnsi : this.ctx.palette.addRowBgAnsi;
|
|
5578
5825
|
case "removed":
|
|
5579
|
-
return side === "left" ? this.palette.removeRowBgAnsi : void 0;
|
|
5826
|
+
return side === "left" ? this.ctx.palette.removeRowBgAnsi : void 0;
|
|
5580
5827
|
case "added":
|
|
5581
|
-
return side === "right" ? this.palette.addRowBgAnsi : void 0;
|
|
5828
|
+
return side === "right" ? this.ctx.palette.addRowBgAnsi : void 0;
|
|
5582
5829
|
default:
|
|
5583
5830
|
return void 0;
|
|
5584
5831
|
}
|
|
@@ -5587,57 +5834,40 @@ var SplitDiffComponent = class {
|
|
|
5587
5834
|
const lineKind = this.getCellLineKind(kind, side);
|
|
5588
5835
|
const markerChar = lineKind === "add" || lineKind === "remove" ? "\u258C" : " ";
|
|
5589
5836
|
const markerColor = lineKind === "add" ? "toolDiffAdded" : lineKind === "remove" ? "toolDiffRemoved" : "borderMuted";
|
|
5590
|
-
const marker2 = this.
|
|
5591
|
-
const lineNumber = this.
|
|
5592
|
-
const divider = this.
|
|
5837
|
+
const marker2 = this.ctx.fg(markerColor, markerChar);
|
|
5838
|
+
const lineNumber = this.ctx.fg("dim", " ".repeat(this.ctx.lineNumberWidth));
|
|
5839
|
+
const divider = this.ctx.fg("borderMuted", " \u2502 ");
|
|
5593
5840
|
const prefix = `${marker2} ${lineNumber}${divider}`;
|
|
5594
|
-
const prefixPlain = `${markerChar} ${" ".repeat(this.lineNumberWidth)} \u2502 `;
|
|
5841
|
+
const prefixPlain = `${markerChar} ${" ".repeat(this.ctx.lineNumberWidth)} \u2502 `;
|
|
5595
5842
|
const tailWidth = Math.max(0, columnWidth - safeVisibleWidth(prefixPlain));
|
|
5596
5843
|
let rendered = prefix + " ".repeat(tailWidth);
|
|
5597
5844
|
const bg = this.getCellFillBackground(kind, side);
|
|
5598
5845
|
if (!bg) return padRenderedLineWidth(rendered, columnWidth);
|
|
5599
|
-
rendered = `${bg}${keepBackgroundAcrossResets(rendered, bg)}${this.containerBgAnsi}`;
|
|
5846
|
+
rendered = `${bg}${keepBackgroundAcrossResets(rendered, bg)}${this.ctx.containerBgAnsi}`;
|
|
5600
5847
|
return padRenderedLineWidth(rendered, columnWidth);
|
|
5601
5848
|
}
|
|
5602
|
-
syntaxHighlight(line) {
|
|
5603
|
-
if (!this.language) return stripInlineBreaksPreserveAnsi(line);
|
|
5604
|
-
const safeLine = sanitizeSingleLineText(line);
|
|
5605
|
-
const key = `${this.language}
|
|
5606
|
-
${safeLine}`;
|
|
5607
|
-
const cached = this.highlightCache.get(key);
|
|
5608
|
-
if (cached) return cached;
|
|
5609
|
-
let highlighted = safeLine;
|
|
5610
|
-
try {
|
|
5611
|
-
highlighted = highlightCode2(safeLine, this.language)[0] ?? safeLine;
|
|
5612
|
-
highlighted = stripInlineBreaksPreserveAnsi(highlighted).replace(BG_ANSI_PATTERN2, "");
|
|
5613
|
-
} catch {
|
|
5614
|
-
highlighted = safeLine;
|
|
5615
|
-
}
|
|
5616
|
-
this.highlightCache.set(key, highlighted);
|
|
5617
|
-
return highlighted;
|
|
5618
|
-
}
|
|
5619
5849
|
formatCellLines(kind, side, line, columnWidth) {
|
|
5620
5850
|
if (!line) return [this.blankCell(kind, side, columnWidth)];
|
|
5621
5851
|
const lineKind = this.getVisualLineKind(kind, side, line);
|
|
5622
5852
|
const markerChar = lineKind === "add" || lineKind === "remove" ? "\u258C" : " ";
|
|
5623
5853
|
const markerColor = lineKind === "add" ? "toolDiffAdded" : lineKind === "remove" ? "toolDiffRemoved" : "borderMuted";
|
|
5624
|
-
const lineNumber = line.lineNumber.trim().padStart(this.lineNumberWidth, " ");
|
|
5625
|
-
const firstPrefixAnsi = this.
|
|
5854
|
+
const lineNumber = line.lineNumber.trim().padStart(this.ctx.lineNumberWidth, " ");
|
|
5855
|
+
const firstPrefixAnsi = this.ctx.fg(markerColor, markerChar) + " " + this.ctx.fg(this.getNumberColor(lineKind), lineNumber) + this.ctx.fg("borderMuted", " \u2502 ");
|
|
5626
5856
|
const firstPrefixPlain = `${markerChar} ${lineNumber} \u2502 `;
|
|
5627
|
-
const contPrefixAnsi = this.
|
|
5628
|
-
const contPrefixPlain = `${markerChar} ${" ".repeat(this.lineNumberWidth)} \u2502 `;
|
|
5857
|
+
const contPrefixAnsi = this.ctx.fg(markerColor, markerChar) + " " + this.ctx.fg("dim", " ".repeat(this.ctx.lineNumberWidth)) + this.ctx.fg("borderMuted", " \u2502 ");
|
|
5858
|
+
const contPrefixPlain = `${markerChar} ${" ".repeat(this.ctx.lineNumberWidth)} \u2502 `;
|
|
5629
5859
|
const codeWidth = Math.max(1, columnWidth - safeVisibleWidth(firstPrefixPlain));
|
|
5630
5860
|
const rowBg = this.getRowBackground(lineKind);
|
|
5631
5861
|
const emphasisBg = this.getEmphasisBackground(lineKind);
|
|
5632
5862
|
const plainSegments = wrapPlainText(line.line, codeWidth);
|
|
5633
5863
|
const lines = [];
|
|
5634
|
-
const spans = this.
|
|
5864
|
+
const spans = this.ctx.inlineSpans(line);
|
|
5635
5865
|
let consumed = 0;
|
|
5636
5866
|
for (let i = 0; i < plainSegments.length; i++) {
|
|
5637
5867
|
const prefixAnsi = i === 0 ? firstPrefixAnsi : contPrefixAnsi;
|
|
5638
5868
|
const prefixPlain = i === 0 ? firstPrefixPlain : contPrefixPlain;
|
|
5639
5869
|
const plainSegment = plainSegments[i] ?? "";
|
|
5640
|
-
let segment2 = this.syntaxHighlight(plainSegment);
|
|
5870
|
+
let segment2 = this.ctx.syntaxHighlight(plainSegment);
|
|
5641
5871
|
if (spans.length > 0 && emphasisBg) {
|
|
5642
5872
|
const segmentStart = consumed;
|
|
5643
5873
|
for (let si = spans.length - 1; si >= 0; si--) {
|
|
@@ -5651,7 +5881,7 @@ ${safeLine}`;
|
|
|
5651
5881
|
localStart,
|
|
5652
5882
|
localEnd,
|
|
5653
5883
|
emphasisBg,
|
|
5654
|
-
rowBg ?? this.containerBgAnsi
|
|
5884
|
+
rowBg ?? this.ctx.containerBgAnsi
|
|
5655
5885
|
);
|
|
5656
5886
|
}
|
|
5657
5887
|
}
|
|
@@ -5664,33 +5894,38 @@ ${safeLine}`;
|
|
|
5664
5894
|
rendered += " ".repeat(expectedWidth - currentWidth);
|
|
5665
5895
|
}
|
|
5666
5896
|
if (rowBg) {
|
|
5667
|
-
rendered = `${rowBg}${keepBackgroundAcrossResets(rendered, rowBg)}${this.containerBgAnsi}`;
|
|
5897
|
+
rendered = `${rowBg}${keepBackgroundAcrossResets(rendered, rowBg)}${this.ctx.containerBgAnsi}`;
|
|
5668
5898
|
}
|
|
5669
5899
|
lines.push(padRenderedLineWidth(rendered, columnWidth));
|
|
5670
5900
|
consumed += plainSegment.length;
|
|
5671
5901
|
}
|
|
5672
5902
|
return lines;
|
|
5673
5903
|
}
|
|
5904
|
+
gapLine(entry, width) {
|
|
5905
|
+
return padRenderedLineWidth(this.ctx.fg("muted", formatGapLabel(entry.hidden)), width);
|
|
5906
|
+
}
|
|
5907
|
+
omittedLine(entry, width) {
|
|
5908
|
+
return padRenderedLineWidth(this.ctx.fg("muted", formatOmittedLabel(entry.count)), width);
|
|
5909
|
+
}
|
|
5674
5910
|
render(width) {
|
|
5675
|
-
if (this.cacheWidth === width && this.cacheLines) return this.cacheLines;
|
|
5676
5911
|
const safeWidth = Math.max(20, width);
|
|
5677
|
-
const columnSeparator = this.
|
|
5912
|
+
const columnSeparator = this.ctx.fg("borderMuted", " \u2502 ");
|
|
5678
5913
|
const separatorWidth = safeVisibleWidth(stripAnsi(columnSeparator));
|
|
5679
5914
|
const leftWidth = Math.max(20, Math.floor((safeWidth - separatorWidth) / 2));
|
|
5680
5915
|
const rightWidth = Math.max(20, safeWidth - separatorWidth - leftWidth);
|
|
5681
5916
|
const formatBorderCell = (columnWidth, junction) => {
|
|
5682
5917
|
const safeColumnWidth = Math.max(1, columnWidth);
|
|
5683
5918
|
const chars = "\u2500".repeat(safeColumnWidth).split("");
|
|
5684
|
-
const dividerIndex = this.lineNumberWidth + 3;
|
|
5919
|
+
const dividerIndex = this.ctx.lineNumberWidth + 3;
|
|
5685
5920
|
if (dividerIndex >= 0 && dividerIndex < chars.length) {
|
|
5686
5921
|
chars[dividerIndex] = junction;
|
|
5687
5922
|
}
|
|
5688
|
-
return this.
|
|
5923
|
+
return this.ctx.fg("borderMuted", chars.join(""));
|
|
5689
5924
|
};
|
|
5690
5925
|
const formatHeaderCell = (label, columnWidth) => {
|
|
5691
5926
|
const markerPad = " ";
|
|
5692
|
-
const lineNumberLabel = fitToWidth(label, this.lineNumberWidth);
|
|
5693
|
-
const prefixAnsi = this.
|
|
5927
|
+
const lineNumberLabel = fitToWidth(label, this.ctx.lineNumberWidth);
|
|
5928
|
+
const prefixAnsi = this.ctx.fg("borderMuted", markerPad) + this.ctx.fg("dim", lineNumberLabel) + this.ctx.fg("borderMuted", " \u2502 ");
|
|
5694
5929
|
const prefixPlain = `${markerPad}${stripAnsi(lineNumberLabel)} \u2502 `;
|
|
5695
5930
|
const codeWidth = Math.max(0, columnWidth - safeVisibleWidth(prefixPlain));
|
|
5696
5931
|
return padRenderedLineWidth(prefixAnsi + " ".repeat(codeWidth), columnWidth);
|
|
@@ -5698,7 +5933,7 @@ ${safeLine}`;
|
|
|
5698
5933
|
const lines = [];
|
|
5699
5934
|
lines.push(
|
|
5700
5935
|
padRenderedLineWidth(
|
|
5701
|
-
formatBorderCell(leftWidth, "\u252C") + this.
|
|
5936
|
+
formatBorderCell(leftWidth, "\u252C") + this.ctx.fg("borderMuted", "\u2500\u252C\u2500") + formatBorderCell(rightWidth, "\u252C"),
|
|
5702
5937
|
safeWidth
|
|
5703
5938
|
)
|
|
5704
5939
|
);
|
|
@@ -5708,28 +5943,70 @@ ${safeLine}`;
|
|
|
5708
5943
|
safeWidth
|
|
5709
5944
|
)
|
|
5710
5945
|
);
|
|
5711
|
-
for (const
|
|
5946
|
+
for (const entry of this.entries) {
|
|
5947
|
+
if (entry.kind === "gap") {
|
|
5948
|
+
lines.push(this.gapLine(entry, safeWidth));
|
|
5949
|
+
continue;
|
|
5950
|
+
}
|
|
5951
|
+
if (entry.kind === "omitted") {
|
|
5952
|
+
lines.push(this.omittedLine(entry, safeWidth));
|
|
5953
|
+
continue;
|
|
5954
|
+
}
|
|
5955
|
+
const row = entry.row;
|
|
5712
5956
|
const leftCellLines = this.formatCellLines(row.kind, "left", row.left, leftWidth);
|
|
5713
5957
|
const rightCellLines = this.formatCellLines(row.kind, "right", row.right, rightWidth);
|
|
5714
5958
|
const rowHeight = Math.max(leftCellLines.length, rightCellLines.length);
|
|
5715
5959
|
for (let i = 0; i < rowHeight; i++) {
|
|
5716
|
-
const
|
|
5717
|
-
const
|
|
5718
|
-
const
|
|
5719
|
-
const rightCell = rightCellLines[i] ?? this.blankCell(rightFallbackKind, "right", rightWidth);
|
|
5960
|
+
const fallbackKind = row.kind === "changed" ? "context" : row.kind;
|
|
5961
|
+
const leftCell = leftCellLines[i] ?? this.blankCell(fallbackKind, "left", leftWidth);
|
|
5962
|
+
const rightCell = rightCellLines[i] ?? this.blankCell(fallbackKind, "right", rightWidth);
|
|
5720
5963
|
const joined = padRenderedLineWidth(leftCell + columnSeparator + rightCell, safeWidth);
|
|
5721
5964
|
lines.push(joined);
|
|
5722
5965
|
}
|
|
5723
5966
|
}
|
|
5724
|
-
if (this.rows.length > this.maxRows) {
|
|
5725
|
-
lines.push(this.theme.fg("muted", `... ${this.rows.length - this.maxRows} more rows`));
|
|
5726
|
-
}
|
|
5727
5967
|
lines.push(
|
|
5728
5968
|
padRenderedLineWidth(
|
|
5729
|
-
formatBorderCell(leftWidth, "\u2534") + this.
|
|
5969
|
+
formatBorderCell(leftWidth, "\u2534") + this.ctx.fg("borderMuted", "\u2500\u2534\u2500") + formatBorderCell(rightWidth, "\u2534"),
|
|
5730
5970
|
safeWidth
|
|
5731
5971
|
)
|
|
5732
5972
|
);
|
|
5973
|
+
return lines;
|
|
5974
|
+
}
|
|
5975
|
+
};
|
|
5976
|
+
var AdaptiveDiffComponent = class {
|
|
5977
|
+
constructor(theme, rows, maxRows, language) {
|
|
5978
|
+
this.rows = rows;
|
|
5979
|
+
this.ctx = new DiffRenderContext(theme, rows, language);
|
|
5980
|
+
this.stats = { additions: 0, removals: 0 };
|
|
5981
|
+
for (const row of rows) {
|
|
5982
|
+
if (row.kind === "added" || row.kind === "changed") this.stats.additions++;
|
|
5983
|
+
if (row.kind === "removed" || row.kind === "changed") this.stats.removals++;
|
|
5984
|
+
}
|
|
5985
|
+
const entries = planEntries(rows, maxRows);
|
|
5986
|
+
this.collapsed = entries.some((entry) => entry.kind !== "row");
|
|
5987
|
+
this.unified = new UnifiedDiffRenderer(this.ctx, entries);
|
|
5988
|
+
this.split = new SplitDiffRenderer(this.ctx, entries);
|
|
5989
|
+
}
|
|
5990
|
+
rows;
|
|
5991
|
+
cacheWidth;
|
|
5992
|
+
cacheLines;
|
|
5993
|
+
ctx;
|
|
5994
|
+
stats;
|
|
5995
|
+
unified;
|
|
5996
|
+
split;
|
|
5997
|
+
collapsed;
|
|
5998
|
+
/** True when any unchanged context was collapsed or rows were omitted. */
|
|
5999
|
+
hasCollapsed() {
|
|
6000
|
+
return this.collapsed;
|
|
6001
|
+
}
|
|
6002
|
+
modeForWidth(width) {
|
|
6003
|
+
return pickDiffMode(this.stats, this.rows, Math.max(20, width));
|
|
6004
|
+
}
|
|
6005
|
+
render(width) {
|
|
6006
|
+
if (this.cacheWidth === width && this.cacheLines) return this.cacheLines;
|
|
6007
|
+
const safeWidth = Math.max(20, width);
|
|
6008
|
+
const mode = this.modeForWidth(safeWidth);
|
|
6009
|
+
const lines = mode === "split" ? this.split.render(safeWidth) : this.unified.render(safeWidth);
|
|
5733
6010
|
this.cacheWidth = width;
|
|
5734
6011
|
this.cacheLines = lines;
|
|
5735
6012
|
return lines;
|
|
@@ -5737,18 +6014,32 @@ ${safeLine}`;
|
|
|
5737
6014
|
invalidate() {
|
|
5738
6015
|
this.cacheWidth = void 0;
|
|
5739
6016
|
this.cacheLines = void 0;
|
|
5740
|
-
this.highlightCache.clear();
|
|
5741
6017
|
}
|
|
5742
6018
|
};
|
|
5743
6019
|
|
|
5744
6020
|
// extension-src/pi-style/features/tools/boxed/edit.ts
|
|
5745
6021
|
var MAX_HIGHLIGHT_DIFF_CHARS = 12e3;
|
|
5746
6022
|
var MAX_HIGHLIGHT_DIFF_ROWS = 120;
|
|
6023
|
+
function diffDividerLabel(theme, stats) {
|
|
6024
|
+
const plus = stats.additions > 0 ? theme.fg("toolDiffAdded", `+${stats.additions}`) : theme.fg("dim", "+0");
|
|
6025
|
+
const minus = stats.removals > 0 ? theme.fg("toolDiffRemoved", `-${stats.removals}`) : theme.fg("dim", "-0");
|
|
6026
|
+
return `Diff \xB7 ${plus} ${minus}`;
|
|
6027
|
+
}
|
|
6028
|
+
function editDiffFooter(theme, result, context, stats) {
|
|
6029
|
+
const elapsedMs = getElapsedMs(result) ?? stateElapsedMs(context);
|
|
6030
|
+
const parts = [];
|
|
6031
|
+
if (elapsedMs !== void 0) parts.push(theme.fg("text", formatElapsedMs(elapsedMs)));
|
|
6032
|
+
const plus = stats.additions > 0 ? theme.fg("toolDiffAdded", `+${stats.additions}`) : theme.fg("dim", "+0");
|
|
6033
|
+
const minus = stats.removals > 0 ? theme.fg("toolDiffRemoved", `-${stats.removals}`) : theme.fg("dim", "-0");
|
|
6034
|
+
parts.push(theme.fg("dim", "1 file"), `${plus} ${minus}`);
|
|
6035
|
+
return parts.join(theme.fg("dim", " \xB7 "));
|
|
6036
|
+
}
|
|
5747
6037
|
var editTool = {
|
|
5748
6038
|
call(args, theme, context) {
|
|
5749
6039
|
noteExecutionStart(context);
|
|
5750
6040
|
const detail = displayPath(String(args?.path ?? args?.file_path ?? ""), context);
|
|
5751
|
-
return renderBoxedToolCall(theme, "Edit", [
|
|
6041
|
+
return renderBoxedToolCall(theme, "Edit", [], {
|
|
6042
|
+
headerDetail: detail,
|
|
5752
6043
|
isError: Boolean(context.isError),
|
|
5753
6044
|
isPartial: Boolean(context.isPartial),
|
|
5754
6045
|
isPending: Boolean(context.isPartial)
|
|
@@ -5783,25 +6074,24 @@ var editTool = {
|
|
|
5783
6074
|
const rows = buildSplitRows(diff);
|
|
5784
6075
|
const expanded = options.expanded;
|
|
5785
6076
|
const shouldHighlight = Boolean(language) && diff.length <= MAX_HIGHLIGHT_DIFF_CHARS && rows.length <= MAX_HIGHLIGHT_DIFF_ROWS;
|
|
5786
|
-
const
|
|
5787
|
-
const meter = renderDiffMeter(theme, additions, removals);
|
|
5788
|
-
const summary = `${theme.fg("dim", "\u21B3")} ${theme.fg("muted", "diff")} ${theme.fg("toolDiffAdded", `+${additions}`)} ${theme.fg("toolDiffRemoved", `-${removals}`)} ${theme.fg("muted", "split")}` + (meter ? ` ${meter}` : "");
|
|
6077
|
+
const stats = countDiffStats(diff);
|
|
5789
6078
|
const maxRows = expanded ? 160 : 36;
|
|
5790
|
-
const
|
|
6079
|
+
const diffView = new AdaptiveDiffComponent(theme, rows, maxRows, shouldHighlight ? language : void 0);
|
|
6080
|
+
const expandHint2 = !expanded && diffView.hasCollapsed() ? "Ctrl+O more" : void 0;
|
|
5791
6081
|
return renderBoxedToolResult(
|
|
5792
6082
|
theme,
|
|
5793
6083
|
{
|
|
5794
6084
|
render(width) {
|
|
5795
|
-
|
|
5796
|
-
const headerLines = new Text(summary, 0, 0).render(safeWidth);
|
|
5797
|
-
return [...headerLines, ...split.render(safeWidth)];
|
|
6085
|
+
return diffView.render(width);
|
|
5798
6086
|
},
|
|
5799
6087
|
invalidate() {
|
|
5800
|
-
|
|
6088
|
+
diffView.invalidate();
|
|
5801
6089
|
}
|
|
5802
6090
|
},
|
|
5803
6091
|
{
|
|
5804
|
-
|
|
6092
|
+
dividerLabel: diffDividerLabel(theme, stats),
|
|
6093
|
+
...expandHint2 ? { dividerRightLabel: expandHint2 } : {},
|
|
6094
|
+
footerLines: [editDiffFooter(theme, result, context, stats)]
|
|
5805
6095
|
}
|
|
5806
6096
|
);
|
|
5807
6097
|
}
|
|
@@ -5823,19 +6113,20 @@ function renderFallbackResult(_toolName, result, options, theme, context) {
|
|
|
5823
6113
|
const maxLines = expanded ? getToolsRenderConfig().maxExpandedLines : MAX_FALLBACK_PREVIEW_LINES;
|
|
5824
6114
|
const output = getTextOutput(result);
|
|
5825
6115
|
const elapsedMs = getStateElapsedMs(context.state);
|
|
6116
|
+
const { lines, omitted } = selectRenderLines(output, maxLines);
|
|
5826
6117
|
return renderBoxedToolResult(
|
|
5827
6118
|
theme,
|
|
5828
|
-
(
|
|
5829
|
-
const body =
|
|
5830
|
-
|
|
5831
|
-
|
|
5832
|
-
|
|
5833
|
-
|
|
5834
|
-
return body ? body.split("\n") : [];
|
|
6119
|
+
() => {
|
|
6120
|
+
const body = lines.map((line) => formatToolOutputLine(theme, line, isError ? "error" : "toolOutput"));
|
|
6121
|
+
if (expanded && omitted > 0) {
|
|
6122
|
+
body.push(theme.fg("muted", `\u2026 ${omitted} more lines omitted by render budget`));
|
|
6123
|
+
}
|
|
6124
|
+
return body;
|
|
5835
6125
|
},
|
|
5836
6126
|
{
|
|
5837
6127
|
footerLines: [formatBoxedFooter(theme, result, [], elapsedMs)],
|
|
5838
6128
|
renderLineBudget: maxLines,
|
|
6129
|
+
...expanded || omitted <= 0 ? {} : { expandHint: "Ctrl+O for more" },
|
|
5839
6130
|
isError,
|
|
5840
6131
|
isPartial: Boolean(options.isPartial)
|
|
5841
6132
|
}
|
|
@@ -6004,7 +6295,6 @@ var lsTool = {
|
|
|
6004
6295
|
|
|
6005
6296
|
// extension-src/pi-style/features/tools/boxed/quick-edit.ts
|
|
6006
6297
|
import { getLanguageFromPath as getLanguageFromPath2 } from "@earendil-works/pi-coding-agent";
|
|
6007
|
-
import { Text as Text2 } from "@earendil-works/pi-tui";
|
|
6008
6298
|
var MAX_HIGHLIGHT_DIFF_CHARS2 = 12e3;
|
|
6009
6299
|
var MAX_HIGHLIGHT_DIFF_ROWS2 = 120;
|
|
6010
6300
|
var QUICK_EDIT_TOOLS = {
|
|
@@ -6073,8 +6363,19 @@ function extractQuickEditDiff(text) {
|
|
|
6073
6363
|
}
|
|
6074
6364
|
return diffLines.length > 0 ? diffLines.join("\n") : void 0;
|
|
6075
6365
|
}
|
|
6076
|
-
function
|
|
6077
|
-
|
|
6366
|
+
function quickEditDividerLabel(theme, stats) {
|
|
6367
|
+
const plus = stats.additions > 0 ? theme.fg("toolDiffAdded", `+${stats.additions}`) : theme.fg("dim", "+0");
|
|
6368
|
+
const minus = stats.removals > 0 ? theme.fg("toolDiffRemoved", `-${stats.removals}`) : theme.fg("dim", "-0");
|
|
6369
|
+
return `Diff \xB7 ${plus} ${minus}`;
|
|
6370
|
+
}
|
|
6371
|
+
function quickEditDiffFooter(theme, result, context, stats) {
|
|
6372
|
+
const elapsedMs = getElapsedMs(result) ?? getStateElapsedMs(context.state);
|
|
6373
|
+
const parts = [];
|
|
6374
|
+
if (elapsedMs !== void 0) parts.push(theme.fg("text", formatElapsedMs(elapsedMs)));
|
|
6375
|
+
const plus = stats.additions > 0 ? theme.fg("toolDiffAdded", `+${stats.additions}`) : theme.fg("dim", "+0");
|
|
6376
|
+
const minus = stats.removals > 0 ? theme.fg("toolDiffRemoved", `-${stats.removals}`) : theme.fg("dim", "-0");
|
|
6377
|
+
parts.push(theme.fg("dim", "1 file"), `${plus} ${minus}`);
|
|
6378
|
+
return parts.join(theme.fg("dim", " \xB7 "));
|
|
6078
6379
|
}
|
|
6079
6380
|
function renderQuickEditResult(_toolName, result, options, theme, context, config) {
|
|
6080
6381
|
if (options.isPartial) {
|
|
@@ -6087,7 +6388,7 @@ function renderQuickEditResult(_toolName, result, options, theme, context, confi
|
|
|
6087
6388
|
const output = getTextOutput(result);
|
|
6088
6389
|
if (context.isError) {
|
|
6089
6390
|
return renderBoxedToolResult(theme, () => [theme.fg("error", stripAnsi(output).trim() || "Error")], {
|
|
6090
|
-
footerLines: [quickEditFooter(theme, context
|
|
6391
|
+
footerLines: [quickEditFooter(theme, context)],
|
|
6091
6392
|
isError: true
|
|
6092
6393
|
});
|
|
6093
6394
|
}
|
|
@@ -6095,7 +6396,7 @@ function renderQuickEditResult(_toolName, result, options, theme, context, confi
|
|
|
6095
6396
|
if (!diff) {
|
|
6096
6397
|
const fallback = stripAnsi(output).trim() || config.fallbackLabel;
|
|
6097
6398
|
return renderBoxedToolResult(theme, () => [`${theme.fg("dim", "\u21B3")} ${theme.fg("muted", fallback)}`], {
|
|
6098
|
-
footerLines: [quickEditFooter(theme, context
|
|
6399
|
+
footerLines: [quickEditFooter(theme, context)]
|
|
6099
6400
|
});
|
|
6100
6401
|
}
|
|
6101
6402
|
const rows = buildSplitRows(diff);
|
|
@@ -6103,34 +6404,41 @@ function renderQuickEditResult(_toolName, result, options, theme, context, confi
|
|
|
6103
6404
|
const argPath = String(context?.args?.path ?? "");
|
|
6104
6405
|
const language = argPath ? getLanguageFromPath2(argPath) : void 0;
|
|
6105
6406
|
const shouldHighlight = Boolean(language) && diff.length <= MAX_HIGHLIGHT_DIFF_CHARS2 && rows.length <= MAX_HIGHLIGHT_DIFF_ROWS2;
|
|
6106
|
-
const
|
|
6107
|
-
const meter = renderDiffMeter(theme, additions, removals);
|
|
6108
|
-
const summary = `${theme.fg("dim", "\u21B3")} ${theme.fg("muted", "diff")} ${theme.fg("toolDiffAdded", `+${additions}`)} ${theme.fg("toolDiffRemoved", `-${removals}`)} ${theme.fg("muted", "split")}` + (meter ? ` ${meter}` : "");
|
|
6407
|
+
const stats = countDiffStats(diff);
|
|
6109
6408
|
const maxRows = expanded ? 160 : 36;
|
|
6110
|
-
const
|
|
6409
|
+
const diffView = new AdaptiveDiffComponent(theme, rows, maxRows, shouldHighlight ? language : void 0);
|
|
6410
|
+
const expandHint2 = !expanded && diffView.hasCollapsed() ? "Ctrl+O more" : void 0;
|
|
6111
6411
|
return renderBoxedToolResult(
|
|
6112
6412
|
theme,
|
|
6113
6413
|
{
|
|
6114
6414
|
render(width) {
|
|
6115
|
-
|
|
6116
|
-
const headerLines = new Text2(summary, 0, 0).render(safeWidth);
|
|
6117
|
-
return [...headerLines, ...split.render(safeWidth)];
|
|
6415
|
+
return diffView.render(width);
|
|
6118
6416
|
},
|
|
6119
6417
|
invalidate() {
|
|
6120
|
-
|
|
6418
|
+
diffView.invalidate();
|
|
6121
6419
|
}
|
|
6122
6420
|
},
|
|
6123
6421
|
{
|
|
6124
|
-
|
|
6422
|
+
dividerLabel: quickEditDividerLabel(theme, stats),
|
|
6423
|
+
...expandHint2 ? { dividerRightLabel: expandHint2 } : {},
|
|
6424
|
+
footerLines: [quickEditDiffFooter(theme, result, context, stats)]
|
|
6125
6425
|
}
|
|
6126
6426
|
);
|
|
6127
6427
|
}
|
|
6428
|
+
function quickEditFooter(theme, context) {
|
|
6429
|
+
const elapsedMs = getStateElapsedMs(context.state);
|
|
6430
|
+
const parts = [];
|
|
6431
|
+
if (elapsedMs !== void 0) parts.push(theme.fg("text", formatElapsedMs(elapsedMs)));
|
|
6432
|
+
parts.push(theme.fg("dim", "1 file"));
|
|
6433
|
+
return parts.join(theme.fg("dim", " \xB7 "));
|
|
6434
|
+
}
|
|
6128
6435
|
function quickEditTool(config) {
|
|
6129
6436
|
return {
|
|
6130
6437
|
call(args, theme, context) {
|
|
6131
6438
|
noteExecutionStart(context);
|
|
6132
6439
|
const detail = displayPath(String(args?.path ?? ""), context);
|
|
6133
|
-
return renderBoxedToolCall(theme, config.toolLabel, [
|
|
6440
|
+
return renderBoxedToolCall(theme, config.toolLabel, [], {
|
|
6441
|
+
headerDetail: detail,
|
|
6134
6442
|
isError: Boolean(context.isError),
|
|
6135
6443
|
isPartial: Boolean(context.isPartial),
|
|
6136
6444
|
isPending: Boolean(context.isPartial)
|
|
@@ -7788,7 +8096,6 @@ function createPiStyleSessionCoordinator(pi, hooks = {}) {
|
|
|
7788
8096
|
terminalInputUnsubscribe?.();
|
|
7789
8097
|
terminalInputUnsubscribe = void 0;
|
|
7790
8098
|
app.sessionShutdown();
|
|
7791
|
-
compatibility.dispose();
|
|
7792
8099
|
}
|
|
7793
8100
|
};
|
|
7794
8101
|
}
|