ansi/lib.rs
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 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360
//! This crate provides a wrapper around the underlying imgui implementation.
#![deny(missing_docs)]
#![deny(unused_results)]
#![deny(rust_2018_idioms)]
use lazy_static::lazy_static;
use std::fmt::{Display, Formatter};
lazy_static! {
static ref ENABLED: bool = {
// The double-negative is not ideal, but this is the "common" pattern with
// CLI tooling; usually NOCOLOR or NO_COLOR can disable formatting.
// This checks if this is set to a positive value, otherwise defaults to
// assuming that this is enabled.
if let Ok(value) = std::env::var("NOCOLOR") {
!is_true_str(value.as_str())
} else if let Ok(value) = std::env::var("NO_COLOR") {
!is_true_str(value.as_str())
} else {
// Assume default enabled
true
}
};
}
#[inline]
fn is_true_str(s: &str) -> bool {
matches!(s, "true" | "TRUE" | "1")
}
/// The ANSI Escape character, which is octal 033.
const ESCAPE: char = 0o33 as char;
/// Represents an ANSI Attribute value. This is always a 1-byte op-code.
pub struct Attribute(pub(crate) u8);
impl Display for Attribute {
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
write!(f, "{}[{}m", ESCAPE, self.0)
}
}
/// A crate for containing various ANSI formatting elements.
///
/// This is organized into two sub-modules: [`bg`] for background colors, and
/// [`fg`] for foreground colors. Root level formatting operations like bolding,
/// font-style, etc are all in this [`fmt`] root module.
pub mod fmt {
use super::*;
/// All attributes become turned off.
pub const RESET: Attribute = Attribute(0);
/// Bold or increased intensity.
pub const BOLD: Attribute = Attribute(1);
/// Faint, decreased intensity, or dim.
pub const DIM: Attribute = Attribute(2);
/// Makes text italicized.
///
/// # Platform Support
///
/// Not widely supported. Sometimes treated as inverse or blink.
pub const ITALIC: Attribute = Attribute(3);
/// Underlines the text.
///
/// # Platform Support
///
/// Style extensions exist for Kitty, VTE, mintty, iTerm2 and Konsole.
pub const UNDERLINE: Attribute = Attribute(4);
/// Sets blinking to less than 150 times per minute.
///
/// # Platform Support
///
/// Widely supported
pub const SLOW_BLINK: Attribute = Attribute(5);
/// Sets blinking to more than 150 times per minute.
///
/// # Platform Support
///
/// Not widely supported.
pub const RAPID_BLINK: Attribute = Attribute(6);
/// Conceals or hides the text.
///
/// # Platform Support
///
/// Not widely supported.
pub const CONCEAL: Attribute = Attribute(8);
/// Reveals previously concealed or hidden text.
///
/// # Platform Support
///
/// Not widely supported.
pub const REVEAL: Attribute = Attribute(28);
/// Crosses out/strikes through text.
///
/// Characters legible but marked as if for deletion.
///
/// # Platform Support
///
/// Not supported in `Terminal.app`.
pub const STRIKETHROUGH: Attribute = Attribute(9);
/// The [`fg`] module provides specific format attributes that apply to
/// foreground elements.
pub mod fg {
use super::*;
/// A pure black foreground color.
pub const BLACK: Attribute = Attribute(30);
/// A dark red foreground color.
pub const RED: Attribute = Attribute(31);
/// A dark green foreground color.
pub const GREEN: Attribute = Attribute(32);
/// A dark yellow foreground color.
pub const YELLOW: Attribute = Attribute(33);
/// A dark blue foreground color.
pub const BLUE: Attribute = Attribute(34);
/// A dark magenta foreground color.
pub const MAGENTA: Attribute = Attribute(35);
/// A dark cyan foreground color.
pub const CYAN: Attribute = Attribute(36);
/// A white foreground color.
///
/// This is not a "pure" white; for that, see [`BRIGHT_WHITE`].
pub const WHITE: Attribute = Attribute(37);
/// A gray foreground color.
///
/// This is also known as `BRIGHT_BLACK` in some systems.
pub const GRAY: Attribute = Attribute(90);
/// A bright red foreground color.
pub const BRIGHT_RED: Attribute = Attribute(91);
/// A bright green foreground color.
pub const BRIGHT_GREEN: Attribute = Attribute(92);
/// A bright yellow foreground color.
pub const BRIGHT_YELLOW: Attribute = Attribute(93);
/// A bright blue foreground color.
pub const BRIGHT_BLUE: Attribute = Attribute(94);
/// A bright magenta foreground color.
pub const BRIGHT_MAGENTA: Attribute = Attribute(95);
/// A bright cyan foreground color.
pub const BRIGHT_CYAN: Attribute = Attribute(96);
/// A bright white foreground color.
pub const BRIGHT_WHITE: Attribute = Attribute(97);
/// Resets the foreground color.
pub const RESET: Attribute = Attribute(39);
}
/// The [`bg`] module provides specific format attributes that apply to
/// background elements.
pub mod bg {
use super::*;
/// A pure black background color.
pub const BLACK: Attribute = Attribute(40);
/// A dark red background color.
pub const RED: Attribute = Attribute(41);
/// A dark green background color.
pub const GREEN: Attribute = Attribute(42);
/// A dark yellow background color.
pub const YELLOW: Attribute = Attribute(43);
/// A dark blue background color.
pub const BLUE: Attribute = Attribute(44);
/// A dark magenta background color.
pub const MAGENTA: Attribute = Attribute(45);
/// A dark cyan background color.
pub const CYAN: Attribute = Attribute(46);
/// A white background color.
///
/// This is not a "Pure" white; for that
pub const WHITE: Attribute = Attribute(47);
/// A gray background color.
///
/// This is not a "pure" white; for that, see [`BRIGHT_WHITE`].
pub const GRAY: Attribute = Attribute(100);
/// A bright red background color.
pub const BRIGHT_RED: Attribute = Attribute(101);
/// A bright green background color.
pub const BRIGHT_GREEN: Attribute = Attribute(102);
/// A bright yellow background color.
pub const BRIGHT_YELLOW: Attribute = Attribute(103);
/// A bright blue background color.
pub const BRIGHT_BLUE: Attribute = Attribute(104);
/// A bright magenta background color.
pub const BRIGHT_MAGENTA: Attribute = Attribute(105);
/// A bright cyan background color.
pub const BRIGHT_CYAN: Attribute = Attribute(106);
/// A bright white background color.
pub const BRIGHT_WHITE: Attribute = Attribute(107);
/// Resets the background color.
pub const RESET: Attribute = Attribute(49);
}
}
/// A collection of ANSI [`Attribute`]s that can be applied to formatting or
/// textual elements.
///
/// This will disable itself if the environment variable `NOCOLOR` or `NO_COLOR`
/// is defined and set to some truthy value.
pub struct Format<'a>(&'a [Attribute]);
impl Default for Format<'_> {
fn default() -> Self {
NO_FORMAT
}
}
/// A default [`Format`] object that does not have any formatting values.
pub const NO_FORMAT: Format<'static> = Format::from_slice(&[]);
impl<'a> Format<'a> {
/// Constructs a [`Format`] object from a slice containing [`Attribute`]
/// instances.
pub const fn from_slice(attributes: &'a [Attribute]) -> Self {
Self(attributes)
}
/// Wraps a formatted [`Display`] element into a [`FormatDisplay`] that
/// will automatically toggle the ANSI formatting before displaying the
/// element, and then follow it up with a [`fmt::RESET`].
///
/// # Parameters
///
/// * `display` - the element to display
pub const fn wrap<'b>(&'a self, display: &'b dyn Display) -> FormatDisplay<'a, 'b> {
FormatDisplay {
format: self,
display,
}
}
/// Computes and returns the optimal format for the specified `writer`
///
/// This will disable formatting if the `writer` does not support ANSI
/// formatting (determined by checking [`IsTerminal`])
///
/// # Parameters
///
/// * `writer` - the writer to write to
///
/// [`IsTerminal`]: std::io::IsTerminal
pub fn optimize_for<W>(self, writer: &W) -> Self
where
W: std::io::Write + std::io::IsTerminal,
{
if self.can_format(writer) {
self
} else {
NO_FORMAT
}
}
/// Checks whether formatting is available for the given `writer`
///
/// # Parameters
///
/// * `writer` - the writer to check formatting availability.
fn can_format<W>(&self, writer: &W) -> bool
where
W: std::io::Write + std::io::IsTerminal,
{
writer.is_terminal()
}
}
impl<'a> Display for Format<'a> {
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
if *ENABLED {
if self.0.is_empty() {
return Ok(());
}
write!(f, "{}[", ESCAPE)?;
for attribute in self.0.iter() {
write!(f, "{};", attribute.0)?;
}
write!(f, "m")
} else {
Ok(())
}
}
}
/// A [`Display`] element that will automatically use [`Format`] and reset the
/// format after.
pub struct FormatDisplay<'a, 'b> {
format: &'a Format<'a>,
display: &'b dyn Display,
}
/// A wrapper around [`fmt::RESET`], used to leverage the test for whether
/// ANSI formatting is enabled.
const RESET_FORMAT: Format<'_> = format![fmt::RESET];
impl<'a, 'b> Display for FormatDisplay<'a, 'b> {
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
self.format.fmt(f)?;
self.display.fmt(f)?;
RESET_FORMAT.fmt(f)
}
}
/// A convenience macro for forming a [`Format`] object, analogous to the
/// [`vec`] macro in the standard library.
///
/// # Example
///
/// Basic Use:
///
/// ```rust
/// const ERROR_FORMAT: ansi::Format<'_> = ansi::format![
/// ansi::fmt::fg::RED, ansi::fmt::UNDERLINE, ansi::fmt::BOLD,
/// ];
/// println!("{}", ERROR_FORMAT.wrap(&"Hello"));
/// ```
#[macro_export]
macro_rules! format {
($($attribute:expr$(,)?)+) => {
$crate::Format::from_slice(&[$($attribute,)+])
};
}