···195195 and lightmagenta = 0x0100000d
196196 and lightcyan = 0x0100000e
197197 and lightwhite = 0x0100000f
198198- and no_color = 0x01000010
198198+ and color_reset = 0x01000010
199199200200 let tag c = (c land 0x03000000) lsr 24
201201···240240241241 let (--) a1 a2 =
242242 if a1 == empty then a2 else if a2 == empty then a1 else
243243- { fg = (match a2.fg with no_color -> 0 | _ -> a1.fg)
244244- ; bg = (match a2.bg with no_color -> 0 | _ -> a1.bg)
243243+ (* 0x01000010 is the color reset color defined above*)
244244+ { fg = (match a2.fg with 0x01000010-> 0 | _ -> if a1.fg==a2.fg then 0 else a1.fg)
245245+ ; bg = (match a2.bg with 0x01000010-> 0 | _ -> if a1.bg==a2.bg then 0 else a1.bg)
245246 ; st = a1.st land (lnot a2.st) }
246247247248 let fg fg = { empty with fg }
+2-5
forks/notty/src/notty.mli
···104104 val lightmagenta : color
105105 val lightcyan : color
106106 val lightwhite : color
107107- val no_color : color
107107+ val color_reset : color
108108109109 (** {2 Extended 256-color palette} *)
110110···169169 [++] is left-associative, and forms a monoid with [empty]. *)
170170171171 val (--) : attr -> attr -> attr
172172- (** [a1 -- a2] is the difference of [a1] and [a2], the attribute that has
173173- [a1]'s foreground (resp. background), unless {e unset}, in which case it
174174- is [a2]'s, and the difference of both style sets.
175175-172172+ (** [a1 -- a2] removes a2 from a1
176173 [--] is left-associative, and forms a monoid with [empty]. *)
177174178175 val fg : color -> attr
+81-14
jj_tui/lib/ansiReverse.ml
···3333 let print_attr img =
3434 print_endline "attr:";
3535 img |> Notty.Render.pp_attr @@ Format.str_formatter;
3636- print_endline (Format.flush_str_formatter ()|>Str.global_replace (Str.regexp "\027") "\\e")
3636+ print_endline
3737+ (Format.flush_str_formatter () |> Str.global_replace (Str.regexp "\027") "\\e")
3738 ;;
38393940 (** Like fold left except we run the first element through init to get the state*)
···5455 | Apply of A.t
5556 | Reset of A.t
5657 | FullyReset
5858+5759 let parse_escape_seq =
5860 let open A in
5961 let open Angstrom in
···6365 let param = digits <* option ' ' (char ';') in
6466 let params = many (param >>| int_of_string) in
6567 let escape_sequence = char '\027' *> char '[' *> params <* char 'm' in
6868+ let full_seq=many1 escape_sequence in
6669 let attr_of_params = function
6770 | [] ->
6871 Apply empty
···9194 | 23 :: _ ->
9295 Reset (st italic) (* Reset italic *)
9396 | 24 :: _ ->
9494- Reset (st underline ) (* Reset underline *)
9797+ Reset (st underline) (* Reset underline *)
9598 | 25 :: _ ->
9699 Reset (st blink) (* Reset blink *)
97100 | 27 :: _ ->
···121124 | 38 :: 2 :: r :: g :: b :: _ ->
122125 Apply (fg (rgb_888 ~r ~g ~b))
123126 | 39 :: _ ->
124124- Reset (fg no_color) (* Default foreground color *)
127127+ Reset (fg color_reset) (* Default foreground color *)
125128 | 40 :: _ ->
126129 Apply (bg black)
127130 | 41 :: _ ->
···143146 | 48 :: 2 :: r :: g :: b :: _ ->
144147 Apply (bg (rgb_888 ~r ~g ~b))
145148 | 49 :: _ ->
146146- Reset (bg no_color) (* Default background color *)
149149+ Reset (bg color_reset) (* Default background color *)
147150 | 90 :: _ ->
148151 Apply (fg lightblack) (* Bright black (gray) *)
149152 | 91 :: _ ->
···179182 | _ ->
180183 Apply empty
181184 in
182182- escape_sequence >>| attr_of_params
185185+ full_seq>>| List.map attr_of_params
183186 ;;
184187185188 let%expect_test "escape_parser" =
···187190 let res =
188191 Angstrom.parse_string ~consume:All parse_escape_seq test_str |> Result.get_ok
189192 in
193193+ res|>List.iter(fun res->
190194 (match res with
191195 | Apply attr ->
192196 print_attr attr
···194198 print_endline "Reset attribute"
195199 | FullyReset ->
196200 print_endline "Fully reset attribute");
197197-201201+ );
202202+ [%expect
203203+ {|
204204+ attr:
205205+ \e[0m<\e[0;32mATTR\e[0m\e[K\e[0m>\e[0m
206206+ |}]
207207+ ;;
208208+ let%expect_test "escape_parser_2" =
209209+ let test_str = "\027[32m" in
210210+ let res =
211211+ Angstrom.parse_string ~consume:All parse_escape_seq test_str |> Result.get_ok
212212+ in
213213+ res|>List.iter(fun res->
214214+ (match res with
215215+ | Apply attr ->
216216+ print_attr attr
217217+ | Reset _ ->
218218+ print_endline "Reset attribute"
219219+ | FullyReset ->
220220+ print_endline "Fully reset attribute");
221221+ );
198222 [%expect
199223 {|
200224 attr:
···208232 let attr = parse_escape_seq in
209233 let substring = take_while (fun c -> c <> '\027') in
210234 let pair =
211211- attr >>= fun action ->
235235+ attr >>= fun actions ->
212236 substring >>= fun s ->
213213- (match action with
237237+ actions|>List.iter(fun action->
238238+ match action with
214239 | Apply a ->
215240 attr_state := A.( ++ ) !attr_state a
216241 | Reset a ->
···264289 Text: "rest"
265290 |}]
266291 ;;
292292+267293 let%expect_test "parse_ansi_strikethrough_test" =
268268- let open A in
294294+ let open A in
269295 print_attr (A.st A.strike);
270296 print_attr (A.st A.strike ++ A.fg A.red);
271297 print_attr (A.st A.blink);
···275301 print_attr (A.st A.bold);
276302 print_attr (A.st A.reverse ++ A.fg A.red);
277303 print_attr (A.st A.hidden);
278278-279304 [%expect
280305 {|
281306 attr:
···299324 |}]
300325 ;;
301326302302-303327 let%expect_test "attribute_removal_test" =
304328 let open A in
305329 (* Test removing styles *)
306306- let base_attr = st bold ++ st underline ++ st italic in
330330+ let base_attr = st bold ++ st underline ++ st italic in
307331 let result = base_attr -- st italic in
308332 Internal.print_attr result;
309333 [%expect
···321345 |}];
322346 (* Test removing foreground color *)
323347 let colored = base_attr ++ fg red in
324324- let no_color = colored -- fg no_color in
325325- Internal.print_attr no_color;
348348+ let color_reset = colored -- fg color_reset in
349349+ Internal.print_attr color_reset;
326350 [%expect
327351 {|
328352 attr:
329353 \e[0m<\e[0;1;3;4mATTR\e[0m\e[K\e[0m>\e[0m
354354+ |}];
355355+ (* Test removing a style from colored *)
356356+ let no_underline = colored -- st underline in
357357+ Internal.print_attr no_underline;
358358+ [%expect
359359+ {|
360360+ attr:
361361+ \e[0m<\e[0;1;3mATTR\e[0m\e[K\e[0m>\e[0m
330362 |}];
331363 (* Test removing background color *)
332364 let bg_colored = base_attr ++ bg blue in
···345377 {|
346378 attr:
347379 \e[0m<\e[0mATTR\e[0m\e[K\e[0m>\e[0m
380380+ |}]
381381+ ;;
382382+383383+ let%expect_test "edge_case_1" =
384384+ let test_str =
385385+ {|[38;5;2m 145[39m: [4m[38;5;2mone[24mscript[4m10|}
386386+ in
387387+ (match parse_ansi_escape_codes test_str with
388388+ | Error err ->
389389+ Printf.printf "Error: %s\n" err
390390+ | Ok result ->
391391+ Printf.printf "Parsed %d segments:\n" (List.length result);
392392+ List.iter
393393+ (fun (attr, text) ->
394394+ print_attr attr;
395395+ Printf.printf "Text: %s" (String.escaped text))
396396+ result);
397397+ [%expect
398398+ {|
399399+ Parsed 7 segments:
400400+ attr:
401401+ \e[0m<\e[0mATTR\e[0m\e[K\e[0m>\e[0m
402402+ Text: attr:
403403+ \e[0m<\e[0;32mATTR\e[0m\e[K\e[0m>\e[0m
404404+ Text: 145attr:
405405+ \e[0m<\e[0mATTR\e[0m\e[K\e[0m>\e[0m
406406+ Text: : attr:
407407+ \e[0m<\e[0;4mATTR\e[0m\e[K\e[0m>\e[0m
408408+ Text: attr:
409409+ \e[0m<\e[0;32;4mATTR\e[0m\e[K\e[0m>\e[0m
410410+ Text: oneattr:
411411+ \e[0m<\e[0mATTR\e[0m\e[K\e[0m>\e[0m
412412+ Text: scriptattr:
413413+ \e[0m<\e[0;4mATTR\e[0m\e[K\e[0m>\e[0m
414414+ Text: 10
348415 |}]
349416 ;;
350417end