From ec105eb9ce93b2eb345640f698962088676fd62e Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Loi=CC=88c=20Correnson?= <loic.correnson@cea.fr>
Date: Tue, 9 Apr 2024 22:05:21 +0200
Subject: [PATCH] [ivette/wp] filtering sub-goals navigation

---
 .../src/frama-c/plugins/wp/api/tip/index.ts   | 19 ++++---
 ivette/src/frama-c/plugins/wp/tip.tsx         | 21 ++++++--
 src/plugins/wp/wpTipApi.ml                    | 49 ++++++++++++++-----
 3 files changed, 64 insertions(+), 25 deletions(-)

diff --git a/ivette/src/frama-c/plugins/wp/api/tip/index.ts b/ivette/src/frama-c/plugins/wp/api/tip/index.ts
index b5b88e457df..c33edca169b 100644
--- a/ivette/src/frama-c/plugins/wp/api/tip/index.ts
+++ b/ivette/src/frama-c/plugins/wp/api/tip/index.ts
@@ -153,14 +153,19 @@ export const getResult: Server.GetRequest<
   >= getResult_internal;
 
 const getProofStatus_internal: Server.GetRequest<
-  goal,
-  { index: number, pending: number, current: node, parents: node[],
-    tactic?: tactic, children: node[] }
+  { main: goal, unproved?: boolean, subtree?: boolean },
+  { size: number, index: number, pending: number, current: node,
+    parents: node[], tactic?: tactic, children: node[] }
   > = {
   kind: Server.RqKind.GET,
   name: 'plugins.wp.tip.getProofStatus',
-  input: jGoal,
+  input: Json.jObject({
+           main: jGoal,
+           unproved: Json.jOption(Json.jBoolean),
+           subtree: Json.jOption(Json.jBoolean),
+         }),
   output: Json.jObject({
+            size: Json.jNumber,
             index: Json.jNumber,
             pending: Json.jNumber,
             current: jNode,
@@ -172,9 +177,9 @@ const getProofStatus_internal: Server.GetRequest<
 };
 /** Current Proof Status of a Goal */
 export const getProofStatus: Server.GetRequest<
-  goal,
-  { index: number, pending: number, current: node, parents: node[],
-    tactic?: tactic, children: node[] }
+  { main: goal, unproved?: boolean, subtree?: boolean },
+  { size: number, index: number, pending: number, current: node,
+    parents: node[], tactic?: tactic, children: node[] }
   >= getProofStatus_internal;
 
 const goForward_internal: Server.SetRequest<goal,null> = {
diff --git a/ivette/src/frama-c/plugins/wp/tip.tsx b/ivette/src/frama-c/plugins/wp/tip.tsx
index 56143ae93d7..e128cc03f03 100644
--- a/ivette/src/frama-c/plugins/wp/tip.tsx
+++ b/ivette/src/frama-c/plugins/wp/tip.tsx
@@ -237,14 +237,19 @@ export interface TIPProps {
 
 export function TIPView(props: TIPProps): JSX.Element {
   const { display, goal, onClose } = props;
+  // --- navbar settings
+  const [unproved, flipU] = Dome.useFlipSettings('frama-c.wp.goals.unproved');
+  const [subtree, flipT] = Dome.useFlipSettings('frama-c.wp.goals.subtree');
   // --- current goal
   const infos =
     States.useSyncArrayElt(WP.goals, goal) ?? WP.goalsDataDefault;
   // --- proof status
   const {
-    current, index = -1, pending = 0,
+    current, index = -1, pending = 0, size = 0,
     tactic: nodeTactic, parents = [], children = [],
-  } = States.useRequest(TIP.getProofStatus, goal, { pending: null }) ?? {};
+  } = States.useRequest(TIP.getProofStatus, goal ? {
+    main: goal, unproved, subtree,
+  } : undefined, { pending: null }) ?? {};
   // --- script status
   const { saved = false, proof = false, script } =
     States.useRequest(TIP.getScriptStatus, goal, { pending: null }) ?? {};
@@ -336,14 +341,20 @@ export function TIPView(props: TIPProps): JSX.Element {
   return (
     <Vfill display={display}>
       <ToolBar>
-        <Cell
-          icon='HOME'
-          label={infos.wpo} title='Goal identifier' />
+        <Cell icon='HOME' label={infos.wpo} title='Goal identifier' />
         <Item
           icon='CODE'
           display={0 <= index && index < pending && 1 < pending}
           label={`${index + 1}/${pending}`} title='Pending proof nodes' />
         <Item {...getStatus(infos)} />
+        <IconButton
+          display={size > 1}
+          icon='CIRC.PLUS' selected={subtree} onClick={flipT}
+          title='Show all tactic nodes' />
+        <IconButton
+          display={size > 1}
+          icon='CIRC.CHECK' selected={unproved} onClick={flipU}
+          title='Show unproved sub-goals only' />
         <Filler />
         <IconButton
           icon={copied ? 'DUPLICATE' : (saved ? 'FOLDER' : 'FOLDER.OPEN')}
diff --git a/src/plugins/wp/wpTipApi.ml b/src/plugins/wp/wpTipApi.ml
index e8582771a6c..d8a6c7fe1c0 100644
--- a/src/plugins/wp/wpTipApi.ml
+++ b/src/plugins/wp/wpTipApi.ml
@@ -142,46 +142,69 @@ let () =
     end
 
 (* -------------------------------------------------------------------------- *)
-(* --- Proof Cursor                                                       --- *)
+(* --- Proof Status                                                     --- *)
 (* -------------------------------------------------------------------------- *)
 
 let () =
-  let state = R.signature ~input:(module W.Goal) () in
-  let set_index = R.result state ~name:"index"
+  let status = R.signature () in
+  let get_main = R.param status ~name:"main"
+      ~descr:(Md.plain "Proof Obligation") (module W.Goal) in
+  let get_unproved = R.param status ~name:"unproved" ~default:false
+      ~descr:(Md.plain "Report unproved children only")
+      (module D.Jbool) in
+  let get_subtree = R.param status ~name:"subtree" ~default:false
+      ~descr:(Md.plain "Report subtree children only")
+      (module D.Jbool) in
+  let set_size = R.result status ~name:"size"
+      ~descr:(Md.plain "Proof size") (module D.Jint) in
+  let set_index = R.result status ~name:"index"
       ~descr:(Md.plain "Current node index among pending nodes (else -1)")
       (module D.Jint) in
-  let set_pending = R.result state ~name:"pending"
+  let set_pending = R.result status ~name:"pending"
       ~descr:(Md.plain "Pending proof nodes") (module D.Jint) in
-  let set_current = R.result state ~name:"current"
+  let set_current = R.result status ~name:"current"
       ~descr:(Md.plain "Current proof node") (module Node) in
-  let set_parents = R.result state ~name:"parents"
+  let set_parents = R.result status ~name:"parents"
       ~descr:(Md.plain "parents nodes")
       (module Path) in
-  let set_tactic = R.result_opt state ~name:"tactic"
+  let set_tactic = R.result_opt status ~name:"tactic"
       ~descr:(Md.plain "Applied tactic (if any)")
       (module Tactic) in
-  let set_children = R.result state ~name:"children"
+  let set_children = R.result status ~name:"children"
       ~descr:(Md.plain "Children nodes")
       (module Path) in
-  R.register_sig ~package
+  R.register_sig ~package status
     ~kind:`GET ~name:"getProofStatus"
-    ~descr:(Md.plain "Current Proof Status of a Goal") state
+    ~descr:(Md.plain "Current Proof Status of a Goal")
     ~signals:[proofStatus]
-    begin fun rq wpo ->
-      let tree = ProofEngine.proof  ~main:wpo in
+    begin fun rq () ->
+      let tree = ProofEngine.proof ~main:(get_main rq) in
       let root = ProofEngine.root tree in
       set_pending rq (ProofEngine.pending root) ;
+      set_size rq (Stats.subgoals @@ ProofEngine.stats root);
       let current, index =
         match ProofEngine.current tree with
         | `Main -> root, -1
         | `Internal node -> node, -1
         | `Leaf(idx,node) -> node, idx
       in
+      let subgoals = ProofEngine.subgoals current in
       set_index rq index ;
       set_current rq current ;
       set_parents rq @@ ProofEngine.path current ;
       set_tactic rq @@ ProofEngine.tactic current ;
-      set_children rq @@ ProofEngine.subgoals current ;
+      set_children rq @@
+      match get_unproved rq, get_subtree rq with
+      | false, false -> subgoals
+      | false, true ->
+        List.filter (fun n -> ProofEngine.subgoals n <> []) subgoals
+      | true, false ->
+        List.filter (fun n -> ProofEngine.pending n > 0) subgoals
+      | true, true ->
+        List.filter (fun n ->
+            ProofEngine.pending n > 0 ||
+            ProofEngine.subgoals n <> []
+          ) subgoals
     end
 
 (* -------------------------------------------------------------------------- *)
-- 
GitLab