From 003a707af058c0050fdb94e5236b52bc50ed5ddd Mon Sep 17 00:00:00 2001 From: milner Date: Tue, 17 May 2022 19:36:28 +0000 Subject: [PATCH] feat(style): gate ANSI colour on tty detection One wrapper per colour plus a padding helper, all no-ops when stdout is not a terminal, so piped output and CI logs stay readable. --- lib/style.ml | 39 +++++++++++++++++++++++++++++++++++++++ 1 file changed, 39 insertions(+) create mode 100644 lib/style.ml diff --git a/lib/style.ml b/lib/style.ml new file mode 100644 index 0000000..cb9a51d --- /dev/null +++ b/lib/style.ml @@ -0,0 +1,39 @@ +let enabled = ref true + +let wrap code s = if !enabled then "\027[" ^ code ^ "m" ^ s ^ "\027[0m" else s + +let bold s = wrap "1" s +let dim s = wrap "2" s +let red s = wrap "31" s +let green s = wrap "32" s +let yellow s = wrap "33" s +let blue s = wrap "34" s +let magenta s = wrap "35" s +let cyan s = wrap "36" s + +let visible s = + let n = String.length s in + let rec go i acc = + if i >= n then acc + else if s.[i] = '\027' then + let rec skip j = if j >= n || s.[j] = 'm' then j + 1 else skip (j + 1) in + go (skip i) acc + else go (i + 1) (acc + 1) + in + go 0 0 + +let pad n s = s ^ String.make (max 0 (n - visible s)) ' ' + +let pad_left n s = String.make (max 0 (n - visible s)) ' ' ^ s +let ellipsis n s = if visible s <= n then s else String.sub s 0 (max 0 (n - 1)) ^ "\xe2\x80\xa6" +let plural n w = + let last = if w = "" then ' ' else w.[String.length w - 1] in + let prev = if String.length w < 2 then ' ' else w.[String.length w - 2] in + let form = + if n = 1 then w + else if last = 'y' && not (List.mem prev [ 'a'; 'e'; 'i'; 'o'; 'u' ]) then + String.sub w 0 (String.length w - 1) ^ "ies" + else if List.mem last [ 's'; 'x'; 'z' ] then w ^ "es" + else w ^ "s" + in + Printf.sprintf "%d %s" n form