From 6f8c8671e3023eae3d7d54145341fc738ca6de0f Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?David=20B=C3=BChler?= <david.buhler@cea.fr>
Date: Thu, 16 Sep 2021 16:19:33 +0200
Subject: [PATCH] [ivette] Automatically selects the 'main' function.

- when the AST is recomputed;
- when the current project changes and the selection is empty.
---
 .../frama-c/api/generated/kernel/ast/index.ts   |  5 +++++
 ivette/src/frama-c/kernel/ASTview.tsx           | 14 ++++++++++----
 ivette/src/frama-c/menu.ts                      |  3 ---
 ivette/src/frama-c/states.ts                    | 17 +++++++++++++++++
 src/plugins/server/kernel_ast.ml                |  5 +++++
 5 files changed, 37 insertions(+), 7 deletions(-)

diff --git a/ivette/src/frama-c/api/generated/kernel/ast/index.ts b/ivette/src/frama-c/api/generated/kernel/ast/index.ts
index f72426c5a32..f5b3bee763a 100644
--- a/ivette/src/frama-c/api/generated/kernel/ast/index.ts
+++ b/ivette/src/frama-c/api/generated/kernel/ast/index.ts
@@ -71,6 +71,11 @@ const compute_internal: Server.ExecRequest<null,null> = {
 /** Ensures that AST is computed */
 export const compute: Server.ExecRequest<null,null>= compute_internal;
 
+/** Emitted when the AST has been computed */
+export const computed: Server.Signal = {
+  name: 'kernel.ast.computed',
+};
+
 /** Marker kind */
 export enum markerKind {
   /** Expression */
diff --git a/ivette/src/frama-c/kernel/ASTview.tsx b/ivette/src/frama-c/kernel/ASTview.tsx
index 2f2d9bbae19..d127bba677e 100644
--- a/ivette/src/frama-c/kernel/ASTview.tsx
+++ b/ivette/src/frama-c/kernel/ASTview.tsx
@@ -201,14 +201,20 @@ export default function ASTview() {
     return () => { buffer.off('change', setBullets); };
   }, [buffer, setBullets]);
 
+  async function reload() {
+    printed.current = theFunction;
+    loadAST(buffer, theFunction, theMarker);
+  }
+
   // Hook: async loading
   React.useEffect(() => {
-    if (printed.current !== theFunction) {
-      printed.current = theFunction;
-      loadAST(buffer, theFunction, theMarker);
-    }
+    if (printed.current !== theFunction)
+      reload();
   });
 
+  // Also reload the buffer when the AST is recomputed.
+  Server.onSignal(Ast.computed, reload);
+
   React.useEffect(() => {
     const decorator = (marker: string) => {
       if (multipleSelections?.some((location) => location?.marker === marker))
diff --git a/ivette/src/frama-c/menu.ts b/ivette/src/frama-c/menu.ts
index 0fa35529440..66fc3b9a8b5 100644
--- a/ivette/src/frama-c/menu.ts
+++ b/ivette/src/frama-c/menu.ts
@@ -28,7 +28,6 @@ import * as Dome from 'dome';
 import * as Dialogs from 'dome/dialogs';
 import * as Server from 'frama-c/server';
 import * as Ast from 'frama-c/api/kernel/ast';
-import * as States from 'frama-c/states';
 
 const cFilter = {
   name: 'C source files',
@@ -46,8 +45,6 @@ async function setFiles(): Promise<void> {
   });
   await Server.send(Ast.setFiles, files);
   await Server.send(Ast.compute, { });
-  const main = await Server.send(Ast.getMainFunction, { });
-  States.setSelection({ fct: main });
   return;
 }
 
diff --git a/ivette/src/frama-c/states.ts b/ivette/src/frama-c/states.ts
index 876761db7b4..39786ef5aad 100644
--- a/ivette/src/frama-c/states.ts
+++ b/ivette/src/frama-c/states.ts
@@ -772,4 +772,21 @@ export function useSelection(): [Selection, (a: SelectionActions) => void] {
   return [current, (action) => setCurrent(reducer(current, action))];
 }
 
+/* Select the main function when the AST is recomputed, or when the current
+   project changes and the selection is still empty. */
+async function selectMainFunction() {
+  const main = await Server.send(Ast.getMainFunction, { });
+  const selection = {
+    ...emptySelection,
+    current: { fct: main },
+  };
+  GlobalSelection.setValue(selection);
+}
+Server.onSignal(Ast.computed, selectMainFunction);
+PROJECT.on(async () => {
+  const selection = GlobalSelection.getValue();
+  if (selection === emptySelection)
+    selectMainFunction();
+});
+
 // --------------------------------------------------------------------------
diff --git a/src/plugins/server/kernel_ast.ml b/src/plugins/server/kernel_ast.ml
index 10c62c2128a..6a83fdf6c71 100644
--- a/src/plugins/server/kernel_ast.ml
+++ b/src/plugins/server/kernel_ast.ml
@@ -37,6 +37,11 @@ let () = Request.register ~package
     ~descr:(Md.plain "Ensures that AST is computed")
     ~input:(module Junit) ~output:(module Junit) Ast.compute
 
+let computed_signal = Request.signal ~package ~name:"computed"
+    ~descr:(Md.plain "Emitted when the AST has been computed")
+
+let () = Ast.apply_after_computed (fun _ -> Request.emit computed_signal)
+
 let ast_update_hook f =
   Ast.add_hook_on_update f;
   Ast.apply_after_computed (fun _ -> f ())
-- 
GitLab