terminal user interface to jujutsu. Focused on speed and clarity
9
fork

Configure Feed

Select the types of activity you want to include in your feed.

Fix parsing issues preventing delta from working:

This also fixed an issue where images required newlines
if they went through the ansi escape parser so i removed some
no longer needed newlines.

the issue was mostly caused by not being able to handle non graphical escape codes.

+531 -441
+1 -1
jj_tui/bin/graph_view.ml
··· 85 85 | `Selectable x -> 86 86 let ui = 87 87 W.Lists.selectable_item 88 - (x ^ "\n" 88 + (x 89 89 (* TODO This won't work if we are on a branch, because that puts the @ further out*) 90 90 |> Jj_tui.AnsiReverse.colored_string 91 91 |> Ui.atom)
+2 -2
jj_tui/bin/jj_widgets.ml
··· 37 37 data = name 38 38 ; id = name |> String.hash 39 39 ; ui = 40 - str ^ "\n" 40 + str 41 41 |> Jj_tui.AnsiReverse.colored_string 42 42 |> Ui.atom 43 43 |> Ui.resize ~w:100 ~h:1 ~mw:100 ··· 95 95 data = name 96 96 ; id = name |> String.hash 97 97 ; ui = 98 - str ^ "\n" 98 + str 99 99 |> Jj_tui.AnsiReverse.colored_string 100 100 |> Ui.atom 101 101 |> Ui.resize ~w:100 ~h:1 ~mw:100
+1 -1
jj_tui/bin/show_view.ml
··· 72 72 Control.yield (); 73 73 res 74 74 | Graph_preview rev -> 75 - let log = jj_no_log ~snapshot:false [ "diff"; "--color-words"; "-r"; rev ] in 75 + let log = jj_no_log ~snapshot:false [ "diff"; "-r"; rev ] in 76 76 Control.yield (); 77 77 let res = log |> AnsiReverse.colored_string in 78 78 Control.yield ();
+190 -337
jj_tui/lib/ansiReverse.ml
··· 27 27 ;; 28 28 29 29 (** Prints the attribute in a human readable format. 30 - Also replaces the escape character with \e. 30 + Also replaces the escape character with \e. 31 31 This means the output can be copy pasted into a terminal to test. 32 32 like: `echo -e "attr: \e[0;31mTEXT\e[0m"` *) 33 33 let print_attr img = ··· 64 64 (* let color_code = digits >>| int_of_string in *) 65 65 let param = digits <* option ' ' (char ';') in 66 66 let params = many (param >>| int_of_string) in 67 - let escape_sequence = char '\027' *> char '[' *> params <* char 'm' in 68 - let full_seq=many1 escape_sequence in 69 - let attr_of_params = function 70 - | [] -> 71 - Apply empty 72 - | 0 :: _ -> 73 - FullyReset 74 - | 1 :: _ -> 75 - Apply (st bold) 76 - | 2 :: _ -> 77 - Apply (st dim) 78 - | 3 :: _ -> 79 - Apply (st italic) 80 - | 4 :: _ -> 81 - Apply (st underline) 82 - | 5 :: _ -> 83 - Apply (st blink) 84 - | 7 :: _ -> 85 - Apply (st reverse) 86 - | 8 :: _ -> 87 - Apply (st hidden) 88 - | 9 :: _ -> 89 - Apply (st strike) 90 - | 21 :: _ -> 91 - Reset (st bold) (* Double underline or bold off *) 92 - | 22 :: _ -> 93 - Reset (st bold ++ st dim) (* Normal intensity - reset bold and dim *) 94 - | 23 :: _ -> 95 - Reset (st italic) (* Reset italic *) 96 - | 24 :: _ -> 97 - Reset (st underline) (* Reset underline *) 98 - | 25 :: _ -> 99 - Reset (st blink) (* Reset blink *) 100 - | 27 :: _ -> 101 - Reset (st reverse) (* Reset reverse *) 102 - | 28 :: _ -> 103 - Reset (st hidden) (* Reset hidden *) 104 - | 29 :: _ -> 105 - Reset (st strike) (* Reset strikethrough *) 106 - | 30 :: _ -> 107 - Apply (fg black) 108 - | 31 :: _ -> 109 - Apply (fg red) 110 - | 32 :: _ -> 111 - Apply (fg green) 112 - | 33 :: _ -> 113 - Apply (fg yellow) 114 - | 34 :: _ -> 115 - Apply (fg blue) 116 - | 35 :: _ -> 117 - Apply (fg magenta) 118 - | 36 :: _ -> 119 - Apply (fg cyan) 120 - | 37 :: _ -> 121 - Apply (fg white) 122 - | 38 :: 5 :: color :: _ -> 123 - Apply (fg (unsafe_color_of_int (0x01000000 lor color))) 124 - | 38 :: 2 :: r :: g :: b :: _ -> 125 - Apply (fg (rgb_888 ~r ~g ~b)) 126 - | 39 :: _ -> 127 - Reset (fg color_reset) (* Default foreground color *) 128 - | 40 :: _ -> 129 - Apply (bg black) 130 - | 41 :: _ -> 131 - Apply (bg red) 132 - | 42 :: _ -> 133 - Apply (bg green) 134 - | 43 :: _ -> 135 - Apply (bg yellow) 136 - | 44 :: _ -> 137 - Apply (bg blue) 138 - | 45 :: _ -> 139 - Apply (bg magenta) 140 - | 46 :: _ -> 141 - Apply (bg cyan) 142 - | 47 :: _ -> 143 - Apply (bg white) 144 - | 48 :: 5 :: color :: _ -> 145 - Apply (bg (unsafe_color_of_int (0x01000000 lor color))) 146 - | 48 :: 2 :: r :: g :: b :: _ -> 147 - Apply (bg (rgb_888 ~r ~g ~b)) 148 - | 49 :: _ -> 149 - Reset (bg color_reset) (* Default background color *) 150 - | 90 :: _ -> 151 - Apply (fg lightblack) (* Bright black (gray) *) 152 - | 91 :: _ -> 153 - Apply (fg lightred) 154 - | 92 :: _ -> 155 - Apply (fg lightgreen) 156 - | 93 :: _ -> 157 - Apply (fg lightyellow) 158 - | 94 :: _ -> 159 - Apply (fg lightblue) 160 - | 95 :: _ -> 161 - Apply (fg lightmagenta) 162 - | 96 :: _ -> 163 - Apply (fg lightcyan) 164 - | 97 :: _ -> 165 - Apply (fg lightwhite) 166 - | 100 :: _ -> 167 - Apply (bg lightblack) 168 - | 101 :: _ -> 169 - Apply (bg lightred) 170 - | 102 :: _ -> 171 - Apply (bg lightgreen) 172 - | 103 :: _ -> 173 - Apply (bg lightyellow) 174 - | 104 :: _ -> 175 - Apply (bg lightblue) 176 - | 105 :: _ -> 177 - Apply (bg lightmagenta) 178 - | 106 :: _ -> 179 - Apply (bg lightcyan) 180 - | 107 :: _ -> 181 - Apply (bg lightwhite) 182 - | _ -> 183 - Apply empty 67 + (* SGR (Select Graphic Rendition) sequence: ESC [ params m *) 68 + let sgr_sequence = 69 + char '\027' *> char '[' *> params <* char 'm' >>| fun ps -> `Sgr ps 70 + in 71 + (* Generic CSI sequence to consume and ignore non-SGR controls like K, J, etc. 72 + Grammar (simplified): ESC [ <params/intermediates> <final> 73 + where final is any byte in 0x40..0x7E *) 74 + let is_final c = 75 + let code = Char.code c in 76 + code >= 0x40 && code <= 0x7E 184 77 in 185 - full_seq>>| List.map attr_of_params 78 + let non_sgr_csi = 79 + char '\027' 80 + *> char '[' 81 + *> take_while (fun c -> not (is_final c)) 82 + *> satisfy is_final 83 + *> return `Skip 84 + in 85 + let escape_any = choice [ sgr_sequence; non_sgr_csi ] in 86 + let full_seq = many1 escape_any in 87 + let attr_actions_of_params params = 88 + let rec loop acc = function 89 + | [] -> 90 + List.rev acc 91 + | 0 :: rest -> 92 + loop (FullyReset :: acc) rest 93 + | 1 :: rest -> 94 + loop (Apply (st bold) :: acc) rest 95 + | 2 :: rest -> 96 + loop (Apply (st dim) :: acc) rest 97 + | 3 :: rest -> 98 + loop (Apply (st italic) :: acc) rest 99 + | 4 :: rest -> 100 + loop (Apply (st underline) :: acc) rest 101 + | 5 :: rest -> 102 + loop (Apply (st blink) :: acc) rest 103 + | 7 :: rest -> 104 + loop (Apply (st reverse) :: acc) rest 105 + | 8 :: rest -> 106 + loop (Apply (st hidden) :: acc) rest 107 + | 9 :: rest -> 108 + loop (Apply (st strike) :: acc) rest 109 + | 21 :: rest -> 110 + loop (Reset (st bold) :: acc) rest 111 + | 22 :: rest -> 112 + loop (Reset (st bold ++ st dim) :: acc) rest 113 + | 23 :: rest -> 114 + loop (Reset (st italic) :: acc) rest 115 + | 24 :: rest -> 116 + loop (Reset (st underline) :: acc) rest 117 + | 25 :: rest -> 118 + loop (Reset (st blink) :: acc) rest 119 + | 27 :: rest -> 120 + loop (Reset (st reverse) :: acc) rest 121 + | 28 :: rest -> 122 + loop (Reset (st hidden) :: acc) rest 123 + | 29 :: rest -> 124 + loop (Reset (st strike) :: acc) rest 125 + | 30 :: rest -> 126 + loop (Apply (fg black) :: acc) rest 127 + | 31 :: rest -> 128 + loop (Apply (fg red) :: acc) rest 129 + | 32 :: rest -> 130 + loop (Apply (fg green) :: acc) rest 131 + | 33 :: rest -> 132 + loop (Apply (fg yellow) :: acc) rest 133 + | 34 :: rest -> 134 + loop (Apply (fg blue) :: acc) rest 135 + | 35 :: rest -> 136 + loop (Apply (fg magenta) :: acc) rest 137 + | 36 :: rest -> 138 + loop (Apply (fg cyan) :: acc) rest 139 + | 37 :: rest -> 140 + loop (Apply (fg white) :: acc) rest 141 + | 38 :: 5 :: color :: rest -> 142 + loop (Apply (fg (unsafe_color_of_int (0x01000000 lor color))) :: acc) rest 143 + | 38 :: 2 :: r :: g :: b :: rest -> 144 + loop (Apply (fg (rgb_888 ~r ~g ~b)) :: acc) rest 145 + | 39 :: rest -> 146 + loop (Reset (fg color_reset) :: acc) rest 147 + | 40 :: rest -> 148 + loop (Apply (bg black) :: acc) rest 149 + | 41 :: rest -> 150 + loop (Apply (bg red) :: acc) rest 151 + | 42 :: rest -> 152 + loop (Apply (bg green) :: acc) rest 153 + | 43 :: rest -> 154 + loop (Apply (bg yellow) :: acc) rest 155 + | 44 :: rest -> 156 + loop (Apply (bg blue) :: acc) rest 157 + | 45 :: rest -> 158 + loop (Apply (bg magenta) :: acc) rest 159 + | 46 :: rest -> 160 + loop (Apply (bg cyan) :: acc) rest 161 + | 47 :: rest -> 162 + loop (Apply (bg white) :: acc) rest 163 + | 48 :: 5 :: color :: rest -> 164 + loop (Apply (bg (unsafe_color_of_int (0x01000000 lor color))) :: acc) rest 165 + | 48 :: 2 :: r :: g :: b :: rest -> 166 + loop (Apply (bg (rgb_888 ~r ~g ~b)) :: acc) rest 167 + | 49 :: rest -> 168 + loop (Reset (bg color_reset) :: acc) rest 169 + | 90 :: rest -> 170 + loop (Apply (fg lightblack) :: acc) rest 171 + | 91 :: rest -> 172 + loop (Apply (fg lightred) :: acc) rest 173 + | 92 :: rest -> 174 + loop (Apply (fg lightgreen) :: acc) rest 175 + | 93 :: rest -> 176 + loop (Apply (fg lightyellow) :: acc) rest 177 + | 94 :: rest -> 178 + loop (Apply (fg lightblue) :: acc) rest 179 + | 95 :: rest -> 180 + loop (Apply (fg lightmagenta) :: acc) rest 181 + | 96 :: rest -> 182 + loop (Apply (fg lightcyan) :: acc) rest 183 + | 97 :: rest -> 184 + loop (Apply (fg lightwhite) :: acc) rest 185 + | 100 :: rest -> 186 + loop (Apply (bg lightblack) :: acc) rest 187 + | 101 :: rest -> 188 + loop (Apply (bg lightred) :: acc) rest 189 + | 102 :: rest -> 190 + loop (Apply (bg lightgreen) :: acc) rest 191 + | 103 :: rest -> 192 + loop (Apply (bg lightyellow) :: acc) rest 193 + | 104 :: rest -> 194 + loop (Apply (bg lightblue) :: acc) rest 195 + | 105 :: rest -> 196 + loop (Apply (bg lightmagenta) :: acc) rest 197 + | 106 :: rest -> 198 + loop (Apply (bg lightcyan) :: acc) rest 199 + | 107 :: rest -> 200 + loop (Apply (bg lightwhite) :: acc) rest 201 + | _ :: rest -> 202 + (* Unknown or unsupported parameter; skip it to avoid stalling *) 203 + loop acc rest 204 + in 205 + loop [] params 206 + in 207 + full_seq >>| fun seqs -> 208 + seqs 209 + |> List.concat_map (function `Sgr ps -> attr_actions_of_params ps | `Skip -> []) 186 210 ;; 187 211 188 - let%expect_test "escape_parser" = 189 - let test_str = "\027[32m" in 190 - let res = 191 - Angstrom.parse_string ~consume:All parse_escape_seq test_str |> Result.get_ok 192 - in 193 - res|>List.iter(fun res-> 194 - (match res with 195 - | Apply attr -> 196 - print_attr attr 197 - | Reset _ -> 198 - print_endline "Reset attribute" 199 - | FullyReset -> 200 - print_endline "Fully reset attribute"); 201 - ); 202 - [%expect 203 - {| 204 - attr: 205 - \e[0m<\e[0;32mATTR\e[0m\e[K\e[0m>\e[0m 206 - |}] 207 - ;; 208 - let%expect_test "escape_parser_2" = 209 - let test_str = "\027[32m" in 210 - let res = 211 - Angstrom.parse_string ~consume:All parse_escape_seq test_str |> Result.get_ok 212 - in 213 - res|>List.iter(fun res-> 214 - (match res with 215 - | Apply attr -> 216 - print_attr attr 217 - | Reset _ -> 218 - print_endline "Reset attribute" 219 - | FullyReset -> 220 - print_endline "Fully reset attribute"); 221 - ); 222 - [%expect 223 - {| 224 - attr: 225 - \e[0m<\e[0;32mATTR\e[0m\e[K\e[0m>\e[0m 226 - |}] 212 + let print_escape_seq seq = 213 + print_endline "escape sequence:"; 214 + seq 215 + |> List.iter (fun action -> 216 + match action with 217 + | Apply attr -> 218 + print_attr attr 219 + | Reset attr -> 220 + print_endline "Reset attribute"; 221 + print_attr attr 222 + | FullyReset -> 223 + print_endline "Fully reset attribute") 227 224 ;; 228 225 229 226 let parse_ansi_escape_codes (input : string) = ··· 234 231 let pair = 235 232 attr >>= fun actions -> 236 233 substring >>= fun s -> 237 - actions|>List.iter(fun action-> 238 - match action with 239 - | Apply a -> 240 - attr_state := A.( ++ ) !attr_state a 241 - | Reset a -> 242 - attr_state := A.( -- ) !attr_state a 243 - | FullyReset -> 244 - attr_state := A.empty); 234 + actions 235 + |> List.iter (fun action -> 236 + match action with 237 + | Apply a -> 238 + attr_state := A.( ++ ) !attr_state a 239 + | Reset a -> 240 + attr_state := A.( -- ) !attr_state a 241 + | FullyReset -> 242 + attr_state := A.empty); 245 243 return (!attr_state, s) 246 244 in 247 245 (* if we don't start on an escape we can match one here*) ··· 253 251 in 254 252 parse_string ~consume:Prefix pairs input 255 253 ;; 256 - 257 - let%expect_test "parse_ansi_escape_codes_test" = 258 - let test_str = "\027[4m\027[38;5;1m\"success\"\027[38;5;2mNone\027[24m\027[39mrest" in 259 - (match parse_ansi_escape_codes test_str with 260 - | Error err -> 261 - Printf.printf "Error: %s\n" err 262 - | Ok result -> 263 - Printf.printf "Parsed %d segments:\n" (List.length result); 264 - List.iter 265 - (fun (attr, text) -> 266 - print_attr attr; 267 - Printf.printf "Text: \"%s\"\n" (String.escaped text)) 268 - result); 269 - [%expect 270 - {| 271 - Parsed 6 segments: 272 - attr: 273 - \e[0m<\e[0mATTR\e[0m\e[K\e[0m>\e[0m 274 - Text: "" 275 - attr: 276 - \e[0m<\e[0;4mATTR\e[0m\e[K\e[0m>\e[0m 277 - Text: "" 278 - attr: 279 - \e[0m<\e[0;31;4mATTR\e[0m\e[K\e[0m>\e[0m 280 - Text: "\"success\"" 281 - attr: 282 - \e[0m<\e[0;32;4mATTR\e[0m\e[K\e[0m>\e[0m 283 - Text: "None" 284 - attr: 285 - \e[0m<\e[0mATTR\e[0m\e[K\e[0m>\e[0m 286 - Text: "" 287 - attr: 288 - \e[0m<\e[0mATTR\e[0m\e[K\e[0m>\e[0m 289 - Text: "rest" 290 - |}] 291 - ;; 292 - 293 - let%expect_test "parse_ansi_strikethrough_test" = 294 - let open A in 295 - print_attr (A.st A.strike); 296 - print_attr (A.st A.strike ++ A.fg A.red); 297 - print_attr (A.st A.blink); 298 - print_attr (A.st A.dim); 299 - print_attr (A.st A.italic); 300 - print_attr (A.st A.underline); 301 - print_attr (A.st A.bold); 302 - print_attr (A.st A.reverse ++ A.fg A.red); 303 - print_attr (A.st A.hidden); 304 - [%expect 305 - {| 306 - attr: 307 - \e[0m<\e[0;9mATTR\e[0m\e[K\e[0m>\e[0m 308 - attr: 309 - \e[0m<\e[0;31;9mATTR\e[0m\e[K\e[0m>\e[0m 310 - attr: 311 - \e[0m<\e[0;5mATTR\e[0m\e[K\e[0m>\e[0m 312 - attr: 313 - \e[0m<\e[0;2mATTR\e[0m\e[K\e[0m>\e[0m 314 - attr: 315 - \e[0m<\e[0;3mATTR\e[0m\e[K\e[0m>\e[0m 316 - attr: 317 - \e[0m<\e[0;4mATTR\e[0m\e[K\e[0m>\e[0m 318 - attr: 319 - \e[0m<\e[0;1mATTR\e[0m\e[K\e[0m>\e[0m 320 - attr: 321 - \e[0m<\e[0;31;7mATTR\e[0m\e[K\e[0m>\e[0m 322 - attr: 323 - \e[0m<\e[0;8mATTR\e[0m\e[K\e[0m>\e[0m 324 - |}] 325 - ;; 326 - 327 - let%expect_test "attribute_removal_test" = 328 - let open A in 329 - (* Test removing styles *) 330 - let base_attr = st bold ++ st underline ++ st italic in 331 - let result = base_attr -- st italic in 332 - Internal.print_attr result; 333 - [%expect 334 - {| 335 - attr: 336 - \e[0m<\e[0;1;4mATTR\e[0m\e[K\e[0m>\e[0m 337 - |}]; 338 - (* Test removing multiple styles at once *) 339 - let result2 = base_attr -- (st underline ++ st italic) in 340 - Internal.print_attr result2; 341 - [%expect 342 - {| 343 - attr: 344 - \e[0m<\e[0;1mATTR\e[0m\e[K\e[0m>\e[0m 345 - |}]; 346 - (* Test removing foreground color *) 347 - let colored = base_attr ++ fg red in 348 - let color_reset = colored -- fg color_reset in 349 - Internal.print_attr color_reset; 350 - [%expect 351 - {| 352 - attr: 353 - \e[0m<\e[0;1;3;4mATTR\e[0m\e[K\e[0m>\e[0m 354 - |}]; 355 - (* Test removing a style from colored *) 356 - let no_underline = colored -- st underline in 357 - Internal.print_attr no_underline; 358 - [%expect 359 - {| 360 - attr: 361 - \e[0m<\e[0;1;3mATTR\e[0m\e[K\e[0m>\e[0m 362 - |}]; 363 - (* Test removing background color *) 364 - let bg_colored = base_attr ++ bg blue in 365 - let no_bg = bg_colored -- bg blue in 366 - Internal.print_attr no_bg; 367 - [%expect 368 - {| 369 - attr: 370 - \e[0m<\e[0;1;3;4mATTR\e[0m\e[K\e[0m>\e[0m 371 - |}]; 372 - (* Test resetting to empty *) 373 - let full_attr = st bold ++ fg red ++ bg green in 374 - let empty_result = full_attr -- full_attr in 375 - Internal.print_attr empty_result; 376 - [%expect 377 - {| 378 - attr: 379 - \e[0m<\e[0mATTR\e[0m\e[K\e[0m>\e[0m 380 - |}] 381 - ;; 382 - 383 - let%expect_test "edge_case_1" = 384 - let test_str = 385 - {| 145: onescript10|} 386 - in 387 - (match parse_ansi_escape_codes test_str with 388 - | Error err -> 389 - Printf.printf "Error: %s\n" err 390 - | Ok result -> 391 - Printf.printf "Parsed %d segments:\n" (List.length result); 392 - List.iter 393 - (fun (attr, text) -> 394 - print_attr attr; 395 - Printf.printf "Text: %s" (String.escaped text)) 396 - result); 397 - [%expect 398 - {| 399 - Parsed 7 segments: 400 - attr: 401 - \e[0m<\e[0mATTR\e[0m\e[K\e[0m>\e[0m 402 - Text: attr: 403 - \e[0m<\e[0;32mATTR\e[0m\e[K\e[0m>\e[0m 404 - Text: 145attr: 405 - \e[0m<\e[0mATTR\e[0m\e[K\e[0m>\e[0m 406 - Text: : attr: 407 - \e[0m<\e[0;4mATTR\e[0m\e[K\e[0m>\e[0m 408 - Text: attr: 409 - \e[0m<\e[0;32;4mATTR\e[0m\e[K\e[0m>\e[0m 410 - Text: oneattr: 411 - \e[0m<\e[0mATTR\e[0m\e[K\e[0m>\e[0m 412 - Text: scriptattr: 413 - \e[0m<\e[0;4mATTR\e[0m\e[K\e[0m>\e[0m 414 - Text: 10 415 - |}] 416 - ;; 417 254 end 418 255 419 256 (** Converts a string with ansi escape codes to a notty image. ··· 443 280 str; 444 281 Buffer.contents buffer 445 282 in 283 + (* print_endline ("pre parse str: " ^ str); *) 446 284 match Parser.parse_ansi_escape_codes str with 447 285 | Error a -> 448 286 Printf.printf "restut: %s" a; ··· 453 291 |> List.concat_map (fun (attr, str) -> 454 292 str 455 293 |> String.split_on_char '\n' 456 - |> List.map (fun x -> `Image (I.string A.(attr ++ extra_attr) x)) 294 + |> List.map (fun x -> 295 + let attrs = A.(attr ++ extra_attr) in 296 + let img = I.string attrs x in 297 + (* Internal.print_attr attrs; 298 + print_endline (("str: " ^ x)|> String.escaped); 299 + Internal.print_image_escaped img; *) 300 + `Image img) 457 301 |> Base.List.intersperse ~sep:`Newline) 458 302 in 459 303 let newline_seperated = locate_newlines coded_strs in 460 304 let lines = 461 305 let open I in 462 - newline_seperated 463 - |> Base.List.fold ~init:([], I.empty) ~f:(fun (images, image) x -> 464 - match x with 465 - | `Newline -> 466 - image :: images, I.empty 467 - | `Image nextImage -> 468 - images, image <|> nextImage) 469 - |> fst 470 - |> Base.List.reduce ~f:(fun bottom top -> top <-> bottom) 306 + let images, last_image = 307 + newline_seperated 308 + |> Base.List.fold ~init:([], I.empty) ~f:(fun (images, image) x -> 309 + match x with 310 + | `Newline -> 311 + image :: images, I.empty 312 + | `Image nextImage -> 313 + (* print_endline "nextImage:"; 314 + Internal.print_image_escaped nextImage; *) 315 + images, image <|> nextImage) 316 + in 317 + last_image :: images 318 + |> Base.List.reduce ~f:(fun bottom top -> 319 + (* print_endline "bottom:"; 320 + Internal.print_image_escaped bottom; 321 + print_endline "top:"; 322 + Internal.print_image_escaped top; *) 323 + top <-> bottom) 471 324 |> Option.value ~default:I.empty 472 325 in 473 326 Ok lines
+298
jj_tui/lib/ansiReverseTests.ml
··· 1 + (******* 2 + parser tests 3 + *******) 4 + open Notty 5 + open AnsiReverse 6 + 7 + module ParserTests = struct 8 + open AnsiReverse.Parser 9 + open AnsiReverse.Internal 10 + 11 + let%expect_test "escape_parser" = 12 + let test_str = "\027[32m" in 13 + let res = 14 + Angstrom.parse_string ~consume:All parse_escape_seq test_str |> Result.get_ok 15 + in 16 + print_escape_seq res; 17 + [%expect 18 + {| 19 + escape sequence: 20 + attr: 21 + \e[0m<\e[0;32mATTR\e[0m\e[K\e[0m>\e[0m 22 + |}] 23 + ;; 24 + 25 + let%expect_test "parse_ansi_escape_codes_test" = 26 + let test_str = "\027[4m\027[38;5;1m\"success\"\027[38;5;2mNone\027[24m\027[39mrest" in 27 + (match parse_ansi_escape_codes test_str with 28 + | Error err -> 29 + Printf.printf "Error: %s\n" err 30 + | Ok result -> 31 + Printf.printf "Parsed %d segments:\n" (List.length result); 32 + List.iter 33 + (fun (attr, text) -> 34 + print_attr attr; 35 + Printf.printf "Text: \"%s\"\n" (String.escaped text)) 36 + result); 37 + [%expect 38 + {| 39 + Parsed 4 segments: 40 + attr: 41 + \e[0m<\e[0mATTR\e[0m\e[K\e[0m>\e[0m 42 + Text: "" 43 + attr: 44 + \e[0m<\e[0;31;4mATTR\e[0m\e[K\e[0m>\e[0m 45 + Text: "\"success\"" 46 + attr: 47 + \e[0m<\e[0;32;4mATTR\e[0m\e[K\e[0m>\e[0m 48 + Text: "None" 49 + attr: 50 + \e[0m<\e[0mATTR\e[0m\e[K\e[0m>\e[0m 51 + Text: "rest" 52 + |}] 53 + ;; 54 + 55 + let%expect_test "parse_ansi_strikethrough_test" = 56 + let open A in 57 + print_attr (A.st A.strike); 58 + print_attr (A.st A.strike ++ A.fg A.red); 59 + print_attr (A.st A.blink); 60 + print_attr (A.st A.dim); 61 + print_attr (A.st A.italic); 62 + print_attr (A.st A.underline); 63 + print_attr (A.st A.bold); 64 + print_attr (A.st A.reverse ++ A.fg A.red); 65 + print_attr (A.st A.hidden); 66 + [%expect 67 + {| 68 + attr: 69 + \e[0m<\e[0;9mATTR\e[0m\e[K\e[0m>\e[0m 70 + attr: 71 + \e[0m<\e[0;31;9mATTR\e[0m\e[K\e[0m>\e[0m 72 + attr: 73 + \e[0m<\e[0;5mATTR\e[0m\e[K\e[0m>\e[0m 74 + attr: 75 + \e[0m<\e[0;2mATTR\e[0m\e[K\e[0m>\e[0m 76 + attr: 77 + \e[0m<\e[0;3mATTR\e[0m\e[K\e[0m>\e[0m 78 + attr: 79 + \e[0m<\e[0;4mATTR\e[0m\e[K\e[0m>\e[0m 80 + attr: 81 + \e[0m<\e[0;1mATTR\e[0m\e[K\e[0m>\e[0m 82 + attr: 83 + \e[0m<\e[0;31;7mATTR\e[0m\e[K\e[0m>\e[0m 84 + attr: 85 + \e[0m<\e[0;8mATTR\e[0m\e[K\e[0m>\e[0m 86 + |}] 87 + ;; 88 + 89 + let%expect_test "attribute_removal_test" = 90 + let open A in 91 + (* Test removing styles *) 92 + let base_attr = st bold ++ st underline ++ st italic in 93 + let result = base_attr -- st italic in 94 + Internal.print_attr result; 95 + [%expect 96 + {| 97 + attr: 98 + \e[0m<\e[0;1;4mATTR\e[0m\e[K\e[0m>\e[0m 99 + |}]; 100 + (* Test removing multiple styles at once *) 101 + let result2 = base_attr -- (st underline ++ st italic) in 102 + Internal.print_attr result2; 103 + [%expect 104 + {| 105 + attr: 106 + \e[0m<\e[0;1mATTR\e[0m\e[K\e[0m>\e[0m 107 + |}]; 108 + (* Test removing foreground color *) 109 + let colored = base_attr ++ fg red in 110 + let color_reset = colored -- fg color_reset in 111 + Internal.print_attr color_reset; 112 + [%expect 113 + {| 114 + attr: 115 + \e[0m<\e[0;1;3;4mATTR\e[0m\e[K\e[0m>\e[0m 116 + |}]; 117 + (* Test removing a style from colored *) 118 + let no_underline = colored -- st underline in 119 + Internal.print_attr no_underline; 120 + [%expect 121 + {| 122 + attr: 123 + \e[0m<\e[0;31;1;3mATTR\e[0m\e[K\e[0m>\e[0m 124 + |}]; 125 + (* Test removing background color *) 126 + let bg_colored = base_attr ++ bg blue in 127 + let no_bg = bg_colored -- bg blue in 128 + Internal.print_attr no_bg; 129 + [%expect 130 + {| 131 + attr: 132 + \e[0m<\e[0;1;3;4mATTR\e[0m\e[K\e[0m>\e[0m 133 + |}]; 134 + (* Test resetting to empty *) 135 + let full_attr = st bold ++ fg red ++ bg green in 136 + let empty_result = full_attr -- full_attr in 137 + Internal.print_attr empty_result; 138 + [%expect 139 + {| 140 + attr: 141 + \e[0m<\e[0mATTR\e[0m\e[K\e[0m>\e[0m 142 + |}] 143 + ;; 144 + 145 + let%expect_test "edge_case_1" = 146 + let test_str = {| 145: onescript10|} in 147 + (match parse_ansi_escape_codes test_str with 148 + | Error err -> 149 + Printf.printf "Error: %s\n" err 150 + | Ok result -> 151 + Printf.printf "Parsed %d segments:\n" (List.length result); 152 + List.iter 153 + (fun (attr, text) -> 154 + print_attr attr; 155 + Printf.printf "Text: %s" (String.escaped text)) 156 + result); 157 + [%expect 158 + {| 159 + Parsed 6 segments: 160 + attr: 161 + \e[0m<\e[0mATTR\e[0m\e[K\e[0m>\e[0m 162 + Text: attr: 163 + \e[0m<\e[0;32mATTR\e[0m\e[K\e[0m>\e[0m 164 + Text: 145attr: 165 + \e[0m<\e[0mATTR\e[0m\e[K\e[0m>\e[0m 166 + Text: : attr: 167 + \e[0m<\e[0;32;4mATTR\e[0m\e[K\e[0m>\e[0m 168 + Text: oneattr: 169 + \e[0m<\e[0;32mATTR\e[0m\e[K\e[0m>\e[0m 170 + Text: scriptattr: 171 + \e[0m<\e[0;32;4mATTR\e[0m\e[K\e[0m>\e[0m 172 + Text: 10 173 + |}] 174 + ;; 175 + 176 + let%expect_test "parse_delta_test" = 177 + let test_str = 178 + "\027[48;2;0;40;0;38;2;248;248;242mhi-therehi" 179 + in 180 + (match parse_ansi_escape_codes test_str with 181 + | Error err -> 182 + Printf.printf "Error: %s\n" err 183 + | Ok result -> 184 + Printf.printf "Parsed %d segments:\n" (List.length result); 185 + List.iter 186 + (fun (attr, text) -> 187 + print_attr attr; 188 + Printf.printf "Text: '%s'\n" (String.escaped text)) 189 + result); 190 + [%expect 191 + {| 192 + Parsed 3 segments: 193 + attr: 194 + \e[0m<\e[0mATTR\e[0m\e[K\e[0m>\e[0m 195 + Text: '' 196 + attr: 197 + \e[0m<\e[0;38;2;248;248;242;48;2;0;40;0mATTR\e[0m\e[K\e[0m>\e[0m 198 + Text: 'hi-there' 199 + attr: 200 + \e[0m<\e[0mATTR\e[0m\e[K\e[0m>\e[0m 201 + Text: 'hi' 202 + |}] 203 + ;; 204 + 205 + let%expect_test "parse_delta_test 2" = 206 + (*turns out this was really testing the \e[0k sequence, which would break anything after it*) 207 + let test_str = 208 + {| 209 +  (x |} 210 + in 211 + (match parse_ansi_escape_codes test_str with 212 + | Error err -> 213 + Printf.printf "Error: %s\n" err 214 + | Ok result -> 215 + Printf.printf "Parsed %d segments:\n" (List.length result); 216 + List.iter 217 + (fun (attr, text) -> 218 + print_attr attr; 219 + Printf.printf "Text: '%s'\n" (String.escaped text)) 220 + result); 221 + [%expect 222 + {| 223 + Parsed 5 segments: 224 + attr: 225 + \e[0m<\e[0mATTR\e[0m\e[K\e[0m>\e[0m 226 + Text: '' 227 + attr: 228 + \e[0m<\e[0mATTR\e[0m\e[K\e[0m>\e[0m 229 + Text: '\n' 230 + attr: 231 + \e[0m<\e[0;38;2;248;248;242;48;2;0;250;250mATTR\e[0m\e[K\e[0m>\e[0m 232 + Text: ' (x' 233 + attr: 234 + \e[0m<\e[0;35;7mATTR\e[0m\e[K\e[0m>\e[0m 235 + Text: ' ' 236 + attr: 237 + \e[0m<\e[0mATTR\e[0m\e[K\e[0m>\e[0m 238 + Text: '' 239 + |}] 240 + ;; 241 + end 242 + 243 + module ImageTests = struct 244 + (*============ 245 + Tests 246 + =============*) 247 + 248 + (* Test delta output*) 249 + let%expect_test "multiple escape sequences test" = 250 + let test_str = "\027[48;2;0;40;0;38;2;248;248;242m" in 251 + let res = 252 + Angstrom.parse_string ~consume:All Parser.parse_escape_seq test_str |> Result.get_ok 253 + in 254 + Parser.print_escape_seq res; 255 + (* print_endline test_str; *) 256 + [%expect 257 + {| 258 + escape sequence: 259 + attr: 260 + \e[0m<\e[0;48;2;0;40;0mATTR\e[0m\e[K\e[0m>\e[0m 261 + attr: 262 + \e[0m<\e[0;38;2;248;248;242mATTR\e[0m\e[K\e[0m>\e[0m 263 + |}] 264 + ;; 265 + 266 + let%expect_test "delta test output" = 267 + let test_str = 268 + "\027[48;2;0;40;0;38;2;248;248;242mhi-therehi" 269 + in 270 + let img = colored_string test_str in 271 + Internal.print_image_escaped img; 272 + (* print_endline test_str; *) 273 + [%expect 274 + {| 275 + image: 276 + \027[0;38;2;248;248;242;48;2;0;40;0mhi-there\027[0m\027[K\027[0mhi\027[0m 277 + |}] 278 + ;; 279 + 280 + let%expect_test "delta test output 2" = 281 + let test_str = 282 + {| 283 +  (x ^ "\n" 284 +  (x  285 + |} 286 + in 287 + let img = colored_string test_str in 288 + Internal.print_image img; 289 + [%expect 290 + {| 291 + image: 292 + 293 + (x ^ "\n" 294 + (x 295 + 296 + |}] 297 + ;; 298 + end
+36 -98
jj_tui/lib/process_wrappers.ml
··· 241 241 x |> print_endline); 242 242 [%expect 243 243 {| 244 - S: 245 - zqtxnkuuryqzzolyksrylpzotmplmvus 246 - 8ee443e4a374f7dfdd00494d8bf71af6162a1300 247 - @ zqtxnkuu eli.jambu@gmail.com 2025-02-15 21:22:48 8ee443e4 248 - │ (no description set) 249 - S: 250 - wmrnukwqvmnrsovsyxnmpwlkklnzpvpp 251 - b72673dcf464650064cdd80233b47848503cd01a 252 - ◌ wmrnukwq eli.jambu@gmail.com 2025-02-12 20:20:28 git_head() b72673dc 253 - │ wip: test 254 - S: 255 - oxpkqyozkvtxoklqutxztsmznxvwroxx 256 - 9c3af61798927da4c80caa216688ea9d69e0d8bb 257 - ○ oxpkqyoz eli.jambu@gmail.com 2024-11-26 12:13:41 9c3af617 258 - │ added duplicate and undo commands 259 - S: 260 - tmyqqryzkukzztrpxrsxlqlzutptsnsw 261 - 47d6c9a1db9d3756549dc7a68690f3df5600c83a 262 - ○ tmyqqryz eli.jambu@gmail.com 2024-11-23 21:50:19 47d6c9a1 263 - │ make update view fully async 264 - S: 265 - xwxrzsrzzlttpmysywysmnvtmrvysrvy 266 - 8e338e5c76cdcfb71951367ff87eb1df98561fbd 267 - │ ○ xwxrzsrz eli.jambu@gmail.com 2024-11-23 21:17:50 8e338e5c 268 - │ │ use picos nottui 269 - S: 270 - osuupotwtypnmvnkrrlxmyxukvykmtsn 271 - 3c203669a359b27833d9104c80505afd89af5f4d 272 - │ ○ osuupotw eli.jambu@gmail.com 2024-11-23 19:25:59 3c203669 273 - │ │ support await_read for async integration with nottui 274 - S: 275 - zmxzlvmwmnqruvrosmmknumpupoztuum 276 - 668152f47d627e80184b8dbb5f40dd2b83ad6488 277 - │ ◌ zmxzlvmw eli.jambu@gmail.com 2024-11-11 12:06:45 668152f4 278 - ├─╯ wip: try to allow nottui to support picos 279 - S: 280 - opytqrnrrxlkzsxtkuvtvxyrpqsmrznl 281 - e9d81817d5e56e0817b725e2965dd36d3918a087 282 - │ ○ opytqrnr eli.jambu@gmail.com 2024-11-02 12:31:37 e9d81817 283 - ├─╯ safeguard obj.magic functions 284 - S: 285 - ozotxprmvvwvwuulxlokrmlksxtzpmmv 286 - e882ff4a65c0eea778c4d0cc572d63e85444bc93 287 - │ ○ ozotxprm eli.jambu@gmail.com 2024-11-01 21:03:37 test-issues* e882ff4a 288 - ├─╯ spooky testing branch indicator 289 - S: 290 - kyzmstkmrsnrvtzzpwwnummnzpwlousx 291 - 15e7195328f95c7158dd1adc5e4bb50c7dd3372a 292 - ◆ kyzmstkm eli.jambu@gmail.com 2024-11-01 21:03:37 master v0.8.8 v0.8.9 15e71953 293 - │ fix remaining references to branch rather than bookmark 294 244 F: 245 + @ $$--START--$$|zqtxnkuuryqzzolyksrylpzotmplmvus|8ee443e4a374f7dfdd00494d8bf71af6162a1300|zqtxnkuu eli.jambu@gmail.com 2025-02-15 21:22:48 8ee443e4 246 + │ (no description set)$$--END--$$ 247 + ◌ $$--START--$$|wmrnukwqvmnrsovsyxnmpwlkklnzpvpp|b72673dcf464650064cdd80233b47848503cd01a|wmrnukwq eli.jambu@gmail.com 2025-02-12 20:20:28 git_head() b72673dc 248 + │ wip: test$$--END--$$ 249 + ○ $$--START--$$|oxpkqyozkvtxoklqutxztsmznxvwroxx|9c3af61798927da4c80caa216688ea9d69e0d8bb|oxpkqyoz eli.jambu@gmail.com 2024-11-26 12:13:41 9c3af617 250 + │ added duplicate and undo commands$$--END--$$ 251 + ○ $$--START--$$|tmyqqryzkukzztrpxrsxlqlzutptsnsw|47d6c9a1db9d3756549dc7a68690f3df5600c83a|tmyqqryz eli.jambu@gmail.com 2024-11-23 21:50:19 47d6c9a1 252 + │ make update view fully async$$--END--$$ 253 + │ ○ $$--START--$$|xwxrzsrzzlttpmysywysmnvtmrvysrvy|8e338e5c76cdcfb71951367ff87eb1df98561fbd|xwxrzsrz eli.jambu@gmail.com 2024-11-23 21:17:50 8e338e5c 254 + │ │ use picos nottui$$--END--$$ 255 + │ ○ $$--START--$$|osuupotwtypnmvnkrrlxmyxukvykmtsn|3c203669a359b27833d9104c80505afd89af5f4d|osuupotw eli.jambu@gmail.com 2024-11-23 19:25:59 3c203669 256 + │ │ support await_read for async integration with nottui$$--END--$$ 257 + │ ◌ $$--START--$$|zmxzlvmwmnqruvrosmmknumpupoztuum|668152f47d627e80184b8dbb5f40dd2b83ad6488|zmxzlvmw eli.jambu@gmail.com 2024-11-11 12:06:45 668152f4 258 + ├─╯ wip: try to allow nottui to support picos$$--END--$$ 259 + │ ○ $$--START--$$|opytqrnrrxlkzsxtkuvtvxyrpqsmrznl|e9d81817d5e56e0817b725e2965dd36d3918a087|opytqrnr eli.jambu@gmail.com 2024-11-02 12:31:37 e9d81817 260 + ├─╯ safeguard obj.magic functions$$--END--$$ 261 + │ ○ $$--START--$$|ozotxprmvvwvwuulxlokrmlksxtzpmmv|e882ff4a65c0eea778c4d0cc572d63e85444bc93|ozotxprm eli.jambu@gmail.com 2024-11-01 21:03:37 test-issues* e882ff4a 262 + ├─╯ spooky testing branch indicator$$--END--$$ 263 + ◆ $$--START--$$|kyzmstkmrsnrvtzzpwwnummnzpwlousx|15e7195328f95c7158dd1adc5e4bb50c7dd3372a|kyzmstkm eli.jambu@gmail.com 2024-11-01 21:03:37 master v0.8.8 v0.8.9 15e71953 264 + │ fix remaining references to branch rather than bookmark$$--END--$$ 295 265 ~ (elided revisions) 296 - 297 - S: 298 - uzuylryqmsmrlyzunluznwlkqsuurktp 299 - 811f78b9f5d3272ff65a80d973ad9fe3db338fc8 300 - │ ○ uzuylryq eli.jambu@gmail.com 2024-10-31 18:49:04 811f78b9 301 - ├─╯ Try to make new dune build the project 302 - S: 303 - oorzkzkwlkqpptmnzvvqvkmxxxrvxpnv 304 - 93c69eccd3e0838ee45946dc2b0eadbe4e679362 305 - ◆ oorzkzkw eli.jambu@gmail.com 2024-10-27 18:44:00 aaa v0.8.7 93c69ecc 306 - │ updated to use bookmark instead of branch 307 - F: 266 + │ ○ $$--START--$$|uzuylryqmsmrlyzunluznwlkqsuurktp|811f78b9f5d3272ff65a80d973ad9fe3db338fc8|uzuylryq eli.jambu@gmail.com 2024-10-31 18:49:04 811f78b9 267 + ├─╯ Try to make new dune build the project$$--END--$$ 268 + ◆ $$--START--$$|oorzkzkwlkqpptmnzvvqvkmxxxrvxpnv|93c69eccd3e0838ee45946dc2b0eadbe4e679362|oorzkzkw eli.jambu@gmail.com 2024-10-27 18:44:00 aaa v0.8.7 93c69ecc 269 + │ updated to use bookmark instead of branch$$--END--$$ 308 270 ~ (elided revisions) 309 - 310 - S: 311 - nyzlmxtpvrxsormrrtzkwsopzuypppwr 312 - 81fca5ab7626736be4f61323ca8f27ed35659343 313 - │ ○ nyzlmxtp eli.jambu@gmail.com 2024-09-30 21:13:28 81fca5ab 314 - ├─╯ debugging config 315 - S: 316 - llxznmqxrmtumwyprntkvzupkywpvwoz 317 - a529037b79b469d3c63857ef70395be46a38dda7 318 - ◆ llxznmqx eli.jambu@gmail.com 2024-09-30 20:57:49 a529037b 319 - │ multi-select 320 - F: 271 + │ ○ $$--START--$$|nyzlmxtpvrxsormrrtzkwsopzuypppwr|81fca5ab7626736be4f61323ca8f27ed35659343|nyzlmxtp eli.jambu@gmail.com 2024-09-30 21:13:28 81fca5ab 272 + ├─╯ debugging config$$--END--$$ 273 + ◆ $$--START--$$|llxznmqxrmtumwyprntkvzupkywpvwoz|a529037b79b469d3c63857ef70395be46a38dda7|llxznmqx eli.jambu@gmail.com 2024-09-30 20:57:49 a529037b 274 + │ multi-select$$--END--$$ 321 275 ~ (elided revisions) 322 - 323 - S: 324 - wlrqltouzqqpvpzzlzstytypnstlronp 325 - a6dbb3d390f01789f34ca279f3ee4ac0df6ceacd 326 - │ ○ wlrqltou eli.jambu@gmail.com 2024-08-18 16:04:45 a6dbb3d3 327 - ├─╯ (no description set) 328 - S: 329 - rwovpxktnwvyzpwmqsymtsquspvszwnl 330 - 235cdeaa5ef71894eca562a04eaee8d010ebe276 331 - ◆ rwovpxkt eli.jambu@gmail.com 2024-08-18 15:07:25 235cdeaa 332 - │ filterable selcteion box styling 333 - F: 276 + │ ○ $$--START--$$|wlrqltouzqqpvpzzlzstytypnstlronp|a6dbb3d390f01789f34ca279f3ee4ac0df6ceacd|wlrqltou eli.jambu@gmail.com 2024-08-18 16:04:45 a6dbb3d3 277 + ├─╯ (no description set)$$--END--$$ 278 + ◆ $$--START--$$|rwovpxktnwvyzpwmqsymtsquspvszwnl|235cdeaa5ef71894eca562a04eaee8d010ebe276|rwovpxkt eli.jambu@gmail.com 2024-08-18 15:07:25 235cdeaa 279 + │ filterable selcteion box styling$$--END--$$ 334 280 ~ (elided revisions) 335 - 336 - S: 337 - vzpuwsqtotlxpkxpqqkxzzlrkupknztq 338 - a26efab4741c026b298098bd4ef6f251b9c29945 339 - │ ○ vzpuwsqt eli.jambu@gmail.com 2024-08-18 11:56:20 a26efab4 340 - ├─╯ (empty) ss 341 - S: 342 - zyonzlkqvopymszlpsztlrxqwttyxqoy 343 - 5cf5114617d86a60abe3dc33b77ff1c13ddcc202 344 - ◆ zyonzlkq eli.jambu@gmail.com 2024-08-09 11:44:33 5cf51146 345 - │ Replace tabs with 4 spaces becasue they cause issuse for nottui 346 - F: 281 + │ ○ $$--START--$$|vzpuwsqtotlxpkxpqqkxzzlrkupknztq|a26efab4741c026b298098bd4ef6f251b9c29945|vzpuwsqt eli.jambu@gmail.com 2024-08-18 11:56:20 a26efab4 282 + ├─╯ (empty) ss$$--END--$$ 283 + ◆ $$--START--$$|zyonzlkqvopymszlpsztlrxqwttyxqoy|5cf5114617d86a60abe3dc33b77ff1c13ddcc202|zyonzlkq eli.jambu@gmail.com 2024-08-09 11:44:33 5cf51146 284 + │ Replace tabs with 4 spaces becasue they cause issuse for nottui$$--END--$$ 347 285 ~ 348 286 |}] 349 287 ;;
+3 -2
jj_tui/test/lib/ansi.ml
··· 46 46 ====== input===== 47 47 \n\226\151\137 \027[1m\027[38;5;5myq\027[0m\027[38;5;8mytskyk\027[39m \027[38;5;3meli.jambu@gmail.com\027[39m \027[38;5;6m2024-05-13 09:34:43\027[39m \027[1m\027[38;5;4mb\027[0m\027[38;5;8m432b3c1\027[39m\n\226\148\130 test reorganise\n@ \027[1m\027[38;5;13mtw\027[38;5;8msoqryt\027[39m \027[38;5;3meli.jambu@gmail.com\027[39m \027[38;5;14m2024-05-13 09:34:43\027[39m \027[38;5;12m87\027[38;5;8md4ffad\027[39m\027[0m\n\226\148\130 \027[1mupdated flakes\027[0m\n\226\151\137 \027[1m\027[38;5;5mys\027[0m\027[38;5;8mzqynxv\027[39m \027[38;5;3meli.jambu@gmail.com\027[39m \027[38;5;6m2024-05-13 08:22:36\027[39m \027[38;5;2mHEAD@git\027[39m \027[1m\027[38;5;4m65\027[0m\027[38;5;8md9b7dc\027[39m\n\226\148\130 opam template\n\226\151\137 \027[1m\027[38;5;5mkr\027[0m\027[38;5;8mzvxzyw\027[39m \027[38;5;3meli.jambu@gmail.com\027[39m \027[38;5;6m2024-05-13 07:53:04\027[39m \027[1m\027[38;5;4m0c\027[0m\027[38;5;8mf0a9b8\027[39m\n\226\148\130 different strat\n\226\151\137 \027[1m\027[38;5;5ml\027[0m\027[38;5;8mzrkyqxq\027[39m \027[38;5;3meli.jambu@gmail.com\027[39m \027[38;5;6m2024-05-12 20:28:46\027[39m \027[38;5;5mmaster?? master?? master@git master@origin\027[39m \027[1m\027[38;5;4me3\027[0m\027[38;5;8me2ba28\027[39m\n\226\148\130 remove vendor libs\n\226\148\130 \226\151\137 \027[1m\027[38;5;5mq\027[0m\027[38;5;8mpqzkuss\027[39m \027[38;5;3meli.jambu@gmail.com\027[39m \027[38;5;6m2024-05-12 21:07:29\027[39m \027[1m\027[38;5;4m5\027[0m\027[38;5;8m1e7fabe\027[39m\n\226\148\130 \226\148\130 \027[38;5;3m(no description set)\027[39m\n\226\148\130 \226\151\137 \027[1m\027[38;5;5mx\027[0m\027[38;5;8mpqmtrmp\027[39m \027[38;5;3meli.jambu@gmail.com\027[39m \027[38;5;6m2024-05-12 20:31:20\027[39m \027[1m\027[38;5;4me5\027[0m\027[38;5;8mcaae1c\027[39m\n\226\148\156\226\148\128\226\149\175 remove old nix file\n\226\151\137 \027[1m\027[38;5;5mzx\027[0m\027[38;5;8mpskuop\027[39m \027[38;5;3meli.jambu@gmail.com\027[39m \027[38;5;6m2024-05-12 00:43:25\027[39m \027[1m\027[38;5;4m3\027[0m\027[38;5;8m3771185\027[39m\n\226\148\130 Update README.md\n\226\151\140 \027[38;5;8m(elided revisions)\027[39m\n\226\148\130 \226\151\137 \027[1m\027[38;5;5mn\027[0m\027[38;5;8mwxyqxuv\027[39m \027[38;5;3meli.jambu@gmail.com\027[39m \027[38;5;6m2024-05-11 14:11:37\027[39m \027[1m\027[38;5;4m89\027[0m\027[38;5;8m392bc6\027[39m\n\226\148\156\226\148\128\226\149\175 \027[38;5;3m(no description set)\027[39m\n\226\151\137 \027[1m\027[38;5;5mkm\027[0m\027[38;5;8mosytmo\027[39m \027[38;5;3meli.jambu@gmail.com\027[39m \027[38;5;6m2024-05-11 14:11:37\027[39m \027[1m\027[38;5;4m4\027[0m\027[38;5;8m1122b29\027[39m\n\226\148\130 backup opam\n\226\151\140 \027[38;5;8m(elided revisions)\027[39m\n\226\148\130 \226\151\137 \027[1m\027[38;5;5mto\027[0m\027[38;5;8moppyyl\027[39m \027[38;5;3meli.jambu@gmail.com\027[39m \027[38;5;6m2024-05-11 03:29:14\027[39m \027[1m\027[38;5;4m6f\027[0m\027[38;5;8md850b1\027[39m\n\226\148\156\226\148\128\226\149\175 test\n\226\151\137 \027[1m\027[38;5;5mzz\027[0m\027[38;5;8mzzzzzz\027[39m \027[38;5;2mroot()\027[39m \027[1m\027[38;5;4m00\027[0m\027[38;5;8m000000\027[39m\n 48 48 ====== output escaped===== 49 - \027[0m\027[K\027[0m\n\027[0m\226\151\137 \027[0;35;1myq\027[0;90mytskyk\027[0m \027[0;33meli.jambu@gmail.com\027[0m \027[0;36m2024-05-13 09:34:43\027[0m \027[0;34;1mb\027[0m\027[K\027[0;90m432b3c1\027[0m\n\027[0m\027[K\027[0m\226\148\130 test reorganise\027[0m\n\027[0m@ \027[0;95;1mtw\027[0;90;1msoqryt\027[0;1m \027[0;33;1meli.jambu@gmail.com\027[0;1m \027[0;96;1m2024-05-13 09:34:43\027[0;1m \027[0;94;1m87\027[0m\027[K\027[0;90;1md4ffad\027[0m\n\027[0m\226\148\130 \027[0m\027[K\027[0;1mupdated flakes\027[0m\n\027[0m\226\151\137 \027[0;35;1mys\027[0;90mzqynxv\027[0m \027[0;33meli.jambu@gmail.com\027[0m \027[0;36m2024-05-13 08:22:36\027[0m \027[0;32mHEAD@git\027[0m \027[0;34;1m65\027[0m\027[K\027[0;90md9b7dc\027[0m\n\027[0m\027[K\027[0m\226\148\130 opam template\027[0m\n\027[0m\226\151\137 \027[0;35;1mkr\027[0;90mzvxzyw\027[0m \027[0;33meli.jambu@gmail.com\027[0m \027[0;36m2024-05-13 07:53:04\027[0m \027[0;34;1m0c\027[0m\027[K\027[0;90mf0a9b8\027[0m\n\027[0m\027[K\027[0m\226\148\130 different strat\027[0m\n\027[0m\226\151\137 \027[0;35;1ml\027[0;90mzrkyqxq\027[0m \027[0;33meli.jambu@gmail.com\027[0m \027[0;36m2024-05-12 20:28:46\027[0m \027[0m\027[K\027[0;35mmaster?? master?? master@g\027[0m\n\027[0m\027[K\027[0m\226\148\130 remove vendor libs\027[0m\n\027[0m\226\148\130 \226\151\137 \027[0;35;1mq\027[0;90mpqzkuss\027[0m \027[0;33meli.jambu@gmail.com\027[0m \027[0;36m2024-05-12 21:07:29\027[0m \027[0;34;1m5\027[0m\027[K\027[0;90m1e7fabe\027[0m\n\027[0m\226\148\130 \226\148\130 \027[0m\027[K\027[0;33m(no description set)\027[0m\n\027[0m\226\148\130 \226\151\137 \027[0;35;1mx\027[0;90mpqmtrmp\027[0m \027[0;33meli.jambu@gmail.com\027[0m \027[0;36m2024-05-12 20:31:20\027[0m \027[0;34;1me5\027[0m\027[K\027[0;90mcaae1c\027[0m\n\027[0m\027[K\027[0m\226\148\156\226\148\128\226\149\175 remove old nix file\027[0m\n\027[0m\226\151\137 \027[0;35;1mzx\027[0;90mpskuop\027[0m \027[0;33meli.jambu@gmail.com\027[0m \027[0;36m2024-05-12 00:43:25\027[0m \027[0;34;1m3\027[0m\027[K\027[0;90m3771185\027[0m\n\027[0m\027[K\027[0m\226\148\130 Update README.md\027[0m\n\027[0m\226\151\140 \027[0m\027[K\027[0;90m(elided revisions)\027[0m\n\027[0m\226\148\130 \226\151\137 \027[0;35;1mn\027[0;90mwxyqxuv\027[0m \027[0;33meli.jambu@gmail.com\027[0m \027[0;36m2024-05-11 14:11:37\027[0m \027[0;34;1m89\027[0m\027[K\027[0;90m392bc6\027[0m\n\027[0m\226\148\156\226\148\128\226\149\175 \027[0m\027[K\027[0;33m(no description set)\027[0m\n\027[0m\226\151\137 \027[0;35;1mkm\027[0;90mosytmo\027[0m \027[0;33meli.jambu@gmail.com\027[0m \027[0;36m2024-05-11 14:11:37\027[0m \027[0;34;1m4\027[0m\027[K\027[0;90m1122b29\027[0m\n\027[0m\027[K\027[0m\226\148\130 backup opam\027[0m\n\027[0m\226\151\140 \027[0m\027[K\027[0;90m(elided revisions)\027[0m\n\027[0m\226\148\130 \226\151\137 \027[0;35;1mto\027[0;90moppyyl\027[0m \027[0;33meli.jambu@gmail.com\027[0m \027[0;36m2024-05-11 03:29:14\027[0m \027[0;34;1m6f\027[0m\027[K\027[0;90md850b1\027[0m\n\027[0m\027[K\027[0m\226\148\156\226\148\128\226\149\175 test\027[0m\n\027[0m\226\151\137 \027[0;35;1mzz\027[0;90mzzzzzz\027[0m \027[0;32mroot()\027[0m \027[0;34;1m00\027[0;90m000000\027[0m\027[K\027[0m \027[0m 49 + \027[0m\027[K\027[0m\n\027[0m\226\151\137 \027[0;35;1myq\027[0;90mytskyk\027[0m \027[0;33meli.jambu@gmail.com\027[0m \027[0;36m2024-05-13 09:34:43\027[0m \027[0;34;1mb\027[0m\027[K\027[0;90m432b3c1\027[0m\n\027[0m\027[K\027[0m\226\148\130 test reorganise\027[0m\n\027[0m@ \027[0;95;1mtw\027[0;90;1msoqryt\027[0;1m \027[0;33;1meli.jambu@gmail.com\027[0;1m \027[0;96;1m2024-05-13 09:34:43\027[0;1m \027[0;94;1m87\027[0m\027[K\027[0;90;1md4ffad\027[0m\n\027[0m\226\148\130 \027[0m\027[K\027[0;1mupdated flakes\027[0m\n\027[0m\226\151\137 \027[0;35;1mys\027[0;90mzqynxv\027[0m \027[0;33meli.jambu@gmail.com\027[0m \027[0;36m2024-05-13 08:22:36\027[0m \027[0;32mHEAD@git\027[0m \027[0;34;1m65\027[0m\027[K\027[0;90md9b7dc\027[0m\n\027[0m\027[K\027[0m\226\148\130 opam template\027[0m\n\027[0m\226\151\137 \027[0;35;1mkr\027[0;90mzvxzyw\027[0m \027[0;33meli.jambu@gmail.com\027[0m \027[0;36m2024-05-13 07:53:04\027[0m \027[0;34;1m0c\027[0m\027[K\027[0;90mf0a9b8\027[0m\n\027[0m\027[K\027[0m\226\148\130 different strat\027[0m\n\027[0m\226\151\137 \027[0;35;1ml\027[0;90mzrkyqxq\027[0m \027[0;33meli.jambu@gmail.com\027[0m \027[0;36m2024-05-12 20:28:46\027[0m \027[0m\027[K\027[0;35mmaster?? master?? master@g\027[0m\n\027[0m\027[K\027[0m\226\148\130 remove vendor libs\027[0m\n\027[0m\226\148\130 \226\151\137 \027[0;35;1mq\027[0;90mpqzkuss\027[0m \027[0;33meli.jambu@gmail.com\027[0m \027[0;36m2024-05-12 21:07:29\027[0m \027[0;34;1m5\027[0m\027[K\027[0;90m1e7fabe\027[0m\n\027[0m\226\148\130 \226\148\130 \027[0m\027[K\027[0;33m(no description set)\027[0m\n\027[0m\226\148\130 \226\151\137 \027[0;35;1mx\027[0;90mpqmtrmp\027[0m \027[0;33meli.jambu@gmail.com\027[0m \027[0;36m2024-05-12 20:31:20\027[0m \027[0;34;1me5\027[0m\027[K\027[0;90mcaae1c\027[0m\n\027[0m\027[K\027[0m\226\148\156\226\148\128\226\149\175 remove old nix file\027[0m\n\027[0m\226\151\137 \027[0;35;1mzx\027[0;90mpskuop\027[0m \027[0;33meli.jambu@gmail.com\027[0m \027[0;36m2024-05-12 00:43:25\027[0m \027[0;34;1m3\027[0m\027[K\027[0;90m3771185\027[0m\n\027[0m\027[K\027[0m\226\148\130 Update README.md\027[0m\n\027[0m\226\151\140 \027[0m\027[K\027[0;90m(elided revisions)\027[0m\n\027[0m\226\148\130 \226\151\137 \027[0;35;1mn\027[0;90mwxyqxuv\027[0m \027[0;33meli.jambu@gmail.com\027[0m \027[0;36m2024-05-11 14:11:37\027[0m \027[0;34;1m89\027[0m\027[K\027[0;90m392bc6\027[0m\n\027[0m\226\148\156\226\148\128\226\149\175 \027[0m\027[K\027[0;33m(no description set)\027[0m\n\027[0m\226\151\137 \027[0;35;1mkm\027[0;90mosytmo\027[0m \027[0;33meli.jambu@gmail.com\027[0m \027[0;36m2024-05-11 14:11:37\027[0m \027[0;34;1m4\027[0m\027[K\027[0;90m1122b29\027[0m\n\027[0m\027[K\027[0m\226\148\130 backup opam\027[0m\n\027[0m\226\151\140 \027[0m\027[K\027[0;90m(elided revisions)\027[0m\n\027[0m\226\148\130 \226\151\137 \027[0;35;1mto\027[0;90moppyyl\027[0m \027[0;33meli.jambu@gmail.com\027[0m \027[0;36m2024-05-11 03:29:14\027[0m \027[0;34;1m6f\027[0m\027[K\027[0;90md850b1\027[0m\n\027[0m\027[K\027[0m\226\148\156\226\148\128\226\149\175 test\027[0m\n\027[0m\226\151\137 \027[0;35;1mzz\027[0;90mzzzzzz\027[0m \027[0;32mroot()\027[0m \027[0;34;1m00\027[0m\027[K\027[0;90m000000\027[0m\n\027[0m \027[0m\027[K\027[0m \027[0m 50 50 =====output==== 51 51  52 52 ◉ yqytskyk eli.jambu@gmail.com 2024-05-13 09:34:43 b432b3c1 ··· 73 73 ◌ (elided revisions) 74 74 │ ◉ tooppyyl eli.jambu@gmail.com 2024-05-11 03:29:14 6fd850b1 75 75 ├─╯ test 76 - ◉ zzzzzzzz root() 00000000  76 + ◉ zzzzzzzz root() 00000000 77 +    77 78 |}] 78 79 ;; 79 80