1 //! The `Style` type is a simplified view of the various 2 //! attributes offered by the `term` library. These are 3 //! enumerated as bits so they can be easily or'd together 4 //! etc. 5 6 use std::default::Default; 7 use term::{self, Terminal}; 8 9 #[derive(Copy, Clone, Default, PartialEq, Eq)] 10 pub struct Style { 11 bits: u64, 12 } 13 14 macro_rules! declare_styles { 15 ($($style:ident,)*) => { 16 #[derive(Copy, Clone)] 17 #[allow(non_camel_case_types)] 18 enum StyleBit { 19 $($style,)* 20 } 21 22 $( 23 pub const $style: Style = Style { bits: 1 << (StyleBit::$style as u64) }; 24 )* 25 } 26 } 27 28 pub const DEFAULT: Style = Style { bits: 0 }; 29 30 declare_styles! { 31 // Foreground colors: 32 FG_BLACK, 33 FG_BLUE, 34 FG_BRIGHT_BLACK, 35 FG_BRIGHT_BLUE, 36 FG_BRIGHT_CYAN, 37 FG_BRIGHT_GREEN, 38 FG_BRIGHT_MAGENTA, 39 FG_BRIGHT_RED, 40 FG_BRIGHT_WHITE, 41 FG_BRIGHT_YELLOW, 42 FG_CYAN, 43 FG_GREEN, 44 FG_MAGENTA, 45 FG_RED, 46 FG_WHITE, 47 FG_YELLOW, 48 49 // Background colors: 50 BG_BLACK, 51 BG_BLUE, 52 BG_BRIGHT_BLACK, 53 BG_BRIGHT_BLUE, 54 BG_BRIGHT_CYAN, 55 BG_BRIGHT_GREEN, 56 BG_BRIGHT_MAGENTA, 57 BG_BRIGHT_RED, 58 BG_BRIGHT_WHITE, 59 BG_BRIGHT_YELLOW, 60 BG_CYAN, 61 BG_GREEN, 62 BG_MAGENTA, 63 BG_RED, 64 BG_WHITE, 65 BG_YELLOW, 66 67 // Other: 68 BOLD, 69 DIM, 70 ITALIC, 71 UNDERLINE, 72 BLINK, 73 STANDOUT, 74 REVERSE, 75 SECURE, 76 } 77 78 impl Style { new() -> Style79 pub fn new() -> Style { 80 Style::default() 81 } 82 with(self, other_style: Style) -> Style83 pub fn with(self, other_style: Style) -> Style { 84 Style { 85 bits: self.bits | other_style.bits, 86 } 87 } 88 contains(self, other_style: Style) -> bool89 pub fn contains(self, other_style: Style) -> bool { 90 self.with(other_style) == self 91 } 92 93 /// Attempts to apply the given style to the given terminal. If 94 /// the style is not supported, either there is no effect or else 95 /// a similar, substitute style may be applied. apply<T: Terminal + ?Sized>(self, term: &mut T) -> term::Result<()>96 pub fn apply<T: Terminal + ?Sized>(self, term: &mut T) -> term::Result<()> { 97 term.reset()?; 98 99 macro_rules! fg_color { 100 ($color:expr, $term_color:ident) => { 101 if self.contains($color) { 102 if term.supports_color() { 103 term.fg(term::color::$term_color)?; 104 } 105 } 106 }; 107 } 108 109 fg_color!(FG_BLACK, BLACK); 110 fg_color!(FG_BLUE, BLUE); 111 fg_color!(FG_BRIGHT_BLACK, BRIGHT_BLACK); 112 fg_color!(FG_BRIGHT_BLUE, BRIGHT_BLUE); 113 fg_color!(FG_BRIGHT_CYAN, BRIGHT_CYAN); 114 fg_color!(FG_BRIGHT_GREEN, BRIGHT_GREEN); 115 fg_color!(FG_BRIGHT_MAGENTA, BRIGHT_MAGENTA); 116 fg_color!(FG_BRIGHT_RED, BRIGHT_RED); 117 fg_color!(FG_BRIGHT_WHITE, BRIGHT_WHITE); 118 fg_color!(FG_BRIGHT_YELLOW, BRIGHT_YELLOW); 119 fg_color!(FG_CYAN, CYAN); 120 fg_color!(FG_GREEN, GREEN); 121 fg_color!(FG_MAGENTA, MAGENTA); 122 fg_color!(FG_RED, RED); 123 fg_color!(FG_WHITE, WHITE); 124 fg_color!(FG_YELLOW, YELLOW); 125 126 macro_rules! bg_color { 127 ($color:expr, $term_color:ident) => { 128 if self.contains($color) { 129 if term.supports_color() { 130 term.bg(term::color::$term_color)?; 131 } 132 } 133 }; 134 } 135 136 bg_color!(BG_BLACK, BLACK); 137 bg_color!(BG_BLUE, BLUE); 138 bg_color!(BG_BRIGHT_BLACK, BRIGHT_BLACK); 139 bg_color!(BG_BRIGHT_BLUE, BRIGHT_BLUE); 140 bg_color!(BG_BRIGHT_CYAN, BRIGHT_CYAN); 141 bg_color!(BG_BRIGHT_GREEN, BRIGHT_GREEN); 142 bg_color!(BG_BRIGHT_MAGENTA, BRIGHT_MAGENTA); 143 bg_color!(BG_BRIGHT_RED, BRIGHT_RED); 144 bg_color!(BG_BRIGHT_WHITE, BRIGHT_WHITE); 145 bg_color!(BG_BRIGHT_YELLOW, BRIGHT_YELLOW); 146 bg_color!(BG_CYAN, CYAN); 147 bg_color!(BG_GREEN, GREEN); 148 bg_color!(BG_MAGENTA, MAGENTA); 149 bg_color!(BG_RED, RED); 150 bg_color!(BG_WHITE, WHITE); 151 bg_color!(BG_YELLOW, YELLOW); 152 153 macro_rules! attr { 154 ($attr:expr, $term_attr:expr) => { 155 if self.contains($attr) { 156 let attr = $term_attr; 157 if term.supports_attr(attr) { 158 term.attr(attr)?; 159 } 160 } 161 }; 162 } 163 164 attr!(BOLD, term::Attr::Bold); 165 attr!(DIM, term::Attr::Dim); 166 attr!(ITALIC, term::Attr::Italic(true)); 167 attr!(UNDERLINE, term::Attr::Underline(true)); 168 attr!(BLINK, term::Attr::Blink); 169 attr!(STANDOUT, term::Attr::Standout(true)); 170 attr!(REVERSE, term::Attr::Reverse); 171 attr!(SECURE, term::Attr::Secure); 172 173 Ok(()) 174 } 175 } 176 177 /////////////////////////////////////////////////////////////////////////// 178 179 pub struct StyleCursor<'term, T: ?Sized + Terminal> { 180 current_style: Style, 181 term: &'term mut T, 182 } 183 184 impl<'term, T: ?Sized + Terminal> StyleCursor<'term, T> { new(term: &'term mut T) -> term::Result<StyleCursor<'term, T>>185 pub fn new(term: &'term mut T) -> term::Result<StyleCursor<'term, T>> { 186 let current_style = Style::default(); 187 current_style.apply(term)?; 188 Ok(StyleCursor { 189 current_style: current_style, 190 term: term, 191 }) 192 } 193 term(&mut self) -> &mut T194 pub fn term(&mut self) -> &mut T { 195 self.term 196 } 197 set_style(&mut self, style: Style) -> term::Result<()>198 pub fn set_style(&mut self, style: Style) -> term::Result<()> { 199 if style != self.current_style { 200 style.apply(self.term)?; 201 self.current_style = style; 202 } 203 Ok(()) 204 } 205 } 206