返回 DeepSeek-Reasonix
HljsDiff.tsx
根目录 / desktop / frontend / src / components / editors / HljsDiff.tsx
1 import { useRef } from "react";
2 import { useVirtualizer } from "@tanstack/react-virtual";
3 import type { DiffProps } from "../DiffView";
4 import { diffLines, diffRowsFromUnifiedDiff } from "../../lib/diff";
5 import { highlightToHtml } from "../../lib/highlight";
6
7 // HljsDiff is the syntax-highlighted default behind the diff seam: an LCS line
8 // diff with a +/- gutter, each line highlighted in the target language. A real
9 // editor (Monaco DiffEditor / CodeMirror merge) would replace this via
10 // DiffView.tsx's lazy import.
11 const SIGN: Record<"ctx" | "add" | "del", string> = { ctx: " ", add: "+", del: "-" };
12
13 function lineNo(n?: number): string {
14 return typeof n === "number" ? String(n) : "";
15 }
16
17 export default function HljsDiff({ original = "", modified = "", diff = "", language, maxHeight }: DiffProps) {
18 const rows = diff ? diffRowsFromUnifiedDiff(diff) : diffLines(original, modified);
19 const scrollRef = useRef<HTMLDivElement>(null);
20
21 const isVirtual = rows.length > 200;
22
23 const virtualizer = useVirtualizer({
24 count: isVirtual ? rows.length : 0,
25 getScrollElement: () => scrollRef.current,
26 estimateSize: () => 24,
27 overscan: 10,
28 directDomUpdates: true,
29 });
30
31 const renderRow = (r: typeof rows[0], idx: number) => (
32 <div key={idx} className={`diff__row diff__row--${r.type}`}>
33 <span className="diff__gutter">
34 <span className="diff__line diff__line--old">{lineNo(r.oldLine)}</span>
35 <span className="diff__line diff__line--new">{lineNo(r.newLine)}</span>
36 <span className="diff__sign">{SIGN[r.type]}</span>
37 </span>
38 <code
39 className="diff__text"
40 dangerouslySetInnerHTML={{ __html: highlightToHtml(r.text, language) }}
41 />
42 </div>
43 );
44
45 return (
46 <div
47 ref={scrollRef}
48 className="diff hljs"
49 style={{
50 maxHeight: maxHeight || undefined,
51 overflow: (maxHeight || isVirtual) ? "auto" : undefined,
52 position: (maxHeight || isVirtual) ? "relative" : undefined,
53 }}
54 >
55 {isVirtual ? (
56 <div
57 ref={virtualizer.containerRef}
58 className="diff__table"
59 style={{
60 width: "100%",
61 position: "relative",
62 }}
63 >
64 {virtualizer.getVirtualItems().map((row) => {
65 const item = rows[row.index];
66 if (!item) return null;
67 return (
68 <div
69 key={row.key}
70 data-index={row.index}
71 ref={virtualizer.measureElement}
72 style={{
73 position: "absolute",
74 top: 0,
75 left: 0,
76 width: "100%",
77 }}
78 >
79 {renderRow(item, row.index)}
80 </div>
81 );
82 })}
83 </div>
84 ) : (
85 <div className="diff__table">
86 {rows.map((r, idx) => renderRow(r, idx))}
87 </div>
88 )}
89 </div>
90 );
91 }
92
92 lines Plain Text