From fbbbdca67c79145d43d6fdd59202a36fddfc8cd0 Mon Sep 17 00:00:00 2001 From: Marc Coquand Date: Sat, 18 May 2024 13:13:29 -0500 Subject: Add command execution to TODO --- lib/todos.ml | 64 +++++++++++++++++++++++++++++++++++++++++++++++++++++++----- 1 file changed, 59 insertions(+), 5 deletions(-) diff --git a/lib/todos.ml b/lib/todos.ml index 51b878f..bdbf877 100644 --- a/lib/todos.ml +++ b/lib/todos.ml @@ -10,6 +10,8 @@ type state = ; content_pretty : string array ; goto_headlines : (unit -> unit) -> unit ; goto_done : (unit -> unit) -> unit + ; output : string option + ; tag : string } let title = I.strf ~attr:A.(st bold) "%s" "Todo View" |> I.pad ~l:0 ~t:0 @@ -24,6 +26,8 @@ let init ~goto_done ~goto_headlines = ; content_pretty = content_pretty |> Array.of_list ; goto_headlines ; goto_done + ; output = None + ; tag = "" } @@ -35,11 +39,19 @@ let load_todos () = let rec render t - ({ pos; scroll; content; content_pretty; goto_headlines; goto_done } as state) + ({ pos; scroll; content; content_pretty; goto_headlines; goto_done; output; _ } as state) = let x, y = pos in + let size_x, size_y = Common.Term.size t in let content_position = y - content_start in let img = + let output_info = + match output with + | Some line -> + I.strf "%s%s" (String.escaped line) (String.make size_x ' ') + |> I.pad ~t:(size_y - 1) + | None -> I.empty + in let dot = if Array.length content_pretty = 0 then I.empty @@ -53,18 +65,17 @@ let rec render (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 + Array.fold_left (fun sum el -> el sum) (title dot output_info) 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 } + render t { state with pos = x, max (y - 1) content_start; scroll; output = None } 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 } + render t { state with pos = x, min (y + 1) content_end; scroll; output = None } in match Common.Term.event t with | `End | `Key (`Escape, []) | `Key (`ASCII 'q', []) | `Key (`ASCII 'C', [ `Ctrl ]) -> () @@ -103,6 +114,7 @@ let rec render { state with content = content |> Array.of_list ; content_pretty = content_pretty |> Array.of_list + ; tag }) ; on_cancel = (fun _ -> @@ -113,6 +125,48 @@ let rec render Input_prompt.render t input_state | `Key (`ASCII 'j', []) | `Key (`ASCII 'N', [ `Ctrl ]) -> scroll_down () | `Key (`ASCII 'k', []) | `Key (`ASCII 'P', [ `Ctrl ]) -> scroll_up () + | `Key (`ASCII '!', []) -> + let selected_file, _ = Array.get content content_position in + let selected_file = Grep.execution_directory ^ "/" ^ selected_file in + let content = + Array.map (fun (_, c) -> c) content |> Array.to_list |> String.concat "\n" + in + let (input_state : Input_prompt.state) = + { screen = img + ; user_input = "" + ; prompt = "COMMAND" + ; on_enter = + (fun command -> + if String.equal (String.trim command) String.empty + then ( + Common.Term.cursor t None; + render t state) + else + Arbitrary_command.run + t + ~command:(Scanf.unescaped command) + ~content + ~selected_file + ~on_return:(fun result -> + let content, content_pretty = load_todos () in + let y = min (List.length content_pretty + content_start) y in + Common.Term.cursor t None; + render + t + { state with + content = Array.of_list content + ; content_pretty = Array.of_list content_pretty + ; pos = 0, y + ; scroll = 0 + ; output = Some result + })) + ; on_cancel = + (fun _ -> + Common.Term.cursor t None; + render t state) + } + in + Input_prompt.render t input_state | `Key (`ASCII 'T', [ `Ctrl ]) -> let selected_file, _ = Array.get content (y - content_start) in let _ = Grep.toggle_done selected_file in -- cgit v1.2.3