aboutsummaryrefslogtreecommitdiff
path: root/lib/grep.ml
blob: 0d79c575e78cb858d2b65d4deb3b456bf32ac99e (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
let execution_directory =
  Sys.getenv_opt "STICH_DIRECTORY" |> Option.value ~default:"/home/mccd/notes-example"


let grep_cmd = Sys.getenv_opt "STICH_GREP_CMD" |> Option.value ~default:"ugrep"

let tag_pattern =
  Sys.getenv_opt "STITCH_TAG_PATTERN" |> Option.value ~default:":[a-z_-]+:"


let headline_pattern =
  Sys.getenv_opt "STITCH_HEADLINE_PATTERN" |> Option.value ~default:"^\\* "


let find_sort_modification () =
  let open Shexp_process in
  let open Shexp_process.Infix in
  call [ "find"; "."; "-printf"; "%Ts/%f\\n" ]
  |- call [ "sort"; "-n" ]
  |- call [ "cut"; "-c12-" ]
  |- call [ "sed"; "/^\\./d" ]


let find_sort_name () =
  let open Shexp_process in
  let open Shexp_process.Infix in
  call [ "find"; "." ] |- call [ "sort"; "-n" ] |- call [ "cut"; "-c3-" ]


let run_print ~dir args =
  let open Shexp_process in
  let open Shexp_process.Infix in
  eval (chdir dir (call args |- read_all))


let headline_args =
  [ "xargs"; grep_cmd; "^\\*"; "-H"; "-r"; "-n"; "--separator=|"; "--no-messages" ]


(* type sort = *)
(*   | Name *)
(*   | LastModified *)

(* let sort_to_cmd = function *)
(*   | Name -> find_sort_name () *)
(*   | LastModified -> find_sort_modification () *)

let get_headlines () =
  let open Shexp_process in
  let open Shexp_process.Infix in
  eval
    (chdir
       execution_directory
       (find_sort_modification () |- call headline_args |- read_all))


let get_tagged_headlines tag () =
  let open Shexp_process in
  let open Shexp_process.Infix in
  eval
    (chdir
       execution_directory
       (find_sort_name ()
        |- call headline_args
        |- call [ grep_cmd; "-E"; "--no-messages"; tag ]
        |- read_all))


let get_tags () =
  let open Shexp_process in
  let open Shexp_process.Infix in
  eval
    (chdir
       execution_directory
       (call headline_args |- call [ grep_cmd; "-E"; tag_pattern; "-o" ] |- read_all))


exception Not_A_Tuple of string * string

(** Returns a tuple of file name and Content *)
let parse_headlines s =
  String.split_on_char '\n' s
  (* Testing in utop it seems like there is maybe a bug with bounded_split, 1 doesn't work for ':'. Therefore using a slower implementation. *)
  |> List.filter_map (fun message ->
    if String.equal message ""
    then None
    else (
      let split = Str.bounded_split (Str.regexp "|") message 3 in
      match split with
      (* file, line, content *)
      | [ file_name; _; content ] -> Some (file_name, content)
      | _ -> raise (Not_A_Tuple (String.concat " SPLIT " split, message))))
  |> Array.of_list


(** Used for pretty printing *)
let get_padding list =
  Array.fold_left (fun n (file_name, _) -> Int.max n (String.length file_name)) 0 list


let pad str n =
  let padding = n - String.length str in
  String.concat "" [ str; String.make padding ' ' ]


(** Turns "2024-03-05.org:* Hello world" into "2024-03-05    | * Hello world" *)
let pretty_format parsed_headlines =
  let padding = get_padding parsed_headlines in
  Array.map
    (fun (file_name, content) -> String.concat " | " [ pad file_name padding; content ])
    parsed_headlines


(** Full body parsing *)

let get_full_content () =
  run_print
    ~dir:execution_directory
    [ grep_cmd; "^\\*"; "-h"; "-r"; "-n"; "-C"; "9999"; "--separator='|'" ]

(* let parse_file_headline collection full = *)
(*   match full with *)
(*   | s :: r -> *)
(*     let split = Str.bounded_split (Str.regexp ":1:") s 1 in *)
(*     (match split with *)
(*      (\* file, line, content *\) *)
(*      | [ file_name; content ] -> file_name, content *)
(*      | rest ->  *)