···1111exception FoundStart
1212exception FoundFiller
13131414-let make_uchar str =
1515- let a = String.get_utf_8_uchar str 0 in
1616- if a |> Uchar.utf_decode_is_valid
1717- then a |> Uchar.utf_decode_uchar
1818- else failwith "not a unicode string"
1919-;;
2020-2121-let elieded_symbol = make_uchar "◌"
2222-let elieded_symbol_alt = make_uchar "○"
2323-let rev_symbol = make_uchar "◉"
2424-let merge_symbol = make_uchar "◆"
2525-2626-let is_whitespace_char (code_point : int) : bool =
2727- match code_point with
2828- | 0x0009 (* Tab *)
2929- | 0x000A (* Line Feed *)
3030- | 0x000B (* Vertical Tab *)
3131- | 0x000C (* Form Feed *)
3232- | 0x000D (* Carriage Return *)
3333- | 0x0020 (* Space *)
3434- | 0x0085 (* Next Line *)
3535- | 0x00A0 (* No-Break Space *)
3636- | 0x1680 (* Ogham Space Mark *)
3737- | 0x2000 (* En Quad *)
3838- | 0x2001 (* Em Quad *)
3939- | 0x2002 (* En Space *)
4040- | 0x2003 (* Em Space *)
4141- | 0x2004 (* Three-Per-Em Space *)
4242- | 0x2005 (* Four-Per-Em Space *)
4343- | 0x2006 (* Six-Per-Em Space *)
4444- | 0x2007 (* Figure Space *)
4545- | 0x2008 (* Punctuation Space *)
4646- | 0x2009 (* Thin Space *)
4747- | 0x200A (* Hair Space *)
4848- | 0x2028 (* Line Separator *)
4949- | 0x2029 (* Paragraph Separator *)
5050- | 0x202F (* Narrow No-Brpeak Space *)
5151- | 0x205F (* Medium Mathematical Space *)
5252- | 0x3000 (* Ideographic Space *) ->
5353- true
5454- | _ ->
5555- false
5656-;;
5757-5858-let is_graph_start_char char =
5959- let i = Uchar.to_int char in
6060- (*chars like these: ├─╮*)
6161- let is_pipe = i > 0x2500 && i < 0x259f in
6262- let is_whitespace = is_whitespace_char i in
6363- is_pipe || is_whitespace
6464-;;
6565-6666-let rec list_to_pairs lst =
6767- match lst with
6868- | [] | [ _ ] ->
6969- [] (* If list is empty or has only one element, return empty list *)
7070- | x :: y :: rest ->
7171- (x, y) :: list_to_pairs rest
7272-;;
7373-7474-let rec pairwise f ~f_last lst =
7575- match lst with
7676- | [ single ] ->
7777- f_last single
7878- | x :: y :: rest ->
7979- ((x, y) |> f) :: pairwise f ~f_last rest
8080- | [] ->
8181- [] (* If list is empty or has only one element, return empty list *)
8282-;;
8383-8484-(*
8585- 1. Make the graph
8686-*)
8714(** Function to tag duplicated items in a list *)
8815let tag_duplicates lst =
8916 (* Create a frequency map to count occurrences of each element *)
···10229 lst
10330;;
10431105105-(*
106106- let ansi_regex =
107107- let open Re in
108108- let csi_start = alt [ char '\x1B'; char '\x9B' ] in (* ESC or CSI *)
109109- let intermediates = rep (set "[]()#;?") in
110110- let params = rep (seq [ char ';'; rep1 (set "-a-zA-Z0-9/#&.:=?%@~_") ]) in
111111- let csi_terminator = alt [
112112- char '\x07'; (* BEL *)
113113- seq [ char '\x1B'; char '\\' ]; (* ESC \ *)
114114- char '\x9C' (* ST *)
115115- ] in
116116- let csi_sequence = seq [
117117- csi_start;
118118- intermediates;
119119- opt (alt [
120120- seq [ params; csi_terminator ];
121121- seq [ rep1 (rg 'a' 'z'); opt params; csi_terminator ]
122122- ])
123123- ] in
124124- let param_sequence = seq [
125125- rep (seq [ rg '0' '9'; rep (seq [ char ';'; rep (rg '0' '9') ]) ]);
126126- alt [
127127- set "A-PR-TZ"; (* Cursor movements and scroll regions *)
128128- set "cf-nq-uy"; (* Tab stops and erasure *)
129129- set "=><~" (* Keypad and editing modes *)
130130- ]
131131- ] in
132132- Re.compile (alt [
133133- csi_sequence;
134134- param_sequence
135135- ])
136136- let ansi_regex =
137137- let open Re in
138138- let st = alt [ str "\x07"; str "\x1B\\"; str "\x9C" ] in
139139- let pattern =
140140- alt [
141141- (* CSI escape sequence pattern *)
142142- seq [
143143- set "\x1B\x9B";
144144- rep (set "[]()#;?");
145145- opt (alt [
146146- rep (seq [ char ';'; rep1 (set "a-zA-Z0-9/#&.:=?%@~_-") ]);
147147- seq [
148148- rep1 (set "a-zA-Z0-9");
149149- rep (seq [ char ';'; rep (set "a-zA-Z0-9/#&.:=?%@~_-") ])
150150- ]
151151- ]);
152152- st;
153153- ];
154154-155155- (* OSC escape sequence pattern *)
156156- seq [
157157- opt (seq [ repn digit 1 (Some 4); rep (seq [ char ';'; repn digit 0 (Some 4) ]) ]);
158158- set "0-9A-PR-TZcf-nq-uy=><~";
159159- ]
160160- ]
161161- in
162162- Re.compile pattern *)
3232+(** Matches any basic ansi escape codes*)
16333let ansi_regex =
16434 let open Re in
16535 let pattern =
···17848 in
17949 Re.compile pattern
18050;;
181181-5151+(** Removes any found ansi escape codes*)
18252let remove_ansi str = str |> Re.replace_string ~by:"" ansi_regex
18353let count_ansi str = str |> Re.all ansi_regex |> List.length
1845418555let find_selectable_from_graph str =
5656+5757+(** Matches a single revision in the format specificied by the graph template *)
18658 let matches =
18759 str
18860 |> Re.split_full
···19062 ~flags:[ Re.Pcre.(`MULTILINE) ]
19163 {|(^.*?)\$\$--START--\$\$\|(.+?)\|(.+?)\|([\s\S]*?)\$\$--END--\$\$\n?|})
19264 in
193193- (*if there are no matches it's all filler*)
194194- (* let count = matches |> List.length in *)
19565 let graph, ids =
19666 matches
19767 |> List.fold_left
···19969 match chunk with
20070 | `Delim selectable ->
20171 let graph_bit = Re.Group.get selectable 1 in
7272+ (* In future we should be able to use the strifify function in ocaml*)
20273 let change_id = Re.Group.get selectable 2 |> remove_ansi in
20374 let commit_id = Re.Group.get selectable 3 |> remove_ansi in
20475 let content = Re.Group.get selectable 4 in
20576 ( `Selectable (graph_bit ^ content) :: graph_acc
20677 , { change_id; commit_id } :: ids_acc )
207207- | `Text filler ->
7878+ | `Text filler -> (*Anything between our match is non-selectable filler*)
20879 if filler = ""
20980 then
21081 graph_acc, ids_acc
···21687 graph, revs
21788;;
21889219219-(** retrieve revs from jj log of jj_tui*)
220220-let revs_from_log log =
221221- log
222222- |> String.split_on_char '\n'
223223- |> List.filter_map (fun x ->
224224- let items = x |> String.split_on_char '|' in
225225- match items with
226226- | [ _graph; change_id; commit_id ] ->
227227- Some { change_id; commit_id }
228228- | _ ->
229229- None)
230230- |> tag_duplicates
231231- |> Array.of_list
232232-;;
233233-23490module Make (Process : sig
23591 val jj_no_log :
23692 ?get_stderr:bool
···24197 end) =
24298struct
24399 open Process
244244-100100+(* Currently hard-coded. Soon it'l be settable in config *)
245101 let base_graph_template =
246102 {|if(root,
247103 format_root_commit(self),
···259115 )
260116)|}
261117 ;;
262262-263263- let graph_info_template =
118118+119119+ let graph_info_template node_template=
264120 {|"$$--START--$$"++"|"++change_id++"|"++commit_id++"|"++|}
265265- ^ base_graph_template
121121+ ^ node_template
266122 ^ {|++"$$--END--$$"++""|}
267123 ;;
268124269269- let get_graph_info revset_arg =
270270- let output = jj_no_log ([ "log"; "-T"; graph_info_template ] @ revset_arg) in
125125+ let get_graph_info node_template revset_arg =
126126+ let output = jj_no_log ([ "log"; "-T"; graph_info_template node_template] @ revset_arg) in
271127 output |> find_selectable_from_graph
272128 ;;
273129274274- (**Returns a list of revs with both the change_id and commit_id*)
275275- let get_revs ?revset () =
276276- let revset_arg = match revset with Some revset -> [ "-r"; revset ] | None -> [] in
277277- jj_no_log
278278- ~color:false
279279- ([ "log"; "-T"; {|"|"++change_id++"|"++commit_id++"\n"|} ] @ revset_arg)
280280- |> revs_from_log
281281- ;;
282282-283283- (* let test= *)
284284- (* let count,graph=find_selectable_from_graph root_test *)
285285- (* in *)
286286- (* if count<=0 then failwith "no process root" *)
287287- (* ;; *)
288288- let graph_view_template = {|""|}
289289-290130 (** returns the graph and a list of revs within that graph*)
291131 let graph_and_revs ?revset () =
292132 (*We join_after here to ensure any errors in sub-fibers only propegate to here, otherwise fibers everywhere would get cancelled when an error here occurs*)
···294134 let graph =
295135 Flock.fork_as_promise @@ fun () ->
296136 let revset_arg = match revset with Some revset -> [ "-r"; revset ] | None -> [] in
297297- get_graph_info revset_arg
137137+ get_graph_info base_graph_template revset_arg
298138 in
299139 let graph, revs = Promise.await graph in
300300- (*The graph should never have selectable items that don't also have a rev*)
301301- (* if not (Array.length graph = List.length revs) then
302302- failwith @@ Printf.sprintf "graph and revs length mismatch %d %d" (Array.length graph) (List.length revs)
303303- else *)
304140 graph, revs |> Array.of_list
305141 ;;
306142end
307143308144(*========Tests======*)
309145310310-let test_data =
311311- {|◉ yzquvpvl eli.jambu@gmail.com 2024-05-23 15:04:24 3565237c
312312-├─╮ merger
313313-◉ │ wttqrrwo eli.jambu@gmail.com 2024-05-23 14:36:43 ui-update* 7e46fdef
314314-│ │ border_box working
315315-│ │ ◉ skwqmzmt eli.jambu@gmail.com 2024-05-25 01:07:57 7e358c79
316316-│ ├─╯ test old size scaling
317317-│ ◉ nuptyuws eli.jambu@gmail.com 2024-05-22 18:58:31 master 7b156964
318318-│ │ Update README.md
319319-│ ◌ (elided revisions)
320320-│ │ ◉ kmslutyl eli.jambu@gmail.com 2024-05-22 18:07:36 7b10ea4f conflict
321321-│ │ │ (no description set)
322322-│ │ ◉ nqyzyups eli.jambu@gmail.com 2024-05-22 18:07:36 519c664f conflict
323323-│ ├─╯ progress
324324-│ ◉ tutrxvzs eli.jambu@gmail.com 2024-05-22 18:07:36 af8620df
325325-│ │ flakes working
326326-│ ◌ (elided revisions)
327327-│ │ ◉ vlkxvssz eli.jambu@gmail.com 2024-05-15 19:40:28 79fb16f1
328328-│ ├─╯ (no description set)
329329-│ ◉ vtkpsqlr eli.jambu@gmail.com 2024-05-15 16:44:09 1974cc7d
330330-│ │ switch to pkgsStatic
331331-│ ◌ (elided revisions)
332332-│ │ ◉ zpvnoqkm eli.jambu@gmail.com 2024-05-15 09:47:41 c9f95816
333333-├───╯ (no description set)
334334-◉ │ unspmqrw eli.jambu@gmail.com 2024-05-15 09:47:41 83aafe3c
335335-├─╯ update to nottui
336336-│ ◉ smvuxtrv eli.jambu@gmail.com 2024-05-15 09:47:41 d0ce4665
337337-├─╯ (empty) bup
338338-◉ yqytskyk eli.jambu@gmail.com 2024-05-15 09:47:41 0a89ce77
339339-│ test reorganise
340340-◌ (elided revisions)
341341-│ ◉ qpqzkuss eli.jambu@gmail.com 2024-05-15 09:46:18 fdd16b26 conflict
342342-│ │ (no description set)
343343-│ ◉ xpqmtrmp eli.jambu@gmail.com 2024-05-15 09:46:18 555a5355
344344-├─╯ remove old nix file
345345-◉ zxpskuop eli.jambu@gmail.com 2024-05-15 09:46:18 dac0f8bb
346346-│ Update README.md|}
347347-;;
348348-349349-let root_test = {|◆ zzzzzzzz root() 00000000|}
350350-351351-let test_data_2 =
352352- {|@ qpnrvwyl ethanboxx 13 seconds ago 48829167
353353-│ (no description set)
354354-◆ pqvkrmkw ethanboxx 3 months ago main v0.1.10 HEAD@git 931019c4
355355-│ (empty) Merge pull request #63 from eopb/release-plz-2024-05-11T09-14-47Z
356356-~ (elided revisions)
357357-│ ○ xnyvmlur ethanboxx 5 months ago push-znvwmrtqnnlq 0deaa0aa
358358-├─┘ feat: impl `Deref` and `DerefMut` without exposing `Secret`
359359-◆ kkzuqwxo ethanboxx 5 months ago 9aa340cc
360360-│ (empty) Merge pull request #56 from eopb/push-smksztlxprww
361361-~|}
362362-;;
363146364147let test_data_3 =
365148 {|@ $$--START--$$|zqtxnkuuryqzzolyksrylpzotmplmvus|8ee443e4a374f7dfdd00494d8bf71af6162a1300|zqtxnkuu eli.jambu@gmail.com 2025-02-15 21:22:48 8ee443e4
+27
jj_tui/lib/util.ml
···4646 strings |> List.filter (Base.String.is_empty >> not) |> String.concat sep
4747 ;;
4848end
4949+(** convinience method to take a str and turn it into a unicode char*)
5050+let make_uchar str =
5151+ let a = String.get_utf_8_uchar str 0 in
5252+ if a |> Uchar.utf_decode_is_valid
5353+ then a |> Uchar.utf_decode_uchar
5454+ else failwith "not a unicode string"
5555+;;
5656+5757+(** Takes a list and pair all elements we can*)
5858+let rec list_to_pairs lst =
5959+ match lst with
6060+ | [] | [ _ ] ->
6161+ [] (* If list is empty or has only one element, return empty list *)
6262+ | x :: y :: rest ->
6363+ (x, y) :: list_to_pairs rest
6464+;;
6565+(** Iterate over a list in pairs. f_last handles if there is a last elemment that doesn't have a pair*)
6666+let rec pairwise f ~f_last lst =
6767+ match lst with
6868+ | [ single ] ->
6969+ f_last single
7070+ | x :: y :: rest ->
7171+ ((x, y) |> f) :: pairwise f ~f_last rest
7272+ | [] ->
7373+ [] (* If list is empty or has only one element, return empty list *)
7474+;;
7575+