diff options
Diffstat (limited to 'lib/done.ml')
-rw-r--r-- | lib/done.ml | 141 |
1 files changed, 141 insertions, 0 deletions
diff --git a/lib/done.ml b/lib/done.ml new file mode 100644 index 0000000..5daad60 --- /dev/null +++ b/lib/done.ml @@ -0,0 +1,141 @@ +module Grep = Grep +module Common = Common +open Notty +module Help_screen = Help_screen + +type state = + { pos : int * int + ; scroll : int + ; content : (string * string) array + ; content_pretty : string array + ; goto_headlines : (unit -> unit) -> unit + ; goto_todo : (unit -> unit) -> unit + } + +let title = I.strf ~attr:A.(st bold) "%s" "Done View" |> I.pad ~l:0 ~t:0 +let content_start = 2 + +let init ~goto_todo ~goto_headlines = + let content = Grep.get_done () |> Grep.parse_todo_string in + let content_pretty = Grep.pretty_format_todo content in + { pos = 0, content_start + ; scroll = 0 + ; content = content |> Array.of_list + ; content_pretty = content_pretty |> Array.of_list + ; goto_headlines + ; goto_todo + } + + +let load_done () = + let done_content = Grep.get_done () |> Grep.parse_todo_string in + let done_pretty = Grep.pretty_format_todo done_content in + done_content, done_pretty + + +let rec render + t + ({ pos; scroll; content; content_pretty; goto_headlines; goto_todo } as state) + = + let x, y = pos in + let content_position = y - content_start in + let img = + let dot = I.string A.(st bold) ">" |> I.pad ~l:0 ~t:(y - scroll) + and elements = + Array.mapi + (fun i el -> + if i == 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)) + (Array.to_seq content_pretty |> Seq.drop scroll |> Array.of_seq) + in + let open I in + Array.fold_left (fun sum el -> el </> sum) (title </> dot) elements + in + let _, size_y = Common.Term.size t in + Common.Term.image t img; + let content_end = Array.length content_pretty + (content_start - 1) in + let scroll_up () = + let scroll = if y - content_start - scroll = 0 then max (scroll - 1) 0 else scroll in + render t { state with pos = x, max (y - 1) content_start; scroll } + in + let scroll_down () = + let scroll = if y - scroll >= size_y - 1 then scroll + 1 else scroll in + render t { state with pos = x, min (y + 1) content_end; scroll } + in + match Common.Term.event t with + | `End | `Key (`Escape, []) | `Key (`ASCII 'q', []) | `Key (`ASCII 'C', [ `Ctrl ]) -> () + | `Mouse (`Press (`Scroll s), _, _) -> + (match s with + | `Down -> scroll_down () + | `Up -> scroll_up ()) + | `Resize _ -> render t state + | `Mouse ((`Press _ | `Drag), (_, y), _) -> + render t { state with pos = 0, min y content_end } + | `Key (`ASCII '?', []) -> Help_screen.render t { go_back = (fun () -> render t state) } + | `Key (`ASCII 's', []) -> + let (input_state : Input_screen.state) = + { screen = img + ; user_input = "" + ; prompt = "GREP: " + ; on_enter = + (fun tag -> + let content = Grep.get_tagged_headlines tag () |> Grep.parse_headlines in + let content_pretty = Grep.pretty_format content in + Common.Term.cursor t None; + render t { state with content; content_pretty }) + ; on_cancel = + (fun _ -> + Common.Term.cursor t None; + render t state) + } + in + Input_screen.render t input_state + | `Key (`ASCII '1', []) -> goto_headlines (fun () -> render t state) + | `Key (`ASCII '2', []) -> goto_todo (fun () -> render t state) + | `Key (`ASCII 'j', []) | `Key (`ASCII 'N', [ `Ctrl ]) -> scroll_down () + | `Key (`ASCII 'k', []) | `Key (`ASCII 'P', [ `Ctrl ]) -> scroll_up () + | `Key (`ASCII 't', []) -> + let selected_file, _ = Array.get content (y - content_start) in + let _ = Grep.toggle_todo selected_file in + let content, content_pretty = load_done () in + render + t + { state with + content = content |> Array.of_list + ; content_pretty = Array.of_list content_pretty + } + | `Key (`Arrow d, _) -> + (match d with + | `Up -> scroll_up () + | `Down -> scroll_down () + | _ -> render t state) + | `Key (`ASCII 'e', []) | `Key (`Enter, []) -> + (* Editor might be set with extra args, in that case we need to separate these *) + let[@warning "-8"] (editor :: args) = + String.split_on_char ' ' (Sys.getenv "EDITOR") + in + let selected_file, _ = Array.get content content_position in + let full_path_file = Grep.execution_directory ^ "/" ^ selected_file in + let full_args = Array.append (Array.of_list args) [| full_path_file |] in + Common.Term.cursor t (Some (0, 0)); + let _ = + Unix.create_process_env + editor + full_args + (Unix.environment ()) + Unix.stdin + Unix.stdout + Unix.stderr + in + let rec run_editor () = + match Unix.wait () with + | _, _ -> + Common.Term.cursor t None; + render t state + (* Capture resizing events *) + | exception Unix.Unix_error (Unix.EINTR, _, _) -> run_editor () + | exception Unix.Unix_error (_, _, _) -> failwith "ERROR" + in + run_editor () + | _ -> render t state |