Skip to content

Commit

Permalink
Scroll to source line on diff click (#1347)
Browse files Browse the repository at this point in the history
* Scroll to source line on diff click

* use chippy's better code

* Add same for objdiff diff (untested)

* move context a little lower

* de-dupe code
  • Loading branch information
mkst authored Sep 23, 2024
1 parent 9c56aa0 commit fbc5278
Show file tree
Hide file tree
Showing 5 changed files with 42 additions and 12 deletions.
18 changes: 17 additions & 1 deletion frontend/src/components/Diff/Diff.tsx
Original file line number Diff line number Diff line change
@@ -1,8 +1,9 @@
/* eslint css-modules/no-unused-class: off */

import { createContext, CSSProperties, forwardRef, HTMLAttributes, useRef, useState } from "react"
import { createContext, CSSProperties, forwardRef, HTMLAttributes, MutableRefObject, useRef, useState } from "react"

import { VersionsIcon } from "@primer/octicons-react"
import { EditorView } from "codemirror"
import { DiffResult } from "objdiff-wasm"
import AutoSizer from "react-virtualized-auto-sizer"
import { FixedSizeList } from "react-window"
Expand Down Expand Up @@ -94,6 +95,21 @@ function ThreeWayToggleButton({ enabled, setEnabled }: { enabled: boolean, setEn
</button>
}

export function scrollToLineNumber(editorView: MutableRefObject<EditorView>, lineNumber: number) {
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" })
}
}
}

export const PADDING_TOP = 8
export const PADDING_BOTTOM = 8

Expand Down
10 changes: 7 additions & 3 deletions frontend/src/components/Diff/DiffRowAsmDiffer.tsx
Original file line number Diff line number Diff line change
@@ -1,14 +1,17 @@
/* eslint css-modules/no-unused-class: off */

import { CSSProperties, memo, useContext } from "react"
import { CSSProperties, MutableRefObject, memo, useContext } from "react"

import classNames from "classnames"
import { EditorView } from "codemirror"
import memoize from "memoize-one"
import { areEqual } from "react-window"

import * as api from "@/lib/api"

import { PADDING_TOP, SelectedSourceLineContext } from "./Diff"
import { ScrollContext } from "../ScrollContext"

import { PADDING_TOP, SelectedSourceLineContext, scrollToLineNumber } from "./Diff"
import styles from "./Diff.module.scss"
import { Highlighter } from "./Highlighter"

Expand Down Expand Up @@ -61,6 +64,7 @@ function DiffCell({ cell, className, highlighter }: {
highlighter: Highlighter
}) {
const selectedSourceLine = useContext(SelectedSourceLineContext)
const sourceEditor = useContext<MutableRefObject<EditorView>>(ScrollContext)
const hasLineNo = typeof cell?.src_line != "undefined"

if (!cell)
Expand All @@ -71,7 +75,7 @@ function DiffCell({ cell, className, highlighter }: {
[styles.highlight]: hasLineNo && cell.src_line == selectedSourceLine,
})}
>
{hasLineNo && <span className={styles.lineNumber}>{cell.src_line}</span>}
{hasLineNo && <span className={styles.lineNumber}><button onClick={() => scrollToLineNumber(sourceEditor, cell.src_line)}>{cell.src_line}</button></span>}
<FormatDiffText texts={cell.text} highlighter={highlighter} />
</div>
}
Expand Down
10 changes: 7 additions & 3 deletions frontend/src/components/Diff/DiffRowObjdiff.tsx
Original file line number Diff line number Diff line change
@@ -1,13 +1,16 @@
/* eslint css-modules/no-unused-class: off */

import { CSSProperties, memo, useContext } from "react"
import { CSSProperties, MutableRefObject, memo, useContext } from "react"

import classNames from "classnames"
import { EditorView } from "codemirror"
import memoize from "memoize-one"
import { DiffKind, DiffResult, FunctionDiff, InstructionDiff, ObjectDiff, displayDiff, oneof } from "objdiff-wasm"
import { areEqual } from "react-window"

import { PADDING_TOP, SelectedSourceLineContext } from "./Diff"
import { ScrollContext } from "../ScrollContext"

import { PADDING_TOP, SelectedSourceLineContext, scrollToLineNumber } from "./Diff"
import styles from "./Diff.module.scss"
import { Highlighter } from "./Highlighter"

Expand Down Expand Up @@ -123,6 +126,7 @@ function DiffCell({ cell, baseAddress, className, highlighter }: {
highlighter?: Highlighter
}) {
const selectedSourceLine = useContext(SelectedSourceLineContext)
const sourceEditor = useContext<MutableRefObject<EditorView>>(ScrollContext)
const hasLineNo = typeof cell?.instruction?.line_number != "undefined"

if (!cell)
Expand All @@ -149,7 +153,7 @@ function DiffCell({ cell, baseAddress, className, highlighter }: {
[styles.highlight]: hasLineNo && cell.instruction.line_number == selectedSourceLine,
})}
>
{hasLineNo && <span className={styles.lineNumber}>{cell.instruction.line_number}</span>}
{hasLineNo && <span className={styles.lineNumber}><button onClick={() => scrollToLineNumber(sourceEditor, cell.instruction.line_number)}>{cell.instruction.line_number}</button></span>}
<FormatDiffText insDiff={cell} baseAddress={baseAddress} highlighter={highlighter} />
</div>
}
Expand Down
13 changes: 8 additions & 5 deletions frontend/src/components/Scratch/Scratch.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ import CompilationPanel from "../Diff/CompilationPanel"
import CodeMirror from "../Editor/CodeMirror"
import ErrorBoundary from "../ErrorBoundary"
import ScoreBadge, { calculateScorePercent } from "../ScoreBadge"
import { ScrollContext } from "../ScrollContext"
import { Tab, TabCloseButton } from "../Tabs"

import useLanguageServer from "./hooks/useLanguageServer"
Expand Down Expand Up @@ -338,11 +339,13 @@ export default function Scratch({
{matchProgressBarEnabledSetting && <div className={styles.progressbar}><ScratchProgressBar matchPercent={matchPercent} /></div>}
</ErrorBoundary>
<ErrorBoundary>
{layout && <CustomLayout
layout={layout}
onChange={setLayout}
renderTab={renderTab}
/>}
{layout && <ScrollContext.Provider value={sourceEditor}>
<CustomLayout
layout={layout}
onChange={setLayout}
renderTab={renderTab}
/>
</ScrollContext.Provider>}
</ErrorBoundary>
{offlineOverlay}
</div>
Expand Down
3 changes: 3 additions & 0 deletions frontend/src/components/ScrollContext.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
import { createContext } from "react"

export const ScrollContext = createContext(null)

0 comments on commit fbc5278

Please sign in to comment.