colorize_rs/
lib.rs

1/*
2Terminal color using ansi escape character for Rust.
3```Rust
4extern crate colorize_rs;
5use colorize_rs::{AnsiColor, Color};
6
7pub fn main() {
8    // Set some global colors
9    colorize_rs::global_fg(Color::Blue);
10    colorize_rs::global_bg(Color::Red);
11    // ^~~~ These settings are reset to default at the end.
12
13    // You can use specific colors or style on a given str,
14    // the globals colors are restored after !
15
16    // Write a green underlined text on a yellow background !
17    println!("{}", "Hello World !".green().underlined().yellowb());
18
19    // Use bright or normal colors
20    println!("{}", "Bright Green foreground and Magenta background !".b_green().magentab());
21}
22```
23*/
24
25use BgColor::*;
26use Color::*;
27use Style::*;
28
29use std::mem;
30
31/// Ansi color to set the global foreground / background color
32#[derive(Clone, Copy)]
33pub enum Color {
34    Black = 30,
35    Red = 31,
36    Green = 32,
37    Yellow = 33,
38    Blue = 34,
39    Magenta = 35,
40    Cyan = 36,
41    Grey = 37,
42    Default = 39,
43    BrightBlack = 90,
44    BrightRed = 91,
45    BrightGreen = 92,
46    BrightYellow = 93,
47    BrightBlue = 94,
48    BrightMagenta = 95,
49    BrightCyan = 96,
50    BrightGrey = 97,
51}
52
53#[derive(Clone, Copy)]
54pub enum BgColor {
55    Blackb = 40,
56    Redb = 41,
57    Greenb = 42,
58    Yellowb = 43,
59    Blueb = 44,
60    Magentab = 45,
61    Cyanb = 46,
62    Greyb = 47,
63    Defaultb = 49,
64    BrightBlackb = 100,
65    BrightRedb = 101,
66    BrightGreenb = 102,
67    BrightYellowb = 103,
68    BrightBlueb = 104,
69    BrightMagentab = 105,
70    BrightCyanb = 106,
71    BrightGreyb = 107,
72}
73
74#[derive(Clone, Copy)]
75pub enum Style {
76    Underscore = 4,
77    Bold = 1,
78    Blink = 5,
79    Reverse = 7,
80    Concealed = 8,
81    Faint = 2,
82    Italic = 3,
83    CrossedOut = 9,
84}
85
86impl internal::TermAttrib for Color {
87    fn to_int(&self) -> i32 {
88        *self as i32
89    }
90}
91
92impl internal::TermAttrib for BgColor {
93    fn to_int(&self) -> i32 {
94        *self as i32
95    }
96}
97
98impl internal::TermAttrib for Style {
99    fn to_int(&self) -> i32 {
100        *self as i32
101    }
102}
103
104impl BgColor {
105    fn from_fg(color: Color) -> BgColor {
106        unsafe { mem::transmute(color as i8 + 10) }
107    }
108}
109
110mod internal {
111    use super::{BgColor, Color};
112    use std::cell::RefCell;
113
114    static DEFAULT_FG: i32 = 39;
115    static DEFAULT_BG: i32 = 49;
116    thread_local!(static GLOB_COLOR: RefCell<GlobalColor> = RefCell::new(GlobalColor {fg: DEFAULT_FG, bg: DEFAULT_BG, enabled: true}));
117
118    pub trait TermAttrib {
119        fn to_int(&self) -> i32;
120    }
121
122    #[derive(Clone)]
123    pub struct GlobalColor {
124        fg: i32,
125        bg: i32,
126        enabled: bool,
127    }
128
129    impl Drop for GlobalColor {
130        fn drop(&mut self) {
131            print!("\x1b[0;{};{}m", DEFAULT_FG, DEFAULT_BG)
132        }
133    }
134
135    fn get_glob() -> (i32, i32, bool) {
136        GLOB_COLOR.with(|cell| {
137            let g = cell.borrow();
138            (g.fg, g.bg, g.enabled)
139        })
140    }
141
142    pub fn global_color(fg_color: Option<Color>, bg_color: Option<BgColor>, enabled: Option<bool>) {
143        GLOB_COLOR.with(|cell| {
144            let mut g = cell.borrow_mut();
145            match fg_color {
146                Some(c) => g.fg = c.to_int(),
147                None => g.fg = g.fg,
148            }
149            match bg_color {
150                Some(c) => g.bg = c.to_int(),
151                None => g.bg = g.bg,
152            }
153            match enabled {
154                Some(c) => g.enabled = c,
155                None => g.enabled = g.enabled,
156            }
157        })
158    }
159
160    pub fn pack<T: TermAttrib>(attrib: T, mut text: String) -> String {
161        if {
162            let (_, _, en) = get_glob();
163            !en
164        } {
165            return text;
166        }
167        if text.as_str().starts_with("\x1b[") {
168            unsafe {
169                text.as_mut_vec().remove(0);
170                text.as_mut_vec().remove(0);
171            }
172            let tmp = text;
173            text = String::from("\x1b[");
174            text.push_str(format!("{};", attrib.to_int()).as_str());
175            text.push_str(tmp.as_str());
176        } else {
177            let tmp = text;
178            text = format!("\x1b[{}m", attrib.to_int());
179            text.push_str(tmp.as_str());
180            let (fg, bg, _) = get_glob();
181            text.push_str(format!("\x1b[0;{};{}m", fg, bg).as_str());
182        }
183        text
184    }
185}
186
187/// Set a custom global foreground color
188pub fn global_fg(color: Color) {
189    internal::global_color(Some(color), None, None)
190}
191
192/// Set a custom global background color
193pub fn global_bg(color: Color) {
194    internal::global_color(None, Some(BgColor::from_fg(color)), None)
195}
196/// Set color to be enabled / disabled
197pub fn color_enabled(enabled: bool) {
198    internal::global_color(None, None, Some(enabled))
199}
200
201/// Reset the background and foreground color to the defaults colors
202pub fn reset() {
203    internal::global_color(Some(Default), Some(Defaultb), None)
204}
205
206/// Methods extension to colorize the text contained in a string
207/// using a simple mathod call
208pub trait AnsiColor {
209    /// Foreground black
210    fn black(self) -> String;
211    /// Foreground red
212    fn red(self) -> String;
213    /// Foreground green
214    fn green(self) -> String;
215    /// Foreground yellow
216    fn yellow(self) -> String;
217    /// Foreground blue
218    fn blue(self) -> String;
219    /// Foreground magenta
220    fn magenta(self) -> String;
221    /// Foreground cyan
222    fn cyan(self) -> String;
223    /// Foreground grey
224    fn grey(self) -> String;
225    /// Foreground black bright
226    fn b_black(self) -> String;
227    /// Foreground red bright
228    fn b_red(self) -> String;
229    /// Foreground green bright
230    fn b_green(self) -> String;
231    /// Foreground yellow bright
232    fn b_yellow(self) -> String;
233    /// Foreground blue bright
234    fn b_blue(self) -> String;
235    /// Foreground magenta bright
236    fn b_magenta(self) -> String;
237    /// Foreground cyan bright
238    fn b_cyan(self) -> String;
239    /// Foreground grey bright
240    fn b_grey(self) -> String;
241    /// Foreground default
242    fn default(self) -> String;
243
244    /// Background black
245    fn blackb(self) -> String;
246    /// Background red
247    fn redb(self) -> String;
248    /// Background green
249    fn greenb(self) -> String;
250    /// Background yellow
251    fn yellowb(self) -> String;
252    /// Background bblue
253    fn blueb(self) -> String;
254    /// Background magenta
255    fn magentab(self) -> String;
256    /// Background cyan
257    fn cyanb(self) -> String;
258    /// Background grey
259    fn greyb(self) -> String;
260    /// Background black bright
261    fn b_blackb(self) -> String;
262    /// Background red bright
263    fn b_redb(self) -> String;
264    /// Background green bright
265    fn b_greenb(self) -> String;
266    /// Background yellow bright
267    fn b_yellowb(self) -> String;
268    /// Background bblue bright
269    fn b_blueb(self) -> String;
270    /// Background magenta bright
271    fn b_magentab(self) -> String;
272    /// Background cyan bright
273    fn b_cyanb(self) -> String;
274    /// Background grey bright
275    fn b_greyb(self) -> String;
276    /// Background default
277    fn defaultb(self) -> String;
278
279    /// Text underlined
280    fn underlined(self) -> String;
281    /// Bold text
282    fn bold(self) -> String;
283    /// Blink tests ( Wonderful )
284    fn blink(self) -> String;
285    /// Reverse mod ON
286    fn reverse(self) -> String;
287    /// Concealed mod ON
288    fn concealed(self) -> String;
289    /// Faint mod ON
290    fn faint(self) -> String;
291    /// Italic text
292    fn italic(self) -> String;
293    /// Crossed out
294    fn crossedout(self) -> String;
295}
296
297impl AnsiColor for String {
298    // Foreground
299    fn black(self) -> String {
300        internal::pack(Black, self)
301    }
302    fn red(self) -> String {
303        internal::pack(Red, self)
304    }
305    fn green(self) -> String {
306        internal::pack(Green, self)
307    }
308    fn yellow(self) -> String {
309        internal::pack(Yellow, self)
310    }
311    fn blue(self) -> String {
312        internal::pack(Blue, self)
313    }
314    fn magenta(self) -> String {
315        internal::pack(Magenta, self)
316    }
317    fn cyan(self) -> String {
318        internal::pack(Cyan, self)
319    }
320    fn grey(self) -> String {
321        internal::pack(Grey, self)
322    }
323    fn b_black(self) -> String {
324        internal::pack(BrightBlack, self)
325    }
326    fn b_red(self) -> String {
327        internal::pack(BrightRed, self)
328    }
329    fn b_green(self) -> String {
330        internal::pack(BrightGreen, self)
331    }
332    fn b_yellow(self) -> String {
333        internal::pack(BrightYellow, self)
334    }
335    fn b_blue(self) -> String {
336        internal::pack(BrightBlue, self)
337    }
338    fn b_magenta(self) -> String {
339        internal::pack(BrightMagenta, self)
340    }
341    fn b_cyan(self) -> String {
342        internal::pack(BrightCyan, self)
343    }
344    fn b_grey(self) -> String {
345        internal::pack(BrightGrey, self)
346    }
347    fn default(self) -> String {
348        internal::pack(Default, self)
349    }
350
351    // Background
352    fn blackb(self) -> String {
353        internal::pack(Blackb, self)
354    }
355    fn redb(self) -> String {
356        internal::pack(Redb, self)
357    }
358    fn greenb(self) -> String {
359        internal::pack(Greenb, self)
360    }
361    fn yellowb(self) -> String {
362        internal::pack(Yellowb, self)
363    }
364    fn blueb(self) -> String {
365        internal::pack(Blueb, self)
366    }
367    fn magentab(self) -> String {
368        internal::pack(Magentab, self)
369    }
370    fn cyanb(self) -> String {
371        internal::pack(Cyanb, self)
372    }
373    fn greyb(self) -> String {
374        internal::pack(Greyb, self)
375    }
376    fn b_blackb(self) -> String {
377        internal::pack(BrightBlackb, self)
378    }
379    fn b_redb(self) -> String {
380        internal::pack(BrightRedb, self)
381    }
382    fn b_greenb(self) -> String {
383        internal::pack(BrightGreenb, self)
384    }
385    fn b_yellowb(self) -> String {
386        internal::pack(BrightYellowb, self)
387    }
388    fn b_blueb(self) -> String {
389        internal::pack(BrightBlueb, self)
390    }
391    fn b_magentab(self) -> String {
392        internal::pack(BrightMagentab, self)
393    }
394    fn b_cyanb(self) -> String {
395        internal::pack(BrightCyanb, self)
396    }
397    fn b_greyb(self) -> String {
398        internal::pack(BrightGreyb, self)
399    }
400    fn defaultb(self) -> String {
401        internal::pack(Defaultb, self)
402    }
403
404    // styles
405    fn underlined(self) -> String {
406        internal::pack(Underscore, self)
407    }
408    fn bold(self) -> String {
409        internal::pack(Bold, self)
410    }
411    fn blink(self) -> String {
412        internal::pack(Blink, self)
413    }
414    fn reverse(self) -> String {
415        internal::pack(Reverse, self)
416    }
417    fn concealed(self) -> String {
418        internal::pack(Concealed, self)
419    }
420    fn faint(self) -> String {
421        internal::pack(Faint, self)
422    }
423    fn italic(self) -> String {
424        internal::pack(Italic, self)
425    }
426    fn crossedout(self) -> String {
427        internal::pack(CrossedOut, self)
428    }
429}
430
431impl AnsiColor for &'static str {
432    // Foreground
433    fn black(self) -> String {
434        String::from(self).black()
435    }
436    fn red(self) -> String {
437        String::from(self).red()
438    }
439    fn green(self) -> String {
440        String::from(self).green()
441    }
442    fn yellow(self) -> String {
443        String::from(self).yellow()
444    }
445    fn blue(self) -> String {
446        String::from(self).blue()
447    }
448    fn magenta(self) -> String {
449        String::from(self).magenta()
450    }
451    fn cyan(self) -> String {
452        String::from(self).cyan()
453    }
454    fn grey(self) -> String {
455        String::from(self).grey()
456    }
457    fn b_black(self) -> String {
458        String::from(self).b_black()
459    }
460    fn b_red(self) -> String {
461        String::from(self).b_red()
462    }
463    fn b_green(self) -> String {
464        String::from(self).b_green()
465    }
466    fn b_yellow(self) -> String {
467        String::from(self).b_yellow()
468    }
469    fn b_blue(self) -> String {
470        String::from(self).b_blue()
471    }
472    fn b_magenta(self) -> String {
473        String::from(self).b_magenta()
474    }
475    fn b_cyan(self) -> String {
476        String::from(self).b_cyan()
477    }
478    fn b_grey(self) -> String {
479        String::from(self).b_grey()
480    }
481    fn default(self) -> String {
482        String::from(self).default()
483    }
484
485    // Background
486    fn blackb(self) -> String {
487        String::from(self).blackb()
488    }
489    fn redb(self) -> String {
490        String::from(self).redb()
491    }
492    fn greenb(self) -> String {
493        String::from(self).greenb()
494    }
495    fn yellowb(self) -> String {
496        String::from(self).yellowb()
497    }
498    fn blueb(self) -> String {
499        String::from(self).blueb()
500    }
501    fn magentab(self) -> String {
502        String::from(self).magentab()
503    }
504    fn cyanb(self) -> String {
505        String::from(self).cyanb()
506    }
507    fn greyb(self) -> String {
508        String::from(self).greyb()
509    }
510    fn b_blackb(self) -> String {
511        String::from(self).b_blackb()
512    }
513    fn b_redb(self) -> String {
514        String::from(self).b_redb()
515    }
516    fn b_greenb(self) -> String {
517        String::from(self).b_greenb()
518    }
519    fn b_yellowb(self) -> String {
520        String::from(self).b_yellowb()
521    }
522    fn b_blueb(self) -> String {
523        String::from(self).b_blueb()
524    }
525    fn b_magentab(self) -> String {
526        String::from(self).b_magentab()
527    }
528    fn b_cyanb(self) -> String {
529        String::from(self).b_cyanb()
530    }
531    fn b_greyb(self) -> String {
532        String::from(self).b_greyb()
533    }
534    fn defaultb(self) -> String {
535        String::from(self).defaultb()
536    }
537
538    // styles
539    fn underlined(self) -> String {
540        String::from(self).underlined()
541    }
542    fn bold(self) -> String {
543        String::from(self).bold()
544    }
545    fn blink(self) -> String {
546        String::from(self).blink()
547    }
548    fn reverse(self) -> String {
549        String::from(self).reverse()
550    }
551    fn concealed(self) -> String {
552        String::from(self).concealed()
553    }
554    fn faint(self) -> String {
555        String::from(self).faint()
556    }
557    fn italic(self) -> String {
558        String::from(self).italic()
559    }
560    fn crossedout(self) -> String {
561        String::from(self).crossedout()
562    }
563}