From 2b7252e4548be504e243dc58c7ed78d5c916c7f0 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Loi=CC=88c=20Correnson?= <loic.correnson@cea.fr>
Date: Wed, 23 Feb 2022 14:24:59 +0100
Subject: [PATCH] [ivette] hooks on hovered selection

---
 ivette/src/dome/renderer/text/editors.tsx |  5 +++++
 ivette/src/frama-c/kernel/ASTview.tsx     | 15 ++++++++++++++-
 ivette/src/frama-c/states.ts              |  9 ++++++++-
 3 files changed, 27 insertions(+), 2 deletions(-)

diff --git a/ivette/src/dome/renderer/text/editors.tsx b/ivette/src/dome/renderer/text/editors.tsx
index 43df5396e92..464a5e9922d 100644
--- a/ivette/src/dome/renderer/text/editors.tsx
+++ b/ivette/src/dome/renderer/text/editors.tsx
@@ -72,6 +72,9 @@ export interface TextProps extends CodeMirror.EditorConfiguration {
   /** The currently selected marker identifier. */
   selection?: string;
 
+  /** Callback on hovered marker, if some. */
+  onHover?: (id?: string) => void;
+
   /** Callback on identified marker selection. */
   onSelection?: MarkerCallback;
 
@@ -311,6 +314,8 @@ class CodeMirrorWrapper extends React.Component<TextProps> {
       if (newMarker && newMarker.hover)
         this._markElementsWith(newMarker.classNameId, CSS_HOVERED);
       this.marker = newMarker;
+      const callback = this.props.onHover;
+      if (callback) callback(newMarker?.id);
     }
   }
 
diff --git a/ivette/src/frama-c/kernel/ASTview.tsx b/ivette/src/frama-c/kernel/ASTview.tsx
index e98cb526378..d54fb085d2f 100644
--- a/ivette/src/frama-c/kernel/ASTview.tsx
+++ b/ivette/src/frama-c/kernel/ASTview.tsx
@@ -161,9 +161,12 @@ export default function ASTview() {
   const buffer = React.useMemo(() => new RichTextBuffer(), []);
   const printed = React.useRef<string | undefined>();
   const [selection, updateSelection] = States.useSelection();
+  const [hoveredLoc] = States.useHovered();
+  const selfhover = React.useRef(false);
   const multipleSelections = selection?.multiple.allSelections;
   const theFunction = selection?.current?.fct;
   const theMarker = selection?.current?.marker;
+  const hovered = hoveredLoc?.marker;
   const [fontSize] = Settings.useGlobalSettings(Preferences.EditorFontSize);
 
   const markersInfo = States.useSyncArray(Ast.markerInfo);
@@ -220,16 +223,25 @@ export default function ASTview() {
         return 'dead-code';
       if (deadCode?.nonTerminating?.some((m) => m === marker))
         return 'non-terminating';
+      if (!selfhover.current && marker === hovered)
+        return 'hovered-marker';
       return undefined;
     };
     buffer.setDecorator(decorator);
-  }, [buffer, multipleSelections, deadCode]);
+  }, [buffer, multipleSelections, selfhover, hovered, deadCode]);
 
   // Hook: marker scrolling
   React.useEffect(() => {
     if (theMarker) buffer.scroll(theMarker);
   }, [buffer, theMarker]);
 
+  function onHover(markerId?: string) {
+    const marker = Ast.jMarker(markerId);
+    const fct = selection?.current?.fct;
+    selfhover.current = (marker !== undefined);
+    States.setHovered(marker ? { fct, marker } : undefined);
+  }
+
   function onSelection(markerId: string, meta = false) {
     const fct = selection?.current?.fct;
     const location = { fct, marker: Ast.jMarker(markerId) };
@@ -303,6 +315,7 @@ export default function ASTview() {
         mode="text/x-csrc"
         fontSize={fontSize}
         selection={theMarker}
+        onHover={onHover}
         onSelection={onSelection}
         onContextMenu={onContextMenu}
         gutters={['bullet']}
diff --git a/ivette/src/frama-c/states.ts b/ivette/src/frama-c/states.ts
index ff7b0310ffc..11b59f05e8a 100644
--- a/ivette/src/frama-c/states.ts
+++ b/ivette/src/frama-c/states.ts
@@ -188,7 +188,7 @@ export function useRequest<In, Out>(
     }
   });
 
-  const signals = options.onSignals ?? rq.signals;
+  const signals = rq.signals.concat(options.onSignals ?? []);
   React.useEffect(() => {
     signals.forEach((s) => Server.onSignal(s, trigger));
     return () => {
@@ -767,11 +767,18 @@ const emptySelection = {
   },
 };
 
+export type Hovered = Location | undefined;
 export const MetaSelection = new Dome.Event<Location>('frama-c-meta-selection');
+export const GlobalHovered = new GlobalState<Hovered>(undefined);
 export const GlobalSelection = new GlobalState<Selection>(emptySelection);
 
 Server.onShutdown(() => GlobalSelection.setValue(emptySelection));
 
+export function setHovered(h: Hovered) { GlobalHovered.setValue(h); }
+export function useHovered(): [Hovered, (h: Hovered) => void] {
+  return useGlobalState(GlobalHovered);
+}
+
 export function setSelection(location: Location, meta = false) {
   const s = GlobalSelection.getValue();
   GlobalSelection.setValue(reducer(s, { location }));
-- 
GitLab