| 1 | // Copyright (c) 2019-2024 Alexander Medvednikov. All rights reserved. |
| 2 | // Use of this source code is governed by an MIT license |
| 3 | // that can be found in the LICENSE file. |
| 4 | module term |
| 5 | |
| 6 | import strings |
| 7 | |
| 8 | // format_esc produces an ANSI escape code, for selecting the graphics rendition of the following text. |
| 9 | // Each of the attributes that can be passed in `code`, separated by `;`, will be in effect, |
| 10 | // until the terminal encounters another SGR ANSI escape code. For more details about the different |
| 11 | // codes, and their meaning, see: https://en.wikipedia.org/wiki/ANSI_escape_code#SGR_(Select_Graphic_Rendition)_parameters |
| 12 | pub fn format_esc(code string) string { |
| 13 | return '\x1b[${code}m' |
| 14 | } |
| 15 | |
| 16 | // format returns ANSI escape coded `msg` formatted with a preceding `open` and a succeeding `close`. |
| 17 | // For instance, `format('hi', '9', '29')` returns `'\x1b[9mhi\x1b[29m'`, |
| 18 | // or 'hi' with strikethrough, where `'\x1b[9m'` represents |
| 19 | // crossed out/strikethrough text and `'\x1b[29m'` turns off strikethrough. |
| 20 | pub fn format(msg string, open string, close string) string { |
| 21 | return '\x1b[${open}m${msg}\x1b[${close}m' |
| 22 | } |
| 23 | |
| 24 | // format_rgb returns ANSI escape coded `msg` formatted with a preceding `open`, a succeeding `close` and the provided RGB colors `r`, `g`, and `b`. |
| 25 | pub fn format_rgb(r int, g int, b int, msg string, open string, close string) string { |
| 26 | return '\x1b[${open};2;${r};${g};${b}m${msg}\x1b[${close}m' |
| 27 | } |
| 28 | |
| 29 | // rbg returns the `msg` with the foreground in the specified RGB color |
| 30 | // For example, `rgb(0, 255, 0, 'hi')` returns the `'hi'` string in |
| 31 | // lime color. |
| 32 | pub fn rgb(r int, g int, b int, msg string) string { |
| 33 | return format_rgb(r, g, b, msg, '38', '39') |
| 34 | } |
| 35 | |
| 36 | // bg_rgb returns the `msg` with the background in the specified RGB color. |
| 37 | // For example, `bg_rgb(255, 0, 0, 'hi')` returns the text `'hi'` in |
| 38 | // red color. |
| 39 | pub fn bg_rgb(r int, g int, b int, msg string) string { |
| 40 | return format_rgb(r, g, b, msg, '48', '49') |
| 41 | } |
| 42 | |
| 43 | // hex returns the `msg` with the foreground in the specified `hex` color. |
| 44 | // For example, `rgb(255, 'hi')` returns the `'hi'` string in |
| 45 | // blue color, which is `(0, 0, 255)` in RGB. |
| 46 | pub fn hex(hex int, msg string) string { |
| 47 | return format_rgb(hex >> 16, (hex >> 8) & 0xFF, hex & 0xFF, msg, '38', '39') |
| 48 | } |
| 49 | |
| 50 | // hex returns the `msg` with the background in the specified `hex` color. |
| 51 | // For example, `bg_rgb(255, 'hi')` returns the `'hi'` string in |
| 52 | // a background of blue color, which is `(0, 0, 255)` in RGB. |
| 53 | pub fn bg_hex(hex int, msg string) string { |
| 54 | return format_rgb(hex >> 16, (hex >> 8) & 0xFF, hex & 0xFF, msg, '48', '49') |
| 55 | } |
| 56 | |
| 57 | // reset resets all formatting for `msg`. |
| 58 | pub fn reset(msg string) string { |
| 59 | return format(msg, '0', '0') |
| 60 | } |
| 61 | |
| 62 | // bold returns the given `msg` in bold. |
| 63 | pub fn bold(msg string) string { |
| 64 | return format(msg, '1', '22') |
| 65 | } |
| 66 | |
| 67 | // dim returns the dimmed `msg`. |
| 68 | pub fn dim(msg string) string { |
| 69 | return format(msg, '2', '22') |
| 70 | } |
| 71 | |
| 72 | // italic returns the given `msg` in italic. |
| 73 | pub fn italic(msg string) string { |
| 74 | return format(msg, '3', '23') |
| 75 | } |
| 76 | |
| 77 | // underline returns the underlined `msg`. |
| 78 | pub fn underline(msg string) string { |
| 79 | return format(msg, '4', '24') |
| 80 | } |
| 81 | |
| 82 | // slow_blink will surround the `msg` with ANSI escape codes for blinking (less than 150 times per minute). |
| 83 | pub fn slow_blink(msg string) string { |
| 84 | return format(msg, '5', '25') |
| 85 | } |
| 86 | |
| 87 | // rapid_blink will surround the `msg` with ANSI escape codes for blinking (over 150 times per minute). |
| 88 | // Note that unlike slow_blink, this is not very widely supported. |
| 89 | pub fn rapid_blink(msg string) string { |
| 90 | return format(msg, '6', '26') |
| 91 | } |
| 92 | |
| 93 | // inverse inverses the given `msg`. |
| 94 | pub fn inverse(msg string) string { |
| 95 | return format(msg, '7', '27') |
| 96 | } |
| 97 | |
| 98 | // hidden hides the given `msg`. |
| 99 | pub fn hidden(msg string) string { |
| 100 | return format(msg, '8', '28') |
| 101 | } |
| 102 | |
| 103 | // strikethrough returns the given `msg` in strikethrough. |
| 104 | pub fn strikethrough(msg string) string { |
| 105 | return format(msg, '9', '29') |
| 106 | } |
| 107 | |
| 108 | // black formats the `msg` in black. |
| 109 | pub fn black(msg string) string { |
| 110 | return format(msg, '30', '39') |
| 111 | } |
| 112 | |
| 113 | // red formats the `msg` in red. |
| 114 | pub fn red(msg string) string { |
| 115 | return format(msg, '31', '39') |
| 116 | } |
| 117 | |
| 118 | // green formats the `msg` in green. |
| 119 | pub fn green(msg string) string { |
| 120 | return format(msg, '32', '39') |
| 121 | } |
| 122 | |
| 123 | // yellow formats the `msg` in yellow. |
| 124 | pub fn yellow(msg string) string { |
| 125 | return format(msg, '33', '39') |
| 126 | } |
| 127 | |
| 128 | // blue formats the `msg` in blue. |
| 129 | pub fn blue(msg string) string { |
| 130 | return format(msg, '34', '39') |
| 131 | } |
| 132 | |
| 133 | // magenta formats the `msg` in magenta. |
| 134 | pub fn magenta(msg string) string { |
| 135 | return format(msg, '35', '39') |
| 136 | } |
| 137 | |
| 138 | // cyan formats the `msg` in cyan. |
| 139 | pub fn cyan(msg string) string { |
| 140 | return format(msg, '36', '39') |
| 141 | } |
| 142 | |
| 143 | // white formats the `msg` in white. |
| 144 | pub fn white(msg string) string { |
| 145 | return format(msg, '37', '39') |
| 146 | } |
| 147 | |
| 148 | // bg_black formats the `msg` in black background. |
| 149 | pub fn bg_black(msg string) string { |
| 150 | return format(msg, '40', '49') |
| 151 | } |
| 152 | |
| 153 | // bg_red formats the `msg` in red background. |
| 154 | pub fn bg_red(msg string) string { |
| 155 | return format(msg, '41', '49') |
| 156 | } |
| 157 | |
| 158 | // bg_green formats the `msg` in green background. |
| 159 | pub fn bg_green(msg string) string { |
| 160 | return format(msg, '42', '49') |
| 161 | } |
| 162 | |
| 163 | // bg_yellow formats the `msg` in yellow background. |
| 164 | pub fn bg_yellow(msg string) string { |
| 165 | return format(msg, '43', '49') |
| 166 | } |
| 167 | |
| 168 | // bg_blue formats the `msg` in blue background. |
| 169 | pub fn bg_blue(msg string) string { |
| 170 | return format(msg, '44', '49') |
| 171 | } |
| 172 | |
| 173 | // bg_magenta formats the `msg` in magenta background. |
| 174 | pub fn bg_magenta(msg string) string { |
| 175 | return format(msg, '45', '49') |
| 176 | } |
| 177 | |
| 178 | // bg_cyan formats the `msg` in cyan background. |
| 179 | pub fn bg_cyan(msg string) string { |
| 180 | return format(msg, '46', '49') |
| 181 | } |
| 182 | |
| 183 | // bg_white formats the `msg` in white background. |
| 184 | pub fn bg_white(msg string) string { |
| 185 | return format(msg, '47', '49') |
| 186 | } |
| 187 | |
| 188 | // gray formats the `msg` in gray (equivalent to `bright_black`). |
| 189 | pub fn gray(msg string) string { |
| 190 | return bright_black(msg) |
| 191 | } |
| 192 | |
| 193 | // bright_black formats the `msg` in bright black. |
| 194 | pub fn bright_black(msg string) string { |
| 195 | return format(msg, '90', '39') |
| 196 | } |
| 197 | |
| 198 | // bright_red formats the `msg` in bright red. |
| 199 | pub fn bright_red(msg string) string { |
| 200 | return format(msg, '91', '39') |
| 201 | } |
| 202 | |
| 203 | // bright_green formats the `msg` in bright green. |
| 204 | pub fn bright_green(msg string) string { |
| 205 | return format(msg, '92', '39') |
| 206 | } |
| 207 | |
| 208 | // bright_yellow formats the `msg` in bright yellow. |
| 209 | pub fn bright_yellow(msg string) string { |
| 210 | return format(msg, '93', '39') |
| 211 | } |
| 212 | |
| 213 | // bright_blue formats the `msg` in bright blue. |
| 214 | pub fn bright_blue(msg string) string { |
| 215 | return format(msg, '94', '39') |
| 216 | } |
| 217 | |
| 218 | // bright_magenta formats the `msg` in bright magenta. |
| 219 | pub fn bright_magenta(msg string) string { |
| 220 | return format(msg, '95', '39') |
| 221 | } |
| 222 | |
| 223 | // bright_cyan formats the `msg` in bright cyan. |
| 224 | pub fn bright_cyan(msg string) string { |
| 225 | return format(msg, '96', '39') |
| 226 | } |
| 227 | |
| 228 | // bright_white formats the `msg` in bright white. |
| 229 | pub fn bright_white(msg string) string { |
| 230 | return format(msg, '97', '39') |
| 231 | } |
| 232 | |
| 233 | // bright_bg_black formats the `msg` in bright black background. |
| 234 | pub fn bright_bg_black(msg string) string { |
| 235 | return format(msg, '100', '49') |
| 236 | } |
| 237 | |
| 238 | // bright_bg_red formats the `msg` in bright red background. |
| 239 | pub fn bright_bg_red(msg string) string { |
| 240 | return format(msg, '101', '49') |
| 241 | } |
| 242 | |
| 243 | // bright_bg_green formats the `msg` in bright green background. |
| 244 | pub fn bright_bg_green(msg string) string { |
| 245 | return format(msg, '102', '49') |
| 246 | } |
| 247 | |
| 248 | // bright_bg_yellow formats the `msg` in bright yellow background. |
| 249 | pub fn bright_bg_yellow(msg string) string { |
| 250 | return format(msg, '103', '49') |
| 251 | } |
| 252 | |
| 253 | // bright_bg_blue formats the `msg` in bright blue background. |
| 254 | pub fn bright_bg_blue(msg string) string { |
| 255 | return format(msg, '104', '49') |
| 256 | } |
| 257 | |
| 258 | // bright_bg_magenta formats the `msg` in bright magenta background. |
| 259 | pub fn bright_bg_magenta(msg string) string { |
| 260 | return format(msg, '105', '49') |
| 261 | } |
| 262 | |
| 263 | // bright_bg_cyan formats the `msg` in bright cyan background. |
| 264 | pub fn bright_bg_cyan(msg string) string { |
| 265 | return format(msg, '106', '49') |
| 266 | } |
| 267 | |
| 268 | // bright_bg_white formats the `msg` in bright white background. |
| 269 | pub fn bright_bg_white(msg string) string { |
| 270 | return format(msg, '107', '49') |
| 271 | } |
| 272 | |
| 273 | // highlight_command highlights the command with an on-brand background to make CLI commands immediately recognizable. |
| 274 | pub fn highlight_command(command string) string { |
| 275 | return bright_white(bg_cyan(' ${command} ')) |
| 276 | } |
| 277 | |
| 278 | pub enum TextStyle { |
| 279 | bold = 1 |
| 280 | dim = 2 |
| 281 | italic = 3 |
| 282 | underline = 4 |
| 283 | blink = 5 |
| 284 | reverse = 7 |
| 285 | } |
| 286 | |
| 287 | pub enum FgColor { |
| 288 | black = 30 |
| 289 | red = 31 |
| 290 | green = 32 |
| 291 | yellow = 33 |
| 292 | blue = 34 |
| 293 | magenta = 35 |
| 294 | cyan = 36 |
| 295 | white = 37 |
| 296 | } |
| 297 | |
| 298 | pub enum BgColor { |
| 299 | black = 40 |
| 300 | red = 41 |
| 301 | green = 42 |
| 302 | yellow = 43 |
| 303 | blue = 44 |
| 304 | magenta = 45 |
| 305 | cyan = 46 |
| 306 | white = 47 |
| 307 | } |
| 308 | |
| 309 | @[params] |
| 310 | pub struct ColorConfig { |
| 311 | pub mut: |
| 312 | styles []TextStyle |
| 313 | fg ?FgColor |
| 314 | bg ?BgColor |
| 315 | custom string |
| 316 | } |
| 317 | |
| 318 | // write_color appends the ANSI colorful string `s` to the buffer. |
| 319 | pub fn write_color(mut b strings.Builder, s string, config ColorConfig) { |
| 320 | mut codes := []string{cap: 3} |
| 321 | |
| 322 | for style in config.styles { |
| 323 | codes << int(style).str() |
| 324 | } |
| 325 | |
| 326 | if fg := config.fg { |
| 327 | codes << int(fg).str() |
| 328 | } |
| 329 | |
| 330 | if bg := config.bg { |
| 331 | codes << int(bg).str() |
| 332 | } |
| 333 | |
| 334 | if config.custom != '' { |
| 335 | codes << config.custom |
| 336 | } |
| 337 | |
| 338 | if codes.len > 0 { |
| 339 | code_str := codes.join(';') |
| 340 | b.write_string('\x1b[${code_str}m${s}\x1b[0m') |
| 341 | } else { |
| 342 | b.write_string(s) |
| 343 | } |
| 344 | } |
| 345 | |
| 346 | // writeln_color appends the ANSI colorful string `s`, and then a newline character. |
| 347 | pub fn writeln_color(mut b strings.Builder, s string, color ColorConfig) { |
| 348 | write_color(mut b, s, color) |
| 349 | b.writeln('') |
| 350 | } |
| 351 | |