"use client"; import { useCallback, useLayoutEffect, useMemo, useRef } from "react"; import { DiffEditor, type DiffOnMount } from "@monaco-editor/react"; import type { editor as monacoEditor } from "monaco-editor"; import { useTheme } from "next-themes"; import { cn } from "@/lib/utils"; import type { FileDiffData } from "@/lib/diff/types"; import { getMonacoLanguage } from "@/lib/editor/language-map"; import { EDITOR_FONT_FAMILY } from "@/lib/theme/editor-theme"; import { initMonacoThemes } from "./monaco-init"; initMonacoThemes(); type MonacoInlineDiffProps = { data: FileDiffData; className?: string; }; /** Parse original/modified content from diff data. */ function parseDiffData(data: FileDiffData): { original: string; modified: string } { if (data.oldContent || data.newContent) { return { original: data.oldContent ?? "", modified: data.newContent ?? "" }; } if (data.diff) { return parsePatchToSides(data.diff); } return { original: "", modified: "" }; } /** Reconstruct original/modified sides from a unified diff patch. */ function parsePatchToSides(diff: string): { original: string; modified: string } { const originalLines: string[] = []; const modifiedLines: string[] = []; for (const line of diff.split("\n")) { if ( line.startsWith("diff ") || line.startsWith("index ") || line.startsWith("--- ") || line.startsWith("+++ ") || line.startsWith("@@") || line.startsWith("\\") ) continue; if (line.startsWith("-")) { originalLines.push(line.slice(1)); } else if (line.startsWith("+")) { modifiedLines.push(line.slice(1)); } else { const content = line.startsWith(" ") ? line.slice(1) : line; originalLines.push(content); modifiedLines.push(content); } } return { original: originalLines.join("\n"), modified: modifiedLines.join("\n") }; } export function MonacoInlineDiff({ data, className }: MonacoInlineDiffProps) { const { resolvedTheme } = useTheme(); const language = getMonacoLanguage(data.filePath); const diffEditorRef = useRef(null); const handleMount: DiffOnMount = useCallback((editor) => { diffEditorRef.current = editor; }, []); // Fix: reset model before @monaco-editor/react's cleanup disposes models useLayoutEffect(() => { return () => { try { diffEditorRef.current?.setModel(null); } catch { /* already disposed */ } }; }, []); const { original, modified } = useMemo(() => parseDiffData(data), [data]); const lineCount = Math.max(original.split("\n").length, modified.split("\n").length); const height = Math.min(Math.max(lineCount * 16 + 8, 48), 300); return (
); }