Skip to content

Commit 7df98e5

Browse files
committed
Cleanup and formatting
1 parent e714a22 commit 7df98e5

File tree

3 files changed

+147
-224
lines changed

3 files changed

+147
-224
lines changed

webview-ui/src/components/common/DiffView.tsx

Lines changed: 26 additions & 224 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
import { memo, useMemo, useEffect, useState } from "react"
2-
import { parsePatch } from "diff"
2+
import { parseUnifiedDiff } from "@src/utils/parseUnifiedDiff"
33
import { toJsxRuntime } from "hast-util-to-jsx-runtime"
44
import { Fragment, jsx, jsxs } from "react/jsx-runtime"
55
import { getHighlighter, normalizeLanguage } from "@src/utils/highlighter"
@@ -10,14 +10,6 @@ interface DiffViewProps {
1010
filePath?: string
1111
}
1212

13-
interface DiffLine {
14-
oldLineNum: number | null
15-
newLineNum: number | null
16-
type: "context" | "addition" | "deletion" | "gap"
17-
content: string
18-
hiddenCount?: number
19-
}
20-
2113
/**
2214
* DiffView component renders unified diffs with side-by-side line numbers
2315
* matching VSCode's diff editor style
@@ -85,261 +77,71 @@ const DiffView = memo(({ source, filePath }: DiffViewProps) => {
8577
}
8678
}
8779

88-
// Parse diff and extract line information
89-
const diffLines = useMemo(() => {
90-
if (!source) return []
91-
92-
try {
93-
const patches = parsePatch(source)
94-
if (!patches || patches.length === 0) return []
95-
96-
const lines: DiffLine[] = []
97-
const patch = filePath
98-
? (patches.find((p) =>
99-
[p.newFileName, p.oldFileName].some(
100-
(n) => typeof n === "string" && (n === filePath || n?.endsWith("/" + filePath)),
101-
),
102-
) ?? patches[0])
103-
: patches[0]
104-
105-
if (!patch) return []
106-
107-
let prevHunk: any = null
108-
for (const hunk of patch.hunks) {
109-
// Insert a compact "hidden lines" separator between hunks
110-
if (prevHunk) {
111-
const gapNew = hunk.newStart - (prevHunk.newStart + prevHunk.newLines)
112-
const gapOld = hunk.oldStart - (prevHunk.oldStart + prevHunk.oldLines)
113-
const hidden = Math.max(gapNew, gapOld)
114-
if (hidden > 0) {
115-
lines.push({
116-
oldLineNum: null,
117-
newLineNum: null,
118-
type: "gap",
119-
content: "",
120-
hiddenCount: hidden,
121-
})
122-
}
123-
}
124-
125-
let oldLine = hunk.oldStart
126-
let newLine = hunk.newStart
127-
128-
for (const line of hunk.lines) {
129-
const firstChar = line[0]
130-
const content = line.slice(1)
131-
132-
if (firstChar === "-") {
133-
lines.push({
134-
oldLineNum: oldLine,
135-
newLineNum: null,
136-
type: "deletion",
137-
content,
138-
})
139-
oldLine++
140-
} else if (firstChar === "+") {
141-
lines.push({
142-
oldLineNum: null,
143-
newLineNum: newLine,
144-
type: "addition",
145-
content,
146-
})
147-
newLine++
148-
} else {
149-
// Context line
150-
lines.push({
151-
oldLineNum: oldLine,
152-
newLineNum: newLine,
153-
type: "context",
154-
content,
155-
})
156-
oldLine++
157-
newLine++
158-
}
159-
}
160-
161-
prevHunk = hunk
162-
}
163-
164-
return lines
165-
} catch (error) {
166-
console.error("[DiffView] Failed to parse diff:", error)
167-
return []
168-
}
169-
}, [source, filePath])
80+
// Parse diff server-provided unified patch into renderable lines
81+
const diffLines = useMemo(() => parseUnifiedDiff(source, filePath), [source, filePath])
17082

17183
return (
172-
<div
173-
style={{
174-
backgroundColor: "var(--vscode-editor-background)",
175-
borderRadius: "6px",
176-
overflow: "hidden",
177-
fontFamily: "var(--vscode-editor-font-family)",
178-
fontSize: "0.95em",
179-
}}>
180-
<div style={{ overflowX: "hidden" }}>
181-
<table
182-
style={{
183-
width: "100%",
184-
borderCollapse: "collapse",
185-
tableLayout: "auto",
186-
}}>
84+
<div className="diff-view bg-[var(--vscode-editor-background)] rounded-md overflow-hidden text-[0.95em]">
85+
<div className="overflow-x-hidden">
86+
<table className="w-full border-collapse table-auto">
18787
<tbody>
18888
{diffLines.map((line, idx) => {
18989
// Render compact separator between hunks
19090
if (line.type === "gap") {
191-
// Match the header/container background tone
192-
const gapBg = "var(--vscode-editor-background)"
91+
// Compact separator between hunks
19392
return (
19493
<tr key={idx}>
195-
<td
196-
style={{
197-
width: "45px",
198-
textAlign: "right",
199-
paddingRight: "12px",
200-
paddingLeft: "8px",
201-
userSelect: "none",
202-
verticalAlign: "top",
203-
whiteSpace: "nowrap",
204-
backgroundColor: gapBg,
205-
}}
206-
/>
207-
<td
208-
style={{
209-
width: "45px",
210-
textAlign: "right",
211-
paddingRight: "12px",
212-
userSelect: "none",
213-
verticalAlign: "top",
214-
whiteSpace: "nowrap",
215-
backgroundColor: gapBg,
216-
}}
217-
/>
218-
<td
219-
style={{
220-
width: "12px",
221-
backgroundColor: gapBg,
222-
verticalAlign: "top",
223-
}}
224-
/>
94+
<td className="w-[45px] text-right pr-3 pl-2 select-none align-top whitespace-nowrap bg-[var(--vscode-editor-background)]" />
95+
<td className="w-[45px] text-right pr-3 select-none align-top whitespace-nowrap bg-[var(--vscode-editor-background)]" />
96+
<td className="w-[12px] align-top bg-[var(--vscode-editor-background)]" />
22597
{/* +/- column (empty for gap) */}
226-
<td
227-
style={{
228-
width: "16px",
229-
textAlign: "center",
230-
userSelect: "none",
231-
backgroundColor: gapBg,
232-
}}
233-
/>
234-
<td
235-
style={{
236-
paddingRight: "12px",
237-
whiteSpace: "pre-wrap",
238-
overflowWrap: "anywhere",
239-
wordBreak: "break-word",
240-
fontFamily: "var(--vscode-editor-font-family)",
241-
width: "100%",
242-
textAlign: "left",
243-
fontStyle: "italic",
244-
backgroundColor: gapBg,
245-
}}>
98+
<td className="w-[16px] text-center select-none bg-[var(--vscode-editor-background)]" />
99+
<td className="pr-3 whitespace-pre-wrap break-words w-full italic bg-[var(--vscode-editor-background)]">
246100
{`${line.hiddenCount ?? 0} hidden lines`}
247101
</td>
248102
</tr>
249103
)
250104
}
251105

252-
// Use VSCode's built-in diff editor color variables with 50% opacity
253-
const gutterBg =
106+
// Use VSCode's built-in diff editor color variables as classes for gutters
107+
const gutterBgClass =
254108
line.type === "addition"
255-
? "var(--vscode-diffEditor-insertedTextBackground)"
109+
? "bg-[var(--vscode-diffEditor-insertedTextBackground)]"
256110
: line.type === "deletion"
257-
? "var(--vscode-diffEditor-removedTextBackground)"
258-
: "var(--vscode-editorGroup-border)"
111+
? "bg-[var(--vscode-diffEditor-removedTextBackground)]"
112+
: "bg-[var(--vscode-editorGroup-border)]"
259113

260-
const contentBgStyles =
114+
const contentBgClass =
261115
line.type === "addition"
262-
? {
263-
backgroundColor:
264-
"color-mix(in srgb, var(--vscode-diffEditor-insertedTextBackground) 70%, transparent)",
265-
}
116+
? "diff-content-inserted"
266117
: line.type === "deletion"
267-
? {
268-
backgroundColor:
269-
"color-mix(in srgb, var(--vscode-diffEditor-removedTextBackground) 70%, transparent)",
270-
}
271-
: {
272-
backgroundColor:
273-
"color-mix(in srgb, var(--vscode-editorGroup-border) 100%, transparent)",
274-
}
118+
? "diff-content-removed"
119+
: "diff-content-context"
275120

276121
const sign = line.type === "addition" ? "+" : line.type === "deletion" ? "-" : ""
277122

278123
return (
279124
<tr key={idx}>
280125
{/* Old line number */}
281126
<td
282-
style={{
283-
width: "45px",
284-
textAlign: "right",
285-
paddingRight: "4px",
286-
paddingLeft: "4px",
287-
userSelect: "none",
288-
verticalAlign: "top",
289-
whiteSpace: "nowrap",
290-
backgroundColor: gutterBg,
291-
}}>
127+
className={`w-[45px] text-right pr-1 pl-1 select-none align-top whitespace-nowrap ${gutterBgClass}`}>
292128
{line.oldLineNum || ""}
293129
</td>
294130
{/* New line number */}
295131
<td
296-
style={{
297-
width: "45px",
298-
textAlign: "right",
299-
paddingRight: "4px",
300-
userSelect: "none",
301-
verticalAlign: "top",
302-
whiteSpace: "nowrap",
303-
backgroundColor: gutterBg,
304-
}}>
132+
className={`w-[45px] text-right pr-1 select-none align-top whitespace-nowrap ${gutterBgClass}`}>
305133
{line.newLineNum || ""}
306134
</td>
307135
{/* Narrow colored gutter */}
308-
<td
309-
style={{
310-
width: "12px",
311-
backgroundColor: gutterBg,
312-
verticalAlign: "top",
313-
}}
314-
/>
136+
<td className={`w-[12px] ${gutterBgClass} align-top`} />
315137
{/* +/- fixed column to prevent wrapping into it */}
316138
<td
317-
style={{
318-
width: "16px",
319-
textAlign: "center",
320-
userSelect: "none",
321-
whiteSpace: "nowrap",
322-
paddingLeft: "4px",
323-
paddingRight: "4px",
324-
backgroundColor: gutterBg,
325-
color: "var(--vscode-editor-foreground)",
326-
fontFamily: "var(--vscode-editor-font-family)",
327-
}}>
139+
className={`w-[16px] text-center select-none whitespace-nowrap px-1 ${gutterBgClass}`}>
328140
{sign}
329141
</td>
330142
{/* Code content (no +/- prefix here) */}
331143
<td
332-
style={{
333-
paddingLeft: "4px",
334-
paddingRight: "12px",
335-
whiteSpace: "pre-wrap",
336-
overflowWrap: "anywhere",
337-
wordBreak: "break-word",
338-
fontFamily: "var(--vscode-editor-font-family)",
339-
color: "var(--vscode-editor-foreground)",
340-
width: "100%",
341-
...contentBgStyles,
342-
}}>
144+
className={`pl-1 pr-3 whitespace-pre-wrap break-words w-full ${contentBgClass}`}>
343145
{renderHighlighted(line.content)}
344146
</td>
345147
</tr>

webview-ui/src/index.css

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -490,3 +490,28 @@ input[cmdk-input]:focus {
490490
transition-timing-function: cubic-bezier(0.4, 0, 0.2, 1);
491491
transition-duration: 150ms;
492492
}
493+
494+
/* DiffView code font: use VS Code editor font and enable ligatures */
495+
.diff-view,
496+
.diff-view pre,
497+
.diff-view code,
498+
.diff-view .hljs {
499+
font-family:
500+
var(--vscode-editor-font-family), ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, "Liberation Mono",
501+
"Courier New", monospace;
502+
font-variant-ligatures: contextual;
503+
font-feature-settings:
504+
"calt" 1,
505+
"liga" 1;
506+
}
507+
508+
/* DiffView background tints via CSS classes instead of inline styles */
509+
.diff-content-inserted {
510+
background-color: color-mix(in srgb, var(--vscode-diffEditor-insertedTextBackground) 70%, transparent);
511+
}
512+
.diff-content-removed {
513+
background-color: color-mix(in srgb, var(--vscode-diffEditor-removedTextBackground) 70%, transparent);
514+
}
515+
.diff-content-context {
516+
background-color: color-mix(in srgb, var(--vscode-editorGroup-border) 100%, transparent);
517+
}

0 commit comments

Comments
 (0)