stitch

Note taking for messy minimalists

git clone git://mccd.space/stitch
commit eed9e36b661009e5bcf1c4f5ec3a9279bbb7cda5
parent 833716046de9b3ee8e4f277f383967c0d35ba28a
Author: Marc Coquand <marc@mccd.space>
Date:   Thu, 23 May 2024 13:45:28 -0500

Add ability to export current view

Diffstat:
Alib/export.ml | 4++++
Mlib/headlines.ml | 27+++++++++++++++++++++++----
Mlib/help_screen.ml | 2+-
Mlib/stitched_article.ml | 26++++++++++++++++++++++++++
4 files changed, 54 insertions(+), 5 deletions(-)
diff --git a/lib/export.ml b/lib/export.ml
@@ -0,0 +1,4 @@
+let to_path path ~content =
+  let oc = open_out path in
+  Printf.fprintf oc "%s" content;
+  close_out oc
diff --git a/lib/headlines.ml b/lib/headlines.ml
@@ -18,9 +18,7 @@ type state =
   }
 
 let init ~goto_done_view ~goto_todos_view ~regexp =
-  let content =
-    Grep.get_tagged_headlines regexp () |> Grep.parse_headlines
-  in
+  let content = Grep.get_tagged_headlines regexp () |> Grep.parse_headlines in
   if Array.length content == 0
   then (
     print_endline "Regexp not found";
@@ -77,7 +75,7 @@ let rec render
     and elements =
       Array.mapi
         (fun i el ->
-          if i + 1 == y - scroll 
+          if i + 1 == y - scroll
           then I.strf "%s" el |> I.pad ~l:2 ~t:(i + content_start)
           else I.strf "%s" el |> I.pad ~l:2 ~t:(i + content_start))
         (Basic.array_drop scroll content_pretty)
@@ -109,6 +107,27 @@ let rec render
     render t { state with pos = 0, min y content_end; output = None }
   | `Key (`ASCII '?', []) -> Help_screen.render t { go_back = (fun () -> render t state) }
   | `Key (`ASCII '2', []) -> goto_todos_view (fun () -> render t state)
+  | `Key (`ASCII 'o', []) ->
+    let (input_state : Input_prompt.state) =
+      { screen = img
+      ; user_input = ""
+      ; prompt = "EXPORT TO"
+      ; on_enter =
+          (fun path ->
+            Common.Term.cursor t None;
+            if String.equal (String.trim path) String.empty |> not
+            then (
+              let export = String.concat "\n" (Array.to_list content_pretty) in
+              Export.to_path path ~content:export;
+              render t { state with output = Some ("Export written to: " ^ path) })
+            else render t { state with output = Some "Export Blank; skipping" })
+      ; on_cancel =
+          (fun _ ->
+            Common.Term.cursor t None;
+            render t { state with output = Some "Export Cancelled" })
+      }
+    in
+    Input_prompt.render t input_state
   | `Key (`ASCII 'h', []) ->
     let hide_file_name = not hide_file_name in
     let content_pretty = content |> Grep.pretty_format ~hide_file_name in
diff --git a/lib/help_screen.ml b/lib/help_screen.ml
@@ -53,7 +53,7 @@ let render_menu ~menu ~title ~start_y =
   1 + List.length elements, List.fold_left (fun sum el -> el </> sum) keybindings elements
 
 
-let note_view_menu = [ "Toggle Full-View Mode", "f" ]
+let note_view_menu = [ "Toggle Full-View Mode", "f"; "Export View", "o" ]
 let todo_view_menu = [ "Toggle Done", "Ctrl-t"; "Refresh", "g" ]
 let done_view_menu = [ "Toggle Todo", "Ctrl-t"; "Refresh", "g" ]
 
diff --git a/lib/stitched_article.ml b/lib/stitched_article.ml
@@ -79,6 +79,32 @@ let rec render
     render t { state with pos = 0, min y content_length }
   | `Key (`ASCII 'j', []) | `Key (`ASCII 'N', [ `Ctrl ]) -> scroll_down ()
   | `Key (`ASCII 'k', []) | `Key (`ASCII 'P', [ `Ctrl ]) -> scroll_up ()
+  | `Key (`ASCII 'o', []) ->
+    let (input_state : Input_prompt.state) =
+      { screen = img
+      ; user_input = ""
+      ; prompt = "EXPORT TO"
+      ; on_enter =
+          (fun path ->
+            Common.Term.cursor t None;
+            if String.equal (String.trim path) String.empty |> not
+            then (
+              let export =
+                String.concat
+                  "\n"
+                  (Array.to_list content_pretty
+                   |> List.map (fun (_, b) -> Grep.display_type_line b))
+              in
+              Export.to_path path ~content:export;
+              render t { state with output = Some ("Export written to: " ^ path ) })
+            else render t { state with output = Some "Export Blank; skipping" })
+      ; on_cancel =
+          (fun _ ->
+            Common.Term.cursor t None;
+            render t {state with output = Some "Export Cancelled"})
+      }
+    in
+    Input_prompt.render t input_state
   | `Key (`ASCII '!', []) ->
     let file_number_offset, content_line = Array.get content_pretty (y - content_start) in
     let content_line = Grep.display_type_line content_line in