From 5ec2fbfd98df40e7223cf78feabec488b844beda Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Fran=C3=A7ois=20Bobot?= <francois.bobot@cea.fr>
Date: Thu, 16 Sep 2021 11:57:56 +0200
Subject: [PATCH] [Ivette] Add default signals for request

---
 ivette/src/frama-c/api/generated/kernel/ast/index.ts | 12 ++++++++++++
 .../frama-c/api/generated/kernel/project/index.ts    |  7 +++++++
 .../frama-c/api/generated/kernel/properties/index.ts |  5 +++++
 .../frama-c/api/generated/kernel/services/index.ts   |  5 +++++
 .../src/frama-c/api/generated/plugins/dive/index.ts  |  7 +++++++
 .../api/generated/plugins/eva/general/index.ts       |  6 ++++++
 .../api/generated/plugins/eva/values/index.ts        |  5 +++++
 .../api/generated/plugins/studia/studia/index.ts     |  2 ++
 ivette/src/frama-c/api/generator.ml                  |  4 ++++
 ivette/src/frama-c/server.ts                         | 12 +++++++-----
 ivette/src/frama-c/states.ts                         |  9 ++++++---
 src/plugins/server/main.ml                           |  1 +
 src/plugins/server/main.mli                          |  1 +
 src/plugins/server/package.ml                        |  1 +
 src/plugins/server/package.mli                       |  1 +
 src/plugins/server/request.ml                        |  7 ++++---
 src/plugins/server/request.mli                       |  5 ++++-
 src/plugins/server/server_doc.ml                     |  5 ++++-
 18 files changed, 82 insertions(+), 13 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 03afaed2e4d..e4ae876f7fe 100644
--- a/ivette/src/frama-c/api/generated/kernel/ast/index.ts
+++ b/ivette/src/frama-c/api/generated/kernel/ast/index.ts
@@ -67,6 +67,7 @@ const compute_internal: Server.ExecRequest<null,null> = {
   name:   'kernel.ast.compute',
   input:  Json.jNull,
   output: Json.jNull,
+  signals: [],
 };
 /** Ensures that AST is computed */
 export const compute: Server.ExecRequest<null,null>= compute_internal;
@@ -105,6 +106,7 @@ const markerKindTags_internal: Server.GetRequest<null,tag[]> = {
   name:   'kernel.ast.markerKindTags',
   input:  Json.jNull,
   output: Json.jList(jTag),
+  signals: [],
 };
 /** Registered tags for the above type. */
 export const markerKindTags: Server.GetRequest<null,tag[]>= markerKindTags_internal;
@@ -135,6 +137,7 @@ const markerVarTags_internal: Server.GetRequest<null,tag[]> = {
   name:   'kernel.ast.markerVarTags',
   input:  Json.jNull,
   output: Json.jList(jTag),
+  signals: [],
 };
 /** Registered tags for the above type. */
 export const markerVarTags: Server.GetRequest<null,tag[]>= markerVarTags_internal;
@@ -193,6 +196,7 @@ const reloadMarkerInfo_internal: Server.GetRequest<null,null> = {
   name:   'kernel.ast.reloadMarkerInfo',
   input:  Json.jNull,
   output: Json.jNull,
+  signals: [],
 };
 /** Force full reload for array [`markerInfo`](#markerinfo)  */
 export const reloadMarkerInfo: Server.GetRequest<null,null>= reloadMarkerInfo_internal;
@@ -211,6 +215,7 @@ const fetchMarkerInfo_internal: Server.GetRequest<
             removed: Json.jList(Json.jString),
             reload: Json.jFail(Json.jBoolean,'Boolean expected'),
           }),
+  signals: [],
 };
 /** Data fetcher for array [`markerInfo`](#markerinfo)  */
 export const fetchMarkerInfo: Server.GetRequest<
@@ -289,6 +294,7 @@ const getFunctions_internal: Server.GetRequest<null,Json.key<'#fct'>[]> = {
   name:   'kernel.ast.getFunctions',
   input:  Json.jNull,
   output: Json.jList(Json.jKey<'#fct'>('#fct')),
+  signals: [],
 };
 /** Collect all functions in the AST */
 export const getFunctions: Server.GetRequest<null,Json.key<'#fct'>[]>= getFunctions_internal;
@@ -298,6 +304,7 @@ const printFunction_internal: Server.GetRequest<Json.key<'#fct'>,text> = {
   name:   'kernel.ast.printFunction',
   input:  Json.jKey<'#fct'>('#fct'),
   output: jText,
+  signals: [],
 };
 /** Print the AST of a function */
 export const printFunction: Server.GetRequest<Json.key<'#fct'>,text>= printFunction_internal;
@@ -370,6 +377,7 @@ const reloadFunctions_internal: Server.GetRequest<null,null> = {
   name:   'kernel.ast.reloadFunctions',
   input:  Json.jNull,
   output: Json.jNull,
+  signals: [],
 };
 /** Force full reload for array [`functions`](#functions)  */
 export const reloadFunctions: Server.GetRequest<null,null>= reloadFunctions_internal;
@@ -388,6 +396,7 @@ const fetchFunctions_internal: Server.GetRequest<
             removed: Json.jList(Json.jKey<'#functions'>('#functions')),
             reload: Json.jFail(Json.jBoolean,'Boolean expected'),
           }),
+  signals: [],
 };
 /** Data fetcher for array [`functions`](#functions)  */
 export const fetchFunctions: Server.GetRequest<
@@ -412,6 +421,7 @@ const getInfo_internal: Server.GetRequest<marker,text> = {
   name:   'kernel.ast.getInfo',
   input:  jMarker,
   output: jText,
+  signals: [],
 };
 /** Get textual information about a marker */
 export const getInfo: Server.GetRequest<marker,text>= getInfo_internal;
@@ -421,6 +431,7 @@ const getFiles_internal: Server.GetRequest<null,string[]> = {
   name:   'kernel.ast.getFiles',
   input:  Json.jNull,
   output: Json.jList(Json.jString),
+  signals: [],
 };
 /** Get the currently analyzed source file names */
 export const getFiles: Server.GetRequest<null,string[]>= getFiles_internal;
@@ -430,6 +441,7 @@ const setFiles_internal: Server.SetRequest<string[],null> = {
   name:   'kernel.ast.setFiles',
   input:  Json.jList(Json.jString),
   output: Json.jNull,
+  signals: [],
 };
 /** Set the source file names to analyze. */
 export const setFiles: Server.SetRequest<string[],null>= setFiles_internal;
diff --git a/ivette/src/frama-c/api/generated/kernel/project/index.ts b/ivette/src/frama-c/api/generated/kernel/project/index.ts
index a618bbc59f5..a08cfb75ffe 100644
--- a/ivette/src/frama-c/api/generated/kernel/project/index.ts
+++ b/ivette/src/frama-c/api/generated/kernel/project/index.ts
@@ -94,6 +94,7 @@ const getCurrent_internal: Server.GetRequest<null,projectInfo> = {
   name:   'kernel.project.getCurrent',
   input:  Json.jNull,
   output: jProjectInfo,
+  signals: [],
 };
 /** Returns the current project */
 export const getCurrent: Server.GetRequest<null,projectInfo>= getCurrent_internal;
@@ -103,6 +104,7 @@ const setCurrent_internal: Server.SetRequest<Json.key<'#project'>,null> = {
   name:   'kernel.project.setCurrent',
   input:  Json.jKey<'#project'>('#project'),
   output: Json.jNull,
+  signals: [],
 };
 /** Switches the current project */
 export const setCurrent: Server.SetRequest<Json.key<'#project'>,null>= setCurrent_internal;
@@ -112,6 +114,7 @@ const getList_internal: Server.GetRequest<null,projectInfo[]> = {
   name:   'kernel.project.getList',
   input:  Json.jNull,
   output: Json.jList(jProjectInfo),
+  signals: [],
 };
 /** Returns the list of all projects */
 export const getList: Server.GetRequest<null,projectInfo[]>= getList_internal;
@@ -121,6 +124,7 @@ const getOn_internal: Server.GetRequest<projectRequest,Json.json> = {
   name:   'kernel.project.getOn',
   input:  jProjectRequest,
   output: Json.jAny,
+  signals: [],
 };
 /** Execute a GET request within the given project */
 export const getOn: Server.GetRequest<projectRequest,Json.json>= getOn_internal;
@@ -130,6 +134,7 @@ const setOn_internal: Server.SetRequest<projectRequest,Json.json> = {
   name:   'kernel.project.setOn',
   input:  jProjectRequest,
   output: Json.jAny,
+  signals: [],
 };
 /** Execute a SET request within the given project */
 export const setOn: Server.SetRequest<projectRequest,Json.json>= setOn_internal;
@@ -139,6 +144,7 @@ const execOn_internal: Server.ExecRequest<projectRequest,Json.json> = {
   name:   'kernel.project.execOn',
   input:  jProjectRequest,
   output: Json.jAny,
+  signals: [],
 };
 /** Execute an EXEC request within the given project */
 export const execOn: Server.ExecRequest<projectRequest,Json.json>= execOn_internal;
@@ -148,6 +154,7 @@ const create_internal: Server.SetRequest<string,projectInfo> = {
   name:   'kernel.project.create',
   input:  Json.jString,
   output: jProjectInfo,
+  signals: [],
 };
 /** Create a new project */
 export const create: Server.SetRequest<string,projectInfo>= create_internal;
diff --git a/ivette/src/frama-c/api/generated/kernel/properties/index.ts b/ivette/src/frama-c/api/generated/kernel/properties/index.ts
index 80e498300ff..6c5a7309f50 100644
--- a/ivette/src/frama-c/api/generated/kernel/properties/index.ts
+++ b/ivette/src/frama-c/api/generated/kernel/properties/index.ts
@@ -141,6 +141,7 @@ const propKindTags_internal: Server.GetRequest<null,tag[]> = {
   name:   'kernel.properties.propKindTags',
   input:  Json.jNull,
   output: Json.jList(jTag),
+  signals: [],
 };
 /** Registered tags for the above type. */
 export const propKindTags: Server.GetRequest<null,tag[]>= propKindTags_internal;
@@ -187,6 +188,7 @@ const propStatusTags_internal: Server.GetRequest<null,tag[]> = {
   name:   'kernel.properties.propStatusTags',
   input:  Json.jNull,
   output: Json.jList(jTag),
+  signals: [],
 };
 /** Registered tags for the above type. */
 export const propStatusTags: Server.GetRequest<null,tag[]>= propStatusTags_internal;
@@ -246,6 +248,7 @@ const alarmsTags_internal: Server.GetRequest<null,tag[]> = {
   name:   'kernel.properties.alarmsTags',
   input:  Json.jNull,
   output: Json.jList(jTag),
+  signals: [],
 };
 /** Registered tags for the above type. */
 export const alarmsTags: Server.GetRequest<null,tag[]>= alarmsTags_internal;
@@ -326,6 +329,7 @@ const reloadStatus_internal: Server.GetRequest<null,null> = {
   name:   'kernel.properties.reloadStatus',
   input:  Json.jNull,
   output: Json.jNull,
+  signals: [],
 };
 /** Force full reload for array [`status`](#status)  */
 export const reloadStatus: Server.GetRequest<null,null>= reloadStatus_internal;
@@ -344,6 +348,7 @@ const fetchStatus_internal: Server.GetRequest<
             removed: Json.jList(Json.jKey<'#property'>('#property')),
             reload: Json.jFail(Json.jBoolean,'Boolean expected'),
           }),
+  signals: [],
 };
 /** Data fetcher for array [`status`](#status)  */
 export const fetchStatus: Server.GetRequest<
diff --git a/ivette/src/frama-c/api/generated/kernel/services/index.ts b/ivette/src/frama-c/api/generated/kernel/services/index.ts
index 3419792ac5a..d0a676b9278 100644
--- a/ivette/src/frama-c/api/generated/kernel/services/index.ts
+++ b/ivette/src/frama-c/api/generated/kernel/services/index.ts
@@ -59,6 +59,7 @@ const getConfig_internal: Server.GetRequest<
             datadir: Json.jFail(Json.jString,'String expected'),
             version: Json.jFail(Json.jString,'String expected'),
           }),
+  signals: [],
 };
 /** Frama-C Kernel configuration */
 export const getConfig: Server.GetRequest<
@@ -71,6 +72,7 @@ const load_internal: Server.SetRequest<string,string | undefined> = {
   name:   'kernel.services.load',
   input:  Json.jString,
   output: Json.jString,
+  signals: [],
 };
 /** Load a save file. Returns an error, if not successfull. */
 export const load: Server.SetRequest<string,string | undefined>= load_internal;
@@ -133,6 +135,7 @@ const logkindTags_internal: Server.GetRequest<null,tag[]> = {
   name:   'kernel.services.logkindTags',
   input:  Json.jNull,
   output: Json.jList(jTag),
+  signals: [],
 };
 /** Registered tags for the above type. */
 export const logkindTags: Server.GetRequest<null,tag[]>= logkindTags_internal;
@@ -181,6 +184,7 @@ const setLogs_internal: Server.SetRequest<boolean,null> = {
   name:   'kernel.services.setLogs',
   input:  Json.jBoolean,
   output: Json.jNull,
+  signals: [],
 };
 /** Turn logs monitoring on/off */
 export const setLogs: Server.SetRequest<boolean,null>= setLogs_internal;
@@ -190,6 +194,7 @@ const getLogs_internal: Server.GetRequest<null,log[]> = {
   name:   'kernel.services.getLogs',
   input:  Json.jNull,
   output: Json.jList(jLog),
+  signals: [],
 };
 /** Flush the last emitted logs since last call (max 100) */
 export const getLogs: Server.GetRequest<null,log[]>= getLogs_internal;
diff --git a/ivette/src/frama-c/api/generated/plugins/dive/index.ts b/ivette/src/frama-c/api/generated/plugins/dive/index.ts
index ebdc7a4f4e5..f1210ae95a6 100644
--- a/ivette/src/frama-c/api/generated/plugins/dive/index.ts
+++ b/ivette/src/frama-c/api/generated/plugins/dive/index.ts
@@ -315,6 +315,7 @@ const window_internal: Server.SetRequest<explorationWindow,null> = {
   name:   'plugins.dive.window',
   input:  jExplorationWindow,
   output: Json.jNull,
+  signals: [],
 };
 /** Set the exploration window */
 export const window: Server.SetRequest<explorationWindow,null>= window_internal;
@@ -324,6 +325,7 @@ const graph_internal: Server.GetRequest<null,graphData> = {
   name:   'plugins.dive.graph',
   input:  Json.jNull,
   output: jGraphData,
+  signals: [],
 };
 /** Retrieve the whole graph */
 export const graph: Server.GetRequest<null,graphData>= graph_internal;
@@ -333,6 +335,7 @@ const clear_internal: Server.ExecRequest<null,null> = {
   name:   'plugins.dive.clear',
   input:  Json.jNull,
   output: Json.jNull,
+  signals: [],
 };
 /** Erase the graph and start over with an empty one */
 export const clear: Server.ExecRequest<null,null>= clear_internal;
@@ -342,6 +345,7 @@ const add_internal: Server.ExecRequest<marker,diffData> = {
   name:   'plugins.dive.add',
   input:  jMarker,
   output: jDiffData,
+  signals: [],
 };
 /** Add a node to the graph */
 export const add: Server.ExecRequest<marker,diffData>= add_internal;
@@ -351,6 +355,7 @@ const explore_internal: Server.ExecRequest<nodeId,diffData> = {
   name:   'plugins.dive.explore',
   input:  jNodeId,
   output: jDiffData,
+  signals: [],
 };
 /** Explore the graph starting from an existing vertex */
 export const explore: Server.ExecRequest<nodeId,diffData>= explore_internal;
@@ -360,6 +365,7 @@ const show_internal: Server.ExecRequest<nodeId,diffData> = {
   name:   'plugins.dive.show',
   input:  jNodeId,
   output: jDiffData,
+  signals: [],
 };
 /** Show the dependencies of an existing vertex */
 export const show: Server.ExecRequest<nodeId,diffData>= show_internal;
@@ -369,6 +375,7 @@ const hide_internal: Server.ExecRequest<nodeId,diffData> = {
   name:   'plugins.dive.hide',
   input:  jNodeId,
   output: jDiffData,
+  signals: [],
 };
 /** Hide the dependencies of an existing vertex */
 export const hide: Server.ExecRequest<nodeId,diffData>= hide_internal;
diff --git a/ivette/src/frama-c/api/generated/plugins/eva/general/index.ts b/ivette/src/frama-c/api/generated/plugins/eva/general/index.ts
index 1013a182974..96be458013e 100644
--- a/ivette/src/frama-c/api/generated/plugins/eva/general/index.ts
+++ b/ivette/src/frama-c/api/generated/plugins/eva/general/index.ts
@@ -59,6 +59,7 @@ const isComputed_internal: Server.GetRequest<null,boolean> = {
   name:   'plugins.eva.general.isComputed',
   input:  Json.jNull,
   output: Json.jBoolean,
+  signals: [],
 };
 /** True if the Eva analysis has been done */
 export const isComputed: Server.GetRequest<null,boolean>= isComputed_internal;
@@ -76,6 +77,7 @@ const getCallers_internal: Server.GetRequest<
                 Json.jFail(Json.jKey<'#fct'>('#fct'),'#fct expected'),
                 Json.jFail(Json.jKey<'#stmt'>('#stmt'),'#stmt expected'),
               ))),
+  signals: [],
 };
 /** Get the list of call site of a function */
 export const getCallers: Server.GetRequest<
@@ -115,6 +117,7 @@ const getDeadCode_internal: Server.GetRequest<Json.key<'#fct'>,deadCode> = {
   name:   'plugins.eva.general.getDeadCode',
   input:  Json.jKey<'#fct'>('#fct'),
   output: jDeadCode,
+  signals: [],
 };
 /** Get the lists of unreachable and of non terminating statements in a function */
 export const getDeadCode: Server.GetRequest<Json.key<'#fct'>,deadCode>= getDeadCode_internal;
@@ -156,6 +159,7 @@ const taintStatusTags_internal: Server.GetRequest<null,tag[]> = {
   name:   'plugins.eva.general.taintStatusTags',
   input:  Json.jNull,
   output: Json.jList(jTag),
+  signals: [],
 };
 /** Registered tags for the above type. */
 export const taintStatusTags: Server.GetRequest<null,tag[]>= taintStatusTags_internal;
@@ -201,6 +205,7 @@ const reloadProperties_internal: Server.GetRequest<null,null> = {
   name:   'plugins.eva.general.reloadProperties',
   input:  Json.jNull,
   output: Json.jNull,
+  signals: [],
 };
 /** Force full reload for array [`properties`](#properties)  */
 export const reloadProperties: Server.GetRequest<null,null>= reloadProperties_internal;
@@ -219,6 +224,7 @@ const fetchProperties_internal: Server.GetRequest<
             removed: Json.jList(Json.jKey<'#property'>('#property')),
             reload: Json.jFail(Json.jBoolean,'Boolean expected'),
           }),
+  signals: [],
 };
 /** Data fetcher for array [`properties`](#properties)  */
 export const fetchProperties: Server.GetRequest<
diff --git a/ivette/src/frama-c/api/generated/plugins/eva/values/index.ts b/ivette/src/frama-c/api/generated/plugins/eva/values/index.ts
index f82f704494f..b4c6915b73c 100644
--- a/ivette/src/frama-c/api/generated/plugins/eva/values/index.ts
+++ b/ivette/src/frama-c/api/generated/plugins/eva/values/index.ts
@@ -70,6 +70,7 @@ const getCallstacks_internal: Server.GetRequest<marker[],callstack[]> = {
   name:   'plugins.eva.values.getCallstacks',
   input:  Json.jList(jMarker),
   output: Json.jList(jCallstack),
+  signals: [],
 };
 /** Callstacks for markers */
 export const getCallstacks: Server.GetRequest<marker[],callstack[]>= getCallstacks_internal;
@@ -89,6 +90,7 @@ const getCallstackInfo_internal: Server.GetRequest<
               stmt: Json.jKey<'#stmt'>('#stmt'),
               rank: Json.jNumber,
             })),
+  signals: [],
 };
 /** Callstack Description */
 export const getCallstackInfo: Server.GetRequest<
@@ -108,6 +110,7 @@ const getStmtInfo_internal: Server.GetRequest<
             rank: Json.jFail(Json.jNumber,'Number expected'),
             fct: Json.jFail(Json.jKey<'#fct'>('#fct'),'#fct expected'),
           }),
+  signals: [],
 };
 /** Stmt Information */
 export const getStmtInfo: Server.GetRequest<
@@ -130,6 +133,7 @@ const getProbeInfo_internal: Server.GetRequest<
             stmt: Json.jKey<'#stmt'>('#stmt'),
             code: Json.jString,
           }),
+  signals: [],
 };
 /** Probe informations */
 export const getProbeInfo: Server.GetRequest<
@@ -163,6 +167,7 @@ const getValues_internal: Server.GetRequest<
                           Json.jFail(Json.jString,'String expected'),
                         ))),
           }),
+  signals: [],
 };
 /** Abstract values for the given marker */
 export const getValues: Server.GetRequest<
diff --git a/ivette/src/frama-c/api/generated/plugins/studia/studia/index.ts b/ivette/src/frama-c/api/generated/plugins/studia/studia/index.ts
index 66d28da4aa9..20ec58320d5 100644
--- a/ivette/src/frama-c/api/generated/plugins/studia/studia/index.ts
+++ b/ivette/src/frama-c/api/generated/plugins/studia/studia/index.ts
@@ -89,6 +89,7 @@ const getReadsLval_internal: Server.GetRequest<Json.key<'#lval'>,effects> = {
   name:   'plugins.studia.studia.getReadsLval',
   input:  Json.jKey<'#lval'>('#lval'),
   output: jEffects,
+  signals: [],
 };
 /** Get the list of statements that read a lval. */
 export const getReadsLval: Server.GetRequest<Json.key<'#lval'>,effects>= getReadsLval_internal;
@@ -98,6 +99,7 @@ const getWritesLval_internal: Server.GetRequest<Json.key<'#lval'>,effects> = {
   name:   'plugins.studia.studia.getWritesLval',
   input:  Json.jKey<'#lval'>('#lval'),
   output: jEffects,
+  signals: [],
 };
 /** Get the list of statements that write a lval. */
 export const getWritesLval: Server.GetRequest<Json.key<'#lval'>,effects>= getWritesLval_internal;
diff --git a/ivette/src/frama-c/api/generator.ml b/ivette/src/frama-c/api/generator.ml
index 61bb475671b..8a3ed1a9d39 100644
--- a/ivette/src/frama-c/api/generator.ml
+++ b/ivette/src/frama-c/api/generator.ml
@@ -335,6 +335,10 @@ let makeDeclaration fmt names d =
     Format.fprintf fmt "  name:   '%s',@\n" (Pkg.name_of_ident d.d_ident) ;
     Format.fprintf fmt "  input:  %a,@\n" makeParam input ;
     Format.fprintf fmt "  output: %a,@\n" makeParam output ;
+    Format.fprintf fmt "  signals: [%a],@\n"
+      (Pretty_utils.pp_list ~pre:"@[<hov 2>[ " ~sep:",@ " ~suf:"@ ]@]"
+         (fun fmt s -> Format.fprintf fmt "{ name: '%s' }" s))
+         rq.rq_signals;
     Format.fprintf fmt "};@\n" ;
     makeDescr fmt d.d_descr ;
     Format.fprintf fmt
diff --git a/ivette/src/frama-c/server.ts b/ivette/src/frama-c/server.ts
index 986a69a6695..63c8029b557 100644
--- a/ivette/src/frama-c/server.ts
+++ b/ivette/src/frama-c/server.ts
@@ -736,6 +736,11 @@ export enum RqKind {
   EXEC = 'EXEC'
 }
 
+/** Server signal. */
+export interface Signal {
+  name: string;
+}
+
 /** Server request. */
 export interface Request<Kd extends RqKind, In, Out> {
   kind: Kd;
@@ -745,11 +750,8 @@ export interface Request<Kd extends RqKind, In, Out> {
   input: Json.Loose<In>;
   /** Decoder of output parameters. */
   output: Json.Loose<Out>;
-}
-
-/** Server signal. */
-export interface Signal {
-  name: string;
+  /** Signals the request depends on */
+  signals: Array<Signal>;
 }
 
 export type GetRequest<In, Out> = Request<RqKind.GET, In, Out>;
diff --git a/ivette/src/frama-c/states.ts b/ivette/src/frama-c/states.ts
index 876761db7b4..e536669d763 100644
--- a/ivette/src/frama-c/states.ts
+++ b/ivette/src/frama-c/states.ts
@@ -66,6 +66,7 @@ Server.onReady(async () => {
       name: 'kernel.project.getCurrent',
       input: Json.jNull,
       output: Json.jObject({ id: Json.jString }),
+      signals: [],
     };
     const current: { id?: string } = await Server.send(sr, null);
     currentProject = current.id;
@@ -109,6 +110,7 @@ export async function setProject(project: string) {
         name: 'kernel.project.setCurrent',
         input: Json.jString,
         output: Json.jNull,
+        signals: [],
       };
       await Server.send(sr, project);
       currentProject = project;
@@ -140,8 +142,9 @@ export interface UseRequestOptions<A> {
   Cached GET request (Custom React Hook).
 
   Sends the specified GET request and returns its result. The request is send
-  asynchronously and cached until any change in the request parameters or
-  server state.
+  asynchronously and cached until any change in the request parameters or server
+  state. The change in the server state are tracked by the signals specified
+  when registering the request or by the one in options.onSignals if specified.
 
   Options can be used to tune more precisely the behavior of the hook.
  */
@@ -183,7 +186,7 @@ export function useRequest<In, Out>(
     }
   });
 
-  const signals = options.onSignals ?? [];
+  const signals = options.onSignals ?? rq.signals;
   React.useEffect(() => {
     signals.forEach((s) => Server.onSignal(s, trigger));
     return () => {
diff --git a/src/plugins/server/main.ml b/src/plugins/server/main.ml
index e7e65dd1658..80b5075d262 100644
--- a/src/plugins/server/main.ml
+++ b/src/plugins/server/main.ml
@@ -177,6 +177,7 @@ let execute server ?yield proc =
 (* -------------------------------------------------------------------------- *)
 
 type signal = string
+let signal_name s = s
 let signals = Hashtbl.create 32
 let signal s =
   if Hashtbl.mem signals s then
diff --git a/src/plugins/server/main.mli b/src/plugins/server/main.mli
index 1ea574e0737..006b69f7c99 100644
--- a/src/plugins/server/main.mli
+++ b/src/plugins/server/main.mli
@@ -43,6 +43,7 @@ val exec : string -> json -> json (** @raises Not_found if not registered. *)
 
 type signal
 val signal : string -> signal
+val signal_name : signal -> string
 
 (* -------------------------------------------------------------------------- *)
 (** {2 Server Main Process} *)
diff --git a/src/plugins/server/package.ml b/src/plugins/server/package.ml
index d771ebc636d..e99bdf70c4c 100644
--- a/src/plugins/server/package.ml
+++ b/src/plugins/server/package.ml
@@ -204,6 +204,7 @@ type requestInfo = {
   rq_kind: [ `GET | `SET | `EXEC ];
   rq_input: paramInfo ;
   rq_output: paramInfo ;
+  rq_signals: string list ;
 }
 
 type arrayInfo = {
diff --git a/src/plugins/server/package.mli b/src/plugins/server/package.mli
index 73da7e4d3d6..7e61f292ae0 100644
--- a/src/plugins/server/package.mli
+++ b/src/plugins/server/package.mli
@@ -68,6 +68,7 @@ type requestInfo = {
   rq_kind: [ `GET | `SET | `EXEC ];
   rq_input: paramInfo ;
   rq_output: paramInfo ;
+  rq_signals : string list;
 }
 
 type arrayInfo = {
diff --git a/src/plugins/server/request.ml b/src/plugins/server/request.ml
index d885343ad39..d49a9e469e3 100644
--- a/src/plugins/server/request.ml
+++ b/src/plugins/server/request.ml
@@ -262,7 +262,7 @@ let mk_output (type b) name required (output : b rq_output) : (rq -> b -> json)
        fmap_to_json rq.result)
 
 let register_sig (type a b)
-    ~package ~kind ~name ~descr
+    ~package ~kind ~name ~descr ?(signals=[])
     (s : (a,b) signature) (process : rq -> a -> b) =
   if s.defined then
     Senv.fatal "Request '%s' is defined twice" name ;
@@ -276,6 +276,7 @@ let register_sig (type a b)
       rq_kind = kind ;
       rq_input = rq_input s.input ;
       rq_output = rq_output s.output ;
+      rq_signals = List.map Main.signal_name signals ;
     } in
   let id = declare_id ~package ~name ~descr request in
   Main.register kind (name_of_ident id) processor ;
@@ -285,8 +286,8 @@ let register_sig (type a b)
 (* --- Request Registration                                               --- *)
 (* -------------------------------------------------------------------------- *)
 
-let register ~package ~kind ~name ~descr ~input ~output process =
-  register_sig  ~package ~kind ~name ~descr
+let register ~package ~kind ~name ~descr ?signals ~input ~output process =
+  register_sig  ~package ~kind ~name ~descr ?signals
     (signature ~input ~output ())
     (fun _rq v -> process v)
 
diff --git a/src/plugins/server/request.mli b/src/plugins/server/request.mli
index a4a6c4596bf..eba95d10ac6 100644
--- a/src/plugins/server/request.mli
+++ b/src/plugins/server/request.mli
@@ -76,7 +76,8 @@ val on_signal : signal -> (bool -> unit) -> unit
 
 (** {2 Simple Requests Registration} *)
 
-(** Register a simple request of type [(a -> b)].
+(** Register a simple request of type [(a -> b)] which depends on the given
+    signals
 
     Name, page and kind must be consistent with each others:
     - No publication on [`Protocol] pages
@@ -92,6 +93,7 @@ val register :
   kind:kind ->
   name:string ->
   descr:Markdown.text ->
+  ?signals:signal list ->
   input:'a input ->
   output:'b output ->
   ('a -> 'b) -> unit
@@ -154,6 +156,7 @@ val register_sig :
   kind:kind ->
   name:string ->
   descr:Markdown.text ->
+  ?signals:signal list ->
   ('a,'b) signature -> (rq -> 'a -> 'b) -> unit
 
 (** {2 Named Parameters and Results}
diff --git a/src/plugins/server/server_doc.ml b/src/plugins/server/server_doc.ml
index 3bc8bae5c26..efe004bbd55 100644
--- a/src/plugins/server/server_doc.ml
+++ b/src/plugins/server/server_doc.ml
@@ -180,7 +180,10 @@ let descr_of_decl names decl =
     Md.quote (md_param ~kind:"input" pp rq.rq_input) @
     Md.quote (md_param ~kind:"output" pp rq.rq_output) @
     md_named ~kind:"input" pp rq.rq_input @
-    md_named ~kind:"output" pp rq.rq_output
+    md_named ~kind:"output" pp rq.rq_output @
+    Md.quote (Md.emph "signals") @
+    Md.block Md.(list (List.map (fun x -> text (code x))
+                         rq.rq_signals))
 
 let declaration page names decl =
   match decl.d_kind with
-- 
GitLab