From debf8dfedd6e54b633aa602f7d30c84b616ca927 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?David=20B=C3=BChler?= <david.buhler@cea.fr>
Date: Fri, 17 Sep 2021 10:39:07 +0200
Subject: [PATCH] [ivette] Changes the reset of the selected locations.

- The signal Ast.changed is emitted by Frama-C on any change of the AST.
  The AST view is always reloaded when this signal is emitted.
- Ivette resets the selected locations according to user actions.
---
 .../frama-c/api/generated/kernel/ast/index.ts  |  6 +++---
 ivette/src/frama-c/kernel/ASTview.tsx          |  2 +-
 ivette/src/frama-c/menu.ts                     | 10 +++++++---
 ivette/src/frama-c/states.ts                   | 18 ++++++++++--------
 src/plugins/server/kernel_ast.ml               |  8 ++++----
 5 files changed, 25 insertions(+), 19 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 f5b3bee763a..fa299dac4c2 100644
--- a/ivette/src/frama-c/api/generated/kernel/ast/index.ts
+++ b/ivette/src/frama-c/api/generated/kernel/ast/index.ts
@@ -71,9 +71,9 @@ 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',
+/** Emitted when the AST has been changed */
+export const changed: Server.Signal = {
+  name: 'kernel.ast.changed',
 };
 
 /** Marker kind */
diff --git a/ivette/src/frama-c/kernel/ASTview.tsx b/ivette/src/frama-c/kernel/ASTview.tsx
index d127bba677e..76879dcfca9 100644
--- a/ivette/src/frama-c/kernel/ASTview.tsx
+++ b/ivette/src/frama-c/kernel/ASTview.tsx
@@ -213,7 +213,7 @@ export default function ASTview() {
   });
 
   // Also reload the buffer when the AST is recomputed.
-  Server.onSignal(Ast.computed, reload);
+  Server.onSignal(Ast.changed, reload);
 
   React.useEffect(() => {
     const decorator = (marker: string) => {
diff --git a/ivette/src/frama-c/menu.ts b/ivette/src/frama-c/menu.ts
index 66fc3b9a8b5..bb9a411c8b8 100644
--- a/ivette/src/frama-c/menu.ts
+++ b/ivette/src/frama-c/menu.ts
@@ -28,6 +28,7 @@ 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',
@@ -43,8 +44,11 @@ async function setFiles(): Promise<void> {
     title: 'Select C source files',
     filters: [cFilter, allFilter],
   });
-  await Server.send(Ast.setFiles, files);
-  await Server.send(Ast.compute, { });
+  if (files) {
+    await Server.send(Ast.setFiles, files);
+    await Server.send(Ast.compute, { });
+    States.resetSelection();
+  }
   return;
 }
 
@@ -52,7 +56,7 @@ export function init() {
   Dome.addMenuItem({
     menu: 'File',
     label: 'Set source files',
-    id: 'file_add',
+    id: 'file_set',
     onClick: setFiles,
     type: 'normal',
   });
diff --git a/ivette/src/frama-c/states.ts b/ivette/src/frama-c/states.ts
index 39786ef5aad..7900638fce9 100644
--- a/ivette/src/frama-c/states.ts
+++ b/ivette/src/frama-c/states.ts
@@ -772,21 +772,23 @@ 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() {
+/** Resets the selected locations. */
+export async function resetSelection() {
+  GlobalSelection.setValue(emptySelection);
   const main = await Server.send(Ast.getMainFunction, { });
   const selection = {
     ...emptySelection,
     current: { fct: main },
   };
-  GlobalSelection.setValue(selection);
+  // If the selection has already been modified, do not change it.
+  if (GlobalSelection.getValue() === emptySelection)
+    GlobalSelection.setValue(selection);
 }
-Server.onSignal(Ast.computed, selectMainFunction);
+/* Select the main function when the current project changes and the selection
+   is still empty (which happens at the start of the GUI). */
 PROJECT.on(async () => {
-  const selection = GlobalSelection.getValue();
-  if (selection === emptySelection)
-    selectMainFunction();
+  if (GlobalSelection.getValue() === emptySelection)
+    resetSelection();
 });
 
 // --------------------------------------------------------------------------
diff --git a/src/plugins/server/kernel_ast.ml b/src/plugins/server/kernel_ast.ml
index 6a83fdf6c71..57794fc7dfb 100644
--- a/src/plugins/server/kernel_ast.ml
+++ b/src/plugins/server/kernel_ast.ml
@@ -37,15 +37,15 @@ 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 changed_signal = Request.signal ~package ~name:"changed"
+    ~descr:(Md.plain "Emitted when the AST has been changed")
 
 let ast_update_hook f =
   Ast.add_hook_on_update f;
   Ast.apply_after_computed (fun _ -> f ())
 
+let () = ast_update_hook (fun _ -> Request.emit changed_signal)
+
 (* -------------------------------------------------------------------------- *)
 (* ---  Printers                                                          --- *)
 (* -------------------------------------------------------------------------- *)
-- 
GitLab