Repository navigation
fix(pretty): prefer details.patch over details.diff for edit tool rendering - #1
Conversation
0054ebc to
4bb3bb2
Compare
4bb3bb2 to
522d60c
Compare
|
@hypnguyen1209 could you take a look at the two small fix PRs I have open here when you get a chance? Both are one-liner changes with tests attached — details are in each description. |
hypnguyen1209
left a comment
There was a problem hiding this comment.
Thanks, this is a real bug and the diagnosis is right: details.diff has no @@ hunk headers, so buildSplit and colorizeDiff never entered a hunk and the split view / word emphasis / old-new gutters silently did nothing for edit results. I confirmed details.patch has been there since pi 0.75.5 (feat(coding-agent): expose edit tool unified patch), well below this package's ^0.87.0 peer floor, so the fallback only matters for odd hosts.
I rendered the change with a patch generated by pi's own generateUnifiedPatch (diff.createTwoFilesPatch(..., { context: 4, headerOptions: FILE_HEADERS_ONLY })) rather than the fixture, and two things show up that the fixture hides:
- The file header lines are drawn. pi's patch starts with
--- src/a.ts/+++ src/a.ts; they come through dimmed inside the result, right under a call line that already saysEdit src/a.ts. The pre-apply preview (src/linediff.ts) emits hunks only, so the result and the preview now disagree. - A phantom last line. pi's patch always ends with
\n, so the split produces a trailing empty line, which the gutter numbers as line 6 of a 5-line file (and the split view draws it as an empty row on both sides). The fixture in the test has no trailing newline, so the test cannot see this.
Both are one strip away, see the inline suggestion. With it applied the result is @@ -1,5 +1,5 @@ + gutters/split, nothing else, and the whole suite (134 tests) stays green; I ran it locally against your branch.
One more small ask for the test: the fixture's leading =====... line is not something pi emits (FILE_HEADERS_ONLY drops the Index: and ==== lines), and the fixture should end with \n like a real patch, so that the phantom-line case is actually covered. Then this is good to merge.
| function extractEditDiff(result: unknown): string { | ||
| if (!isRecord(result) || !isRecord(result.details)) return ""; | ||
| const { patch, diff } = result.details; | ||
| if (typeof patch === "string" && patch) return patch; |
There was a problem hiding this comment.
pi's patch is --- path, +++ path, hunks, trailing newline. The call line already names the path, and the trailing newline draws as a phantom, numbered empty last line. Strip both here so the result matches the pre-apply preview, which emits hunks only:
| if (typeof patch === "string" && patch) return patch; | |
| if (typeof patch === "string" && patch) { | |
| // pi's patch is `--- path`, `+++ path`, then hunks, with a trailing | |
| // newline. The call line already names the path, and the trailing | |
| // newline would draw as a phantom, numbered empty last line. | |
| return patch | |
| .replace(/\n$/, "") | |
| .split("\n") | |
| .filter((line, i) => !(i < 2 && (line.startsWith("--- ") || line.startsWith("+++ ")))) | |
| .join("\n"); | |
| } |
…dering pi's edit tool result details provides both `patch` (standard unified diff with hunk headers) and `diff` (pre-formatted line-numbered diff without hunk headers). The edit renderer previously read only `details.diff`, causing both word-level emphasis and side-by-side split (`diffSplit`) to silently fall back because they require `@@` hunk headers to pair lines. Add `extractEditDiff` to prefer `details.patch` when available, falling back to `details.diff`. The patch's `--- path` / `+++ path` header lines and its trailing newline (which draws as a phantom, numbered empty last line) are stripped, so the result body matches the pre-apply preview, which emits hunks only.
522d60c to
8af7444
Compare
|
Applied — the patch's |
hypnguyen1209
left a comment
There was a problem hiding this comment.
Applied exactly, and the fixture is now the real patch shape with the trailing newline, so the phantom-row case is covered. Re-verified on top of main (0.14.0): typecheck clean, 134 tests pass, CI green on 8af7444. Merging. Thanks!
- Edit results render from details.patch (pi's unified patch with hunk headers) instead of details.diff, so side-by-side split, word-level emphasis and the old/new gutter finally work for edit; the patch's file headers and trailing newline are stripped so the result matches the pre-apply preview (#1 by @iamxeph). - The read summary coerces string-typed offset/limit before computing the line range, so "1" + "2000" no longer reads as lines 1-11999, and a non-numeric value is left out of the range (#2 by @iamxeph).
Problem
When
diffSplit: trueis enabled, theedittool diff never renders in side-by-side mode and silently falls back to a unified diff. Similarly, word-level diff emphasis and line-number gutters fail to activate foreditresults, degrading to plain line-colored output.Root Cause
In pi's core
edittool (packages/coding-agent/src/core/tools/edit.ts),EditToolDetailsexplicitly provides two diff representations:When executing an edit:
extensions/pretty.tspreviously read onlyresult.details.diff(the display-oriented diff which lacks@@hunk headers). Becausedetails.diffdoes not contain@@hunk headers, theinHunkstate in bothsrc/split.ts(parseRows) andsrc/diff.tsremainedfalseacross all lines. Consequently:buildSplittreated every line as an unparsedfullrow, failing to split into columns.colorizeDiffskipped paired word-diff analysis and line-number gutter formatting.Solution
extractEditDiff(result)inextensions/pretty.tsto preferdetails.patchwhen available, falling back todetails.diff.details.patch(the standard unified patch) consumed,buildSplitandcolorizeDiffreceive the expected hunk headers, allowing side-by-side split rendering, word-level emphasis, and line gutters to work as originally designed without altering any core parser logic.Verification
test/wire.test.ts:edit result prefers details.patch over details.diff(verifies split view separator│is present whendiffSplitis on)edit result falls back to details.diff when details.patch is absentbun run typecheck: clean (0 errors).bun test: all 124 tests passed (0 failed).