Legend:
Page
Library
Module
Module type
Parameter
Class
Class type
Source
Page
Library
Module
Module type
Parameter
Class
Class type
Source
Style.ml1 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 129(* Text highlighting *) open Printf type color = Default | Red | Green | Yellow | Cyan | Bold | Faint let ansi_code_of_style = function | Default -> "0" | Red -> "31" | Green -> "32" | Yellow -> "33" | Cyan -> "36" | Bold -> "1" | Faint -> "2" let color color str = Printf.sprintf "\027[%sm%s\027[%sm" (ansi_code_of_style color) str (ansi_code_of_style Default) let opt_color cond color_ str = if cond then color color_ str else str (* Remove formatting. It's a bit ugly but convenient to compute the length of a sequence of characters. *) let strip = let re = Re.Pcre.regexp "\027\\[[0-9]+m" in fun str -> Re.replace re ~f:(fun _ -> "") str (* Return the number of code points assuming UTF-8-compatible encoding (and no surrogate pairs i.e. WTF-8). *) let utf8_length str = let count = ref 0 in String.iter (fun c -> if Char.code c <= 0b01111111 || Char.code c >= 0b11000000 then incr count) str; !count (* The physical length of a rendered string assuming UTF-8 encoding, one character per UTF-8 code point, and a fixed width of 1 per character. The result will be wrong if the string contains control characters such as newlines. *) let graph_length str = strip str |> utf8_length let pad str min_len = let len = graph_length str in if len >= min_len then str ^ " " else str ^ String.make (min_len - len) ' ' let left_col text = pad text 8 (* Same as String.make but repeats a multi-byte unit rather than a byte *) let string_make len unit = let buf = Buffer.create (len * String.length unit) in for _ = 1 to len do Buffer.add_string buf unit done; Buffer.contents buf let term_width = 80 let horizontal_line = let res = (string_make term_width "─" |> color Faint) ^ "\n" in fun () -> res let frame str = let padded_str = pad str (term_width - 4) in let horizontal_line = string_make (String.length (strip padded_str) + 2) "─" in let top_line = sprintf "┌%s┐\n" horizontal_line |> color Faint in let bottom_line = sprintf "└%s┘\n" horizontal_line |> color Faint in let contents_line = sprintf "%s %s %s\n" (color Faint "│") padded_str (color Faint "│") in top_line ^ contents_line ^ bottom_line let truncate_text ~decorate_comment ~decorate_data_fragment ~max_bytes str = match max_bytes with | None -> str | Some max_len -> let orig_len = String.length str in let max_len = max 0 max_len in if orig_len <= max_len then str else (* Let's keep the beginning and the end of the text since they're more likely to contain useful information than the middle. We don't care about breaking multibyte characters. UTF-8 decoders are expected to recover from broken multibyte sequences. *) let head_len = max_len / 2 in let tail_len = max_len - head_len in if head_len <= 0 || tail_len <= 0 then str else let mid_len = orig_len - head_len - tail_len in let head = String.sub str 0 head_len in let tail = String.sub str (head_len + mid_len) tail_len in let mid = sprintf "\n###### [hidden: %d bytes] ######\n" mid_len in let warning = sprintf "###### Warning: bytes %d-%d below were elided ######\n" head_len (head_len + mid_len - 1) in String.concat "" [ decorate_comment warning; decorate_data_fragment head; decorate_comment mid; decorate_data_fragment tail; ] (* Add a trailing newline and indent each line. *) let quote_multiline_text = (* Indent by one space, similarly to 'diff -u' output *) let margin = " " in fun ?(decorate_comment = color Yellow) ?(decorate_data_fragment = fun str -> str) ?max_bytes str -> str |> truncate_text ~decorate_comment ~decorate_data_fragment ~max_bytes |> String.split_on_char '\n' |> Helpers.list_map (fun line -> margin ^ line ^ "\n") |> String.concat ""