1 //! Defines the macros for repetitive styling implementations 2 3 // There's a single core set of macros structure here that's essentially repeated twice; once for 4 // implementing `Styler` and once for `Colorize`. We'll go through `Styler` as the example, knowing 5 // that `Colorize` works in precisely the same manner. 6 // 7 // There are four macros in each group. For `Styler`, they are: 8 // * def_attr_base, 9 // * def_attr_generic, 10 // * impl_styler_callback, 11 // * impl_styler 12 // 13 // Fundamentally, any implementation works in a similar fashion; many methods with near-identical 14 // bodies are grouped together. There are additionally two types of implementors: so-called "base" 15 // implementors (`char`, `String`, etc.) and a single "generic" implementor - 'StyledContent<D>'. 16 // 17 // We can visualize the macro expansion with a sort of pipeline: 18 // 19 // /--------> def_attr_base 20 // [impl_styler ->] impl_styler_callback 21 // \--------> def_attr_generic 22 // 23 // The code-gen starts at 'impl_styler' for "base" implementors, and at 'impl_styler_callback' for 24 // `StyledContent<D>`. From there, 'impl_styler_callback' either repeatedly calls 'def_attr_base' 25 // or 'def_attr_generic' - this is determined by the 'callback' argument. 26 // 27 // 'def_attr_base' is used to provide the method bodies for base types, and 'def_attr_generic' 28 // provides the method bodies for 'StyledContent<D>'. 29 30 //////////////////////////////////////////////////////////////////////////////// 31 // `Styler` macros // 32 //////////////////////////////////////////////////////////////////////////////// 33 34 // Produces a single method for a "base" Styler implementation 35 // 36 // The first argument is the type for which Styler is being implemented. Because this is the same 37 // for all "base" types, we can collase them into a single macro. 38 macro_rules! def_attr_base { 39 ($impl_ty:ty, $name:ident => $attr:path) => { 40 fn $name(self) -> StyledContent<$impl_ty> { 41 StyledContent::new( 42 ContentStyle { 43 attributes: $attr.into(), 44 ..Default::default() 45 }, 46 self, 47 ) 48 } 49 }; 50 } 51 52 // Produces a single method within an implementation of Styler for 'StyledContent<D>' 53 // 54 // We give it an empty argument at the start so that it has the same "signature" as 55 // 'def_attr_base', which takes a type as its first argument 56 macro_rules! def_attr_generic { 57 ((), $name:ident => $attr:path) => { 58 fn $name(self) -> StyledContent<D> { 59 self.attribute($attr) 60 } 61 }; 62 } 63 64 // Produces the set of methods inside the implementation, but not the outer block itself 65 // 66 // 'callback' should be either one of 'def_attr_base' or 'def_attr_generic'. Each expansion of 67 // 'callback' produces a single method with the name given by the second argument. 68 macro_rules! impl_styler_callback { 69 ($callback:ident!($args:tt)) => { 70 $callback!($args, reset => Attribute::Reset); 71 $callback!($args, bold => Attribute::Bold); 72 $callback!($args, underlined => Attribute::Underlined); 73 $callback!($args, reverse => Attribute::Reverse); 74 $callback!($args, dim => Attribute::Dim); 75 $callback!($args, italic => Attribute::Italic); 76 $callback!($args, negative => Attribute::Reverse); 77 $callback!($args, slow_blink => Attribute::SlowBlink); 78 $callback!($args, rapid_blink => Attribute::RapidBlink); 79 $callback!($args, hidden => Attribute::Hidden); 80 $callback!($args, crossed_out => Attribute::CrossedOut); 81 } 82 } 83 84 // Produces the full implementation of Styler for "base" types 85 // 86 // This macro is mostly here for convenience; it's nice to not require writing out the 87 // `impl Styler<..> for ..` for each base type. 88 macro_rules! impl_styler { 89 ($impl_ty:ty) => { 90 impl Styler<$impl_ty> for $impl_ty { 91 impl_styler_callback!(def_attr_base!($impl_ty)); 92 } 93 }; 94 } 95 96 //////////////////////////////////////////////////////////////////////////////// 97 // `Colorize` macros // 98 // // 99 // These are effectively the same as the `Styler` macros described above, so // 100 // not much detail is repeated here. Where above we have 'def_attr_*', there // 101 // is 'def_color_*' here, and 'impl_colorize' takes the place of // 102 // 'impl_styler'. // 103 //////////////////////////////////////////////////////////////////////////////// 104 105 macro_rules! def_color_base { 106 ($color_ty:ty, $side:ident: $name:ident => $color:path) => { 107 fn $name(self) -> StyledContent<$color_ty> { 108 StyledContent::new( 109 ContentStyle { 110 $side: Some($color), 111 ..Default::default() 112 }, 113 self, 114 ) 115 } 116 }; 117 } 118 119 macro_rules! def_color_generic { 120 ((), $side:ident: $name:ident => $color:path) => { 121 fn $name(self) -> StyledContent<D> { 122 StyledContent::new( 123 ContentStyle { 124 $side: Some($color), 125 ..self.style 126 }, 127 self.content, 128 ) 129 } 130 }; 131 } 132 133 macro_rules! impl_colorize_callback { 134 ($callback:ident!($args:tt)) => { 135 // foreground colors 136 $callback!($args, foreground_color: black => Color::Black); 137 $callback!($args, foreground_color: dark_grey => Color::DarkGrey); 138 $callback!($args, foreground_color: red => Color::Red); 139 $callback!($args, foreground_color: dark_red => Color::DarkRed); 140 $callback!($args, foreground_color: green => Color::Green); 141 $callback!($args, foreground_color: dark_green => Color::DarkGreen); 142 $callback!($args, foreground_color: yellow => Color::Yellow); 143 $callback!($args, foreground_color: dark_yellow => Color::DarkYellow); 144 $callback!($args, foreground_color: blue => Color::Blue); 145 $callback!($args, foreground_color: dark_blue => Color::DarkBlue); 146 $callback!($args, foreground_color: magenta => Color::Magenta); 147 $callback!($args, foreground_color: dark_magenta => Color::DarkMagenta); 148 $callback!($args, foreground_color: cyan => Color::Cyan); 149 $callback!($args, foreground_color: dark_cyan => Color::DarkCyan); 150 $callback!($args, foreground_color: white => Color::White); 151 $callback!($args, foreground_color: grey => Color::Grey); 152 153 // background colors 154 $callback!($args, background_color: on_black => Color::Black); 155 $callback!($args, background_color: on_dark_grey => Color::DarkGrey); 156 $callback!($args, background_color: on_red => Color::Red); 157 $callback!($args, background_color: on_dark_red => Color::DarkRed); 158 $callback!($args, background_color: on_green => Color::Green); 159 $callback!($args, background_color: on_dark_green => Color::DarkGreen); 160 $callback!($args, background_color: on_yellow => Color::Yellow); 161 $callback!($args, background_color: on_dark_yellow => Color::DarkYellow); 162 $callback!($args, background_color: on_blue => Color::Blue); 163 $callback!($args, background_color: on_dark_blue => Color::DarkBlue); 164 $callback!($args, background_color: on_magenta => Color::Magenta); 165 $callback!($args, background_color: on_dark_magenta => Color::DarkMagenta); 166 $callback!($args, background_color: on_cyan => Color::Cyan); 167 $callback!($args, background_color: on_dark_cyan => Color::DarkCyan); 168 $callback!($args, background_color: on_white => Color::White); 169 $callback!($args, background_color: on_grey => Color::Grey); 170 }; 171 } 172 173 macro_rules! impl_colorize { 174 ($impl_ty:ty) => { 175 impl Colorize<$impl_ty> for $impl_ty { 176 impl_colorize_callback!(def_color_base!($impl_ty)); 177 } 178 }; 179 } 180