diff --git a/frontend/src/components/Diff/Diff.tsx b/frontend/src/components/Diff/Diff.tsx index d13f62203..b2c54bbcb 100644 --- a/frontend/src/components/Diff/Diff.tsx +++ b/frontend/src/components/Diff/Diff.tsx @@ -3,9 +3,11 @@ import { createContext, type CSSProperties, + type Dispatch, forwardRef, type HTMLAttributes, type RefObject, + type SetStateAction, useRef, useState, } from "react"; @@ -25,6 +27,8 @@ import styles from "./Diff.module.scss"; import * as AsmDiffer from "./DiffRowAsmDiffer"; import DragBar from "./DragBar"; import { useHighlighers } from "./Highlighter"; +import { activateTabInLayout, type Layout } from "../CustomLayout"; +import { TabId } from "../Scratch/Scratch"; const copyDiffContentsToClipboard = (diff: api.DiffOutput, kind: string) => { // kind is either "base", "current", or "previous" @@ -154,21 +158,48 @@ function ThreeWayToggleButton({ } export function scrollToLineNumber( - editorView: RefObject, + sourceEditorView: RefObject, + contextEditorView: RefObject, + setLayout: Dispatch>, + isInContext: boolean, lineNumber: number, ) { + const editorView = isInContext ? contextEditorView : sourceEditorView; if (!editorView) { return; } - if (lineNumber <= editorView.current.state.doc.lines) { - // check if the source line <= number of lines - // which can be false if pragmas are used to force line numbers - const line = editorView.current.state.doc.line(lineNumber); - if (line) { - const { top } = editorView.current.lineBlockAt(line.to); - editorView.current.scrollDOM.scrollTo({ top, behavior: "smooth" }); - } + // check if the source line <= number of lines + // which can be false if pragmas are used to force line numbers + if (lineNumber > editorView.current.state.doc.lines) { + return; } + const line = editorView.current.state.doc.line(lineNumber); + if (!line) { + return; + } + setLayout((layout) => { + const clone = { ...layout }; + activateTabInLayout( + clone, + isInContext ? TabId.CONTEXT : TabId.SOURCE_CODE, + ); + + const scrollToLine = () => { + if (editorView.current.inView) { + const { top } = editorView.current.lineBlockAt(line.to); + editorView.current.scrollDOM.scrollTo({ + top, + behavior: "smooth", + }); + } else { + requestAnimationFrame(scrollToLine); + } + }; + + requestAnimationFrame(scrollToLine); + + return clone; + }); } export const PADDING_TOP = 8; diff --git a/frontend/src/components/Diff/DiffRowAsmDiffer.tsx b/frontend/src/components/Diff/DiffRowAsmDiffer.tsx index 5bbbba315..a11788230 100644 --- a/frontend/src/components/Diff/DiffRowAsmDiffer.tsx +++ b/frontend/src/components/Diff/DiffRowAsmDiffer.tsx @@ -1,6 +1,13 @@ /* eslint css-modules/no-unused-class: off */ -import { type CSSProperties, type RefObject, memo, useContext } from "react"; +import { + type CSSProperties, + type Dispatch, + type RefObject, + type SetStateAction, + memo, + useContext, +} from "react"; import clsx from "clsx"; import type { EditorView } from "codemirror"; @@ -19,6 +26,7 @@ import { } from "./Diff"; import styles from "./Diff.module.scss"; import type { Highlighter } from "./Highlighter"; +import type { Layout } from "../CustomLayout"; // Regex for tokenizing lines for click-to-highlight purposes. // Strings matched by the first regex group (spaces, punctuation) @@ -82,8 +90,13 @@ function DiffCell({ highlighter: Highlighter; }) { const selectedSourceLine = useContext(SelectedSourceLineContext); - const sourceEditor = useContext>(ScrollContext); + const { sourceEditor, contextEditor, setLayout } = useContext<{ + sourceEditor: RefObject; + contextEditor: RefObject; + setLayout: Dispatch>; + }>(ScrollContext); const hasLineNo = typeof cell?.src_line !== "undefined"; + const isInContext = cell?.src?.some((s) => s?.includes("ctx")); if (!cell) return
; @@ -112,7 +125,13 @@ function DiffCell({