diff --git a/site/src/components/SyntaxHighlighter/SyntaxHighlighter.tsx b/site/src/components/SyntaxHighlighter/SyntaxHighlighter.tsx index 050939f088..451f754b95 100644 --- a/site/src/components/SyntaxHighlighter/SyntaxHighlighter.tsx +++ b/site/src/components/SyntaxHighlighter/SyntaxHighlighter.tsx @@ -1,16 +1,30 @@ import { useTheme } from "@emotion/react"; import Editor, { DiffEditor, loader } from "@monaco-editor/react"; +import type * as Monaco from "monaco-editor"; import * as monaco from "monaco-editor"; -import type { ComponentProps, FC } from "react"; +import { type ComponentProps, type FC, useCallback } from "react"; import { useCoderTheme } from "./coderTheme"; loader.config({ monaco }); +// Shared editor props with onMount typed to accept either editor variant, +// so callers don't need to know which underlying component will render. +type CommonEditorProps = Omit< + ComponentProps & ComponentProps, + "onMount" +> & { + onMount?: ( + editor: + | Monaco.editor.IStandaloneCodeEditor + | Monaco.editor.IStandaloneDiffEditor, + monaco: typeof Monaco, + ) => void; +}; + interface SyntaxHighlighterProps { value: string; language?: string; - editorProps?: ComponentProps & - ComponentProps; + editorProps?: CommonEditorProps; compareWith?: string; } @@ -23,6 +37,41 @@ export const SyntaxHighlighter: FC = ({ const hasDiff = compareWith && value !== compareWith; const theme = useTheme(); const coderTheme = useCoderTheme(); + + // Auto-scroll to first diff when the diff editor mounts and diffs are computed. + const handleDiffEditorMount = useCallback( + ( + editor: Monaco.editor.IStandaloneDiffEditor, + monacoInstance: typeof Monaco, + ) => { + // Call any existing onMount handler from editorProps. + editorProps?.onMount?.(editor, monacoInstance); + + // Diffs may already be computed by the time onMount fires, + // so check immediately first. If not ready yet, fall back + // to waiting for the onDidUpdateDiff event. + const scrollToFirstDiff = () => { + editor.goToDiff("next"); + }; + + const changes = editor.getLineChanges(); + if (changes && changes.length > 0) { + scrollToFirstDiff(); + return; + } + + const disposable = editor.onDidUpdateDiff(() => { + const updatedChanges = editor.getLineChanges(); + if (!updatedChanges || updatedChanges.length === 0) { + return; + } + disposable.dispose(); + scrollToFirstDiff(); + }); + }, + [editorProps], + ); + const commonProps = { language, theme: coderTheme.name, @@ -50,7 +99,12 @@ export const SyntaxHighlighter: FC = ({ }} > {hasDiff ? ( - + ) : ( )}