From acb42d7250f4832e2c93e5ecfaab4dd69b4c4a11 Mon Sep 17 00:00:00 2001 From: Marc Coquand Date: Sat, 18 May 2024 13:36:55 -0500 Subject: Arbitrary command for article --- lib/arbitrary_command.ml | 2 +- lib/grep.ml | 5 +++ lib/headlines.ml | 2 ++ lib/stitched_article.ml | 82 ++++++++++++++++++++++++++++++++++++++++++++---- 4 files changed, 84 insertions(+), 7 deletions(-) (limited to 'lib') diff --git a/lib/arbitrary_command.ml b/lib/arbitrary_command.ml index 920a82f..05baf43 100644 --- a/lib/arbitrary_command.ml +++ b/lib/arbitrary_command.ml @@ -7,7 +7,7 @@ let run ~(on_return : string -> unit) t ~selected_file ~content ~command = command |> List.map (fun s -> let s = Str.global_replace (Str.regexp "%(file)") selected_file s in - Str.global_replace (Str.regexp "%(content)") content s) + Str.global_replace (Str.regexp "%(line)") content s) in Common.Term.cursor t (Some (0, 0)); try diff --git a/lib/grep.ml b/lib/grep.ml index 5690edc..c5acbb6 100644 --- a/lib/grep.ml +++ b/lib/grep.ml @@ -292,6 +292,11 @@ type display_type = | Bold of string | Normal of string +let display_type_line = function + | Bold s -> s + | Normal s -> s + + let pretty_print_parsed_content parsed_files = let padding = String.make headline_pattern_length ' ' in List.concat_map diff --git a/lib/headlines.ml b/lib/headlines.ml index 915ba22..2f9ebe4 100644 --- a/lib/headlines.ml +++ b/lib/headlines.ml @@ -114,6 +114,8 @@ let rec render ; content = full_content |> Array.of_list ; content_pretty = full_content_pretty ; scroll = 0 + ; tag + ; output = None ; go_back = (fun () -> render t state) ; goto_todos_view ; goto_done_view diff --git a/lib/stitched_article.ml b/lib/stitched_article.ml index e6c8f0f..f9fa45a 100644 --- a/lib/stitched_article.ml +++ b/lib/stitched_article.ml @@ -12,6 +12,8 @@ type state = ; content_pretty : (int * Grep.display_type) array ; goto_todos_view : (unit -> unit) -> unit ; goto_done_view : (unit -> unit) -> unit + ; output : string option + ; tag : string } let title = I.strf ~attr:A.(st bold) "%s" "Note View" |> I.pad ~l:0 ~t:0 @@ -20,30 +22,45 @@ let content_start = 1 (* TODO: Use grep -l to filter notes by regexp and rerender those files*) let rec render t - ({ pos; scroll; content_pretty; go_back; content; goto_todos_view; goto_done_view } as - state) + ({ output + ; pos + ; scroll + ; content_pretty + ; go_back + ; content + ; goto_todos_view + ; goto_done_view + ; tag + } as state) = let size_x, size_y = Common.Term.size t in let x, y = pos in let img = - let elements = + 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 + and elements = Array.mapi (fun i (_, el) -> Compontent.current_line size_x y scroll el (i + content_start)) (* TODO: Fix this ugly slow conversion *) (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 elements + output_info Array.fold_left (fun sum el -> el sum) title elements in Common.Term.image t img; let content_length = Array.length content_pretty 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_length - 1); scroll } + render t + @@ { state with pos = x, min (y + 1) (content_length - 1); scroll; output = None } in match Common.Term.event t with | `End | `Key (`Escape, []) | `Key (`ASCII 'q', []) | `Key (`ASCII 'C', [ `Ctrl ]) -> () @@ -57,6 +74,58 @@ 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 '!', []) -> + let file_number_offset, content_line = Array.get content_pretty (y - content_start) in + let content_line = Grep.display_type_line content_line in + let selected_file, _, _, _ = + Array.get content (y - content_start - file_number_offset) + in + let selected_file = Grep.execution_directory ^ "/" ^ selected_file 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 ( + let content = Grep.get_file_names tag |> Array.of_list in + let content = + Array.map + (fun file_name -> Grep.get_full_file_content_content file_name) + content + |> Array.to_list + in + let content = Grep.parse_full_content content in + let content_pretty = + Grep.pretty_print_parsed_content content |> Array.of_list + in + Arbitrary_command.run + t + ~command:(Scanf.unescaped command) + ~content:content_line + ~selected_file + ~on_return:(fun result -> + Common.Term.cursor t None; + render + t + { state with + content = Array.of_list content + ; content_pretty + ; pos = 0, content_start + ; 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 's', []) -> let (input_state : Input_prompt.state) = { screen = img @@ -87,6 +156,7 @@ let rec render ; content_pretty ; pos = 0, content_start ; scroll = 0 + ; tag } with | _ -> -- cgit v1.2.3