aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMarc Coquand <marc@mccd.space>2024-05-18 13:36:55 -0500
committerMarc Coquand <marc@mccd.space>2024-05-18 13:36:55 -0500
commitacb42d7250f4832e2c93e5ecfaab4dd69b4c4a11 (patch)
tree40d1123e90d13dfbedd20bc329dd85afe808aa1d
parentf805a04bd0600653f71e5e4e006104892cf7b6b9 (diff)
downloadstitch-acb42d7250f4832e2c93e5ecfaab4dd69b4c4a11.tar.gz
stitch-acb42d7250f4832e2c93e5ecfaab4dd69b4c4a11.tar.bz2
stitch-acb42d7250f4832e2c93e5ecfaab4dd69b4c4a11.zip
Arbitrary command for article
-rw-r--r--bin/main.ml2
-rw-r--r--lib/arbitrary_command.ml2
-rw-r--r--lib/grep.ml5
-rw-r--r--lib/headlines.ml2
-rw-r--r--lib/stitched_article.ml82
5 files changed, 85 insertions, 8 deletions
diff --git a/bin/main.ml b/bin/main.ml
index 8fbefb1..64ef144 100644
--- a/bin/main.ml
+++ b/bin/main.ml
@@ -147,7 +147,7 @@ let headlines_cmd =
"You can run arbitrary commands in Stitch. These commands can make use of \
variable substitutions. Available substitutions are"
; `I ("%(file)", "Currently selected file")
- ; `I ("%(content)", "Currently selected content")
+ ; `I ("%(line)", "Currently selected content")
]
in
let credit =
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
| _ ->