stitch

Note taking for messy minimalists

git clone git://mccd.space/stitch
commit 681c9e3a618a6834aa778102d8f4fd201d488244
parent 598ce9ecef91264bd78555bd5b6fcca97a073d95
Author: Marc Coquand <marc@mccd.space>
Date:   Sun, 30 Jun 2024 17:23:27 -0500

Bug fixes

Diffstat:
Mlib/grep.ml | 10++++++----
Mlib/headlines.ml | 61+++++++++++++++++++++++++++++++++++++++----------------------
Mlib/stitch.ml | 18++++++++++++------
3 files changed, 57 insertions(+), 32 deletions(-)
diff --git a/lib/grep.ml b/lib/grep.ml
@@ -197,7 +197,7 @@ let get_headlines () =
 let get_tagged_headlines tag () =
   let open Shexp_process in
   let open Shexp_process.Infix in
-  try
+  let cmd () =
     eval
       (chdir
          execution_directory
@@ -208,8 +208,10 @@ let get_tagged_headlines tag () =
           |- call filter_done_args
           |- call [ "sort"; "-n"; "-r" ]
           |- read_all))
-  with
-  | _ -> ""
+    |> Option.some
+  in
+  try cmd () with
+  | _ -> None
 
 
 let get_tags () =
@@ -233,7 +235,7 @@ let parse_headlines s =
       match split with
       (* file, line, content *)
       | [ file_name; content ] -> Some (file_name, content)
-      | _ -> raise (Not_A_Tuple (String.concat " SPLIT " split, message))))
+      | _ -> None))
   |> Array.of_list
 
 
diff --git a/lib/headlines.ml b/lib/headlines.ml
@@ -18,24 +18,31 @@ type state =
   }
 
 let init ~goto_done_view ~goto_todos_view ~regexp =
-  let content = Grep.get_tagged_headlines regexp () |> Grep.parse_headlines in
-  if Array.length content == 0
-  then (
-    print_endline "Regexp not found";
-    exit 0)
-  else (
-    let hide_file_name = true in
-    let content_pretty = content |> Grep.pretty_format ~hide_file_name in
-    { pos = 0, 2
-    ; scroll = 0
-    ; content
-    ; content_pretty
-    ; goto_done_view
-    ; goto_todos_view
-    ; output = None
-    ; tag = regexp
-    ; hide_file_name
-    })
+  let content = Grep.get_tagged_headlines regexp () |> Option.map Grep.parse_headlines in
+  match content with
+  | None ->
+    Error
+      "There are no notes to load. Make sure to create some in order to view them in \
+       stitch. Check stitch --help for how to get started."
+  | Some content ->
+    if Array.length content == 0
+    then (
+      print_endline "Unable to load any content. Check grep commands and make sure there are notes";
+      exit 0)
+    else (
+      let hide_file_name = true in
+      let content_pretty = content |> Grep.pretty_format ~hide_file_name in
+      Ok
+        { pos = 0, 2
+        ; scroll = 0
+        ; content
+        ; content_pretty
+        ; goto_done_view
+        ; goto_todos_view
+        ; output = None
+        ; tag = regexp
+        ; hide_file_name
+        })
 
 
 let title ~tag =
@@ -45,8 +52,12 @@ let title ~tag =
 
 
 let refresh ~hide_file_name regexp =
-  let content = Grep.get_tagged_headlines regexp () |> Grep.parse_headlines in
-  content, content |> Grep.pretty_format ~hide_file_name
+  let content =
+    Grep.get_tagged_headlines regexp ()
+    |> Option.map Grep.parse_headlines
+    |> Option.value ~default:[||]
+  in
+  content, Grep.pretty_format ~hide_file_name content
 
 
 let rec render
@@ -173,7 +184,11 @@ let rec render
       ; prompt = "REGEXP"
       ; on_enter =
           (fun tag ->
-            let content = Grep.get_tagged_headlines tag () |> Grep.parse_headlines in
+            let content =
+              Grep.get_tagged_headlines tag ()
+              |> Option.map Grep.parse_headlines
+              |> Option.value ~default:[||]
+            in
             let content_pretty = Grep.pretty_format ~hide_file_name content in
             Common.Term.cursor t None;
             render
@@ -225,7 +240,9 @@ let rec render
                 ~selected_file
                 ~on_return:(fun result ->
                   let content =
-                    Grep.get_tagged_headlines tag () |> Grep.parse_headlines
+                    Grep.get_tagged_headlines tag ()
+                    |> Option.map Grep.parse_headlines
+                    |> Option.value ~default:[||]
                   in
                   let content_pretty = Grep.pretty_format ~hide_file_name content in
                   Common.Term.cursor t None;
diff --git a/lib/stitch.ml b/lib/stitch.ml
@@ -4,13 +4,13 @@ module Todos = Todos
 module Headlines = Headlines
 
 let start (tag : string) () =
-  (* This is a rather funky state management that isn't maybe entirely functional.
+  (* This is a rather funky state management.
      What we do is store a function for each view that restores it's state. Since the render function is
      void -> void
 
      This allows us to remember the state of the view and restore it as we travel between different views.
 
-     It does create a rather funky, cyclical state though.
+     It does create a cyclical state though.
   *)
   if String.equal String.empty (String.trim Grep.execution_directory)
   then
@@ -19,12 +19,12 @@ let start (tag : string) () =
        STITCH_DIRECTORY to the absolute path of your notes. For example: \
        STITCH_DIRECTORY='/home/you/notes'."
   else (
-    print_endline "Launching";
     let term = Common.Term.create () in
     let restore_headline_state = ref (fun () -> ()) in
     let restore_done_state = ref (fun () -> ()) in
     let restore_todo_state = ref (fun () -> ()) in
-    (* DONE *)
+    (* INIT DONE VIEW *)
+    print_endline "DONE INIT";
     let goto_todo_from_done new_done_state =
       restore_done_state := new_done_state;
       !restore_todo_state ()
@@ -41,7 +41,8 @@ let start (tag : string) () =
               ~goto_todo:goto_todo_from_done
           in
           Done.render term done_state);
-    (* TODO *)
+    (* INIT TODO VIEW *)
+    print_endline "TODO INIT";
     let goto_done_from_todo new_todo_state =
       restore_todo_state := new_todo_state;
       !restore_done_state ()
@@ -58,6 +59,8 @@ let start (tag : string) () =
               ~goto_done:goto_done_from_todo
           in
           Todos.render term todo);
+    (* INIT HEADLINE VIEW *)
+    print_endline "HEADLINE INIT";
     let headline =
       Headlines.init
         ~goto_done_view:(fun new_state ->
@@ -68,4 +71,7 @@ let start (tag : string) () =
           !restore_todo_state ())
         ~regexp:tag
     in
-    Headlines.render term headline)
+    print_endline "Got render without error";
+    match headline with
+    | Ok headline -> Headlines.render term headline
+    | Error msg -> print_endline msg)