1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179
//! Wrapper crate for [`termcolor_output_impl`] procedural macro. //! //! The reason for this code to be split into two crates is simple: we want to make //! this functionality available on stable. In fact, this dual-crate system is simply //! the manual implementation of the code generated by [`proc_macro_hack`]. //! //! ## What is it //! //! The [`termcolor`] crate is a cross-platform implementation for the different console //! APIs, abstracting away both Linux terminals and Windows consoles. It has, however, //! a but cumbersome API itself (only a bit though), since for formatting-heavy parts //! we have to litter our code with explicit styling commands. This crate allows to //! abstract these things away, providing the interface similar to the standard [`write!`] //! macro. //! //! [`termcolor_output_impl`]: http://crates.io/crates/termcolor_output_impl //! [`proc_macro_hack`]: http://github.com/dtolnay/proc-macro-hack //! [`termcolor`]: http://docs.rs/termcolor //! [`write!`]: https://doc.rust-lang.org/stable/std/macro.write.html trait ColoredOutput {} mod seal { pub trait Seal {} impl<T: termcolor::WriteColor> Seal for T {} } /// Extension trait for [`WriteColor`] instances. /// /// This trait is not intended for public use. Its only purpose is to allow us check if the /// provided value implements [`WriteColor`] in an ergonomic way, without consuming the value if /// unnecessary, and it is used internally by the [`colored`] macro. /// /// You'll probably see this trait only in type errors, if the first argument to the macro appears /// to be of the wrong type. /// /// ## Example /// /// ```compile_fail /// use termcolor_output::colored; /// # fn main() -> Result<(), Box<dyn std::error::Error>> { /// colored!(0u8, "This won't be written")?; /// # Ok(()) /// # } /// ``` /// /// This example yields the following error: /// ```text /// error[E0599]: no method named `guard` found for type `u8` in the current scope /// --> src/lib.rs:37:1 /// | /// 5 | colored!(0u8, "This won't be written")?; /// | ^^^ /// | /// = note: the method `guard` exists but the following trait bounds were not satisfied: /// `u8 : termcolor_output::WriteColorGuard` /// ``` /// /// This trait is implemented on everything that implements `WriteColor` and sealed, so that it /// can't be implemented elsewhere. /// /// [`WriteColor`]: https://docs.rs/termcolor/1.0.5/termcolor/trait.WriteColor.html /// [`colored`]: colored pub trait WriteColorGuard: seal::Seal { fn guard(&mut self) -> &mut Self { self } } impl<T: termcolor::WriteColor> WriteColorGuard for T {} #[doc(hidden)] pub use std; #[doc(hidden)] pub use termcolor; #[doc(hidden)] pub use termcolor_output_impl; /// The macro writing colored text. /// /// Like the standard [`write!`] macro, it takes the writer, format string and the sequence of /// arguments. The arguments may be either formattable with the corresponding formatter (`Display` /// for `{}`, `Debug` for `{:?}`, etc.), or the _control sequences_, which are written in /// macro-like style: /// - `reset!()` yields call to [`ColorSpec::clear`][termcolor::ColorSpec::clear]; /// - `fg!(color)`, `bg!(color)`, `bold!(bool)`, `underline!(bool)` and `intense!(bool)` are /// translated into corresponding `ColorSpec::set_*` calls with the provided arguments. /// /// Internally, this expands to the following: /// - imports of all necessary traits; /// - call to the `guard` method on the [`WriteColorGuard`] trait (as a sanity check); /// - an immediately called closure, containing: /// - creation of `ColorSpec`; /// - calls to `write!` for every formattable input; /// - updates for `ColorSpec` for every control sequence. /// Every error generated inside the closure is returned early and yielded by the macro as an /// [`std::io::Result<()>`]. /// /// When the arguments list is malformed, macro generates a compile error trying to point on the /// exact origin. /// /// ## Examples /// /// Simple formatting is provided in exactly the same way as for standard writes: /// ``` /// # use termcolor_output::colored; /// # fn write(writer: &mut impl termcolor::WriteColor) { /// colored!(writer, "This text is {} styled", "not").unwrap(); /// # } /// ``` /// /// Styled formatting is provided by using any formatter argument in format string, wherever you /// need to apply the style: /// ``` /// # use termcolor_output::colored; /// # fn write(writer: &mut impl termcolor::WriteColor) { /// # use termcolor::Color; /// colored!(writer, "This text is not styled\n{}And this is colored", fg!(Some(Color::Blue))).unwrap(); /// # } /// ``` /// /// You can chain several styling commands by specifying several formatter arguments without text /// between them: /// ``` /// # use termcolor_output::colored; /// # fn write(writer: &mut impl termcolor::WriteColor) { /// # use termcolor::Color; /// colored!( /// writer, /// "{}{}{}This text is bold blue on yellow background /// {}{}{}And this has default colors, but is bold and underlined", /// fg!(Some(Color::Blue)), bg!(Some(Color::Yellow)), bold!(true), /// fg!(None), bg!(None), underline!(true), /// ).unwrap(); /// # } /// ``` /// Note that the `bold` being set in the first block of control sequences is preserved after the /// second one. /// /// And, of course, you can mix ordinary formatting outputs with the control sequences: /// /// ``` /// # use termcolor_output::colored; /// # fn write(writer: &mut impl termcolor::WriteColor) { /// # use termcolor::Color; /// colored!(writer, "{}{:?}{} unwraps to {}", bold!(true), Some(0), bold!(false), 0).unwrap(); /// # } /// ``` /// /// [`write!`]: https://doc.rust-lang.org/std/macro.write.html /// [`std::io::Result<()>`]: https://doc.rust-lang.org/std/io/type.Result.html #[macro_export] macro_rules! colored { ($($arg:tt)*) => {{ use $crate::termcolor_output_impl::ColoredOutput; use $crate::termcolor::WriteColor; use $crate::std::io::Write; use $crate::WriteColorGuard; #[derive(ColoredOutput)] enum __Writer { Data = (stringify!($($arg)*), 0).1 } colored_impl!() }} } /// A convenience function, serving the role of `writeln!` macro. /// /// This function accepts a closure containing all necessary [`colored`]! calls. /// It will clear the writer style, run the closure, clear the writer style again /// and write a newline. #[allow(unused_imports)] pub fn colored_ln<W: termcolor::WriteColor, F: FnOnce(&mut W) -> std::io::Result<()>>( buf: &mut W, func: F, ) -> std::io::Result<()> { colored!(buf, "{}", reset!())?; func(buf)?; colored!(buf, "{}\n", reset!()) }