From 520ea326d2d3e263cf3a884cc0c8093b6f9cbc0f Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?David=20B=C3=BChler?= <david.buhler@cea.fr>
Date: Sat, 25 Mar 2023 11:22:01 +0100
Subject: [PATCH] [Ivette] Improves editor scrolling in SourceCode and ASTview.

Scroll to center selected element, but only if it is not already visible.
---
 ivette/src/dome/renderer/text/editor.tsx | 19 ++++++++++++++++---
 ivette/src/frama-c/kernel/ASTview.tsx    |  3 ++-
 2 files changed, 18 insertions(+), 4 deletions(-)

diff --git a/ivette/src/dome/renderer/text/editor.tsx b/ivette/src/dome/renderer/text/editor.tsx
index 7ca40b680eb..c22c6f6835c 100644
--- a/ivette/src/dome/renderer/text/editor.tsx
+++ b/ivette/src/dome/renderer/text/editor.tsx
@@ -432,6 +432,18 @@ export function unfoldAll(view: View): void {
   if (view !== null) Language.unfoldAll(view);
 }
 
+function isVisible(view: View, line: number): boolean {
+  if (!view || view.state.doc.lines < line) return false;
+  const doc = view.state.doc;
+  const top = view.documentTop;
+  const rect = view.dom.getBoundingClientRect();
+  const topVisibleBlock = view.lineBlockAtHeight(rect.top - top);
+  const topVisibleLine = doc.lineAt(topVisibleBlock.to).number;
+  const bottomVisibleBlock = view.lineBlockAtHeight(rect.bottom - top);
+  const bottomVisibleLine = doc.lineAt(bottomVisibleBlock.from).number;
+  return (topVisibleLine < line && line < bottomVisibleLine);
+}
+
 // Move to the given line. The indexation starts at 1.
 export function selectLine(view: View, line: number, atTop: boolean): void {
   if (!view || view.state.doc.lines < line) return;
@@ -439,9 +451,10 @@ export function selectLine(view: View, line: number, atTop: boolean): void {
   const { from: here } = doc.lineAt(view.state.selection.main.from);
   const { from: goto } = doc.line(Math.max(line, 1));
   if (here === goto) return;
-  view.dispatch({ selection: { anchor: goto }, scrollIntoView: true });
-  if (!atTop) return;
-  const effects = EditorView.scrollIntoView(goto, { y: 'start', yMargin: 0 });
+  view.dispatch({ selection: { anchor: goto } });
+  if (isVisible(view, line)) return;
+  const verticalScroll = atTop ? 'start' : 'center';
+  const effects = EditorView.scrollIntoView(goto, { y: verticalScroll });
   view.dispatch({ effects });
 }
 
diff --git a/ivette/src/frama-c/kernel/ASTview.tsx b/ivette/src/frama-c/kernel/ASTview.tsx
index 112823a87b6..94b20dc6b61 100644
--- a/ivette/src/frama-c/kernel/ASTview.tsx
+++ b/ivette/src/frama-c/kernel/ASTview.tsx
@@ -217,7 +217,8 @@ function createMarkerScroller(): Editor.Extension {
     const markerRanges = ranges.get(marker) ?? [];
     if (markerRanges.length !== 1) return;
     const { from: anchor } = markerRanges[0];
-    view.dispatch({ selection: { anchor }, scrollIntoView: true });
+    const line = view.state.doc.lineAt(anchor).number;
+    Editor.selectLine(view, line, false);
   });
 }
 
-- 
GitLab