├── .github └── workflows │ └── rust.yml ├── .gitignore ├── .vscode └── settings.json ├── Cargo.lock ├── Cargo.toml ├── LICENSE ├── README.md ├── src ├── color.rs ├── colors.rs └── lib.rs └── tests └── tests.rs /.github/workflows/rust.yml: -------------------------------------------------------------------------------- 1 | name: Rust 2 | 3 | on: 4 | push: 5 | branches: [ "master" ] 6 | pull_request: 7 | branches: [ "master" ] 8 | 9 | env: 10 | CARGO_TERM_COLOR: always 11 | 12 | jobs: 13 | build: 14 | 15 | runs-on: ubuntu-latest 16 | 17 | steps: 18 | - uses: actions/checkout@v3 19 | - name: Build 20 | run: cargo build --verbose 21 | - name: Run tests 22 | run: cargo test --verbose 23 | - name: List package contents 24 | run: cargo package --list 25 | - name: Publish to crates.io 26 | env: 27 | CARGO_REGISTRY_TOKEN: ${{ secrets.CARGO_REGISTRY_TOKEN }} 28 | run: cargo publish 29 | - name: Upload crate 30 | uses: actions/upload-artifact@v3 31 | with: 32 | name: crate 33 | path: target/package/*.crate 34 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | /target 2 | **/*.rs.bk 3 | -------------------------------------------------------------------------------- /.vscode/settings.json: -------------------------------------------------------------------------------- 1 | { 2 | "rust.all_targets": true 3 | } -------------------------------------------------------------------------------- /Cargo.lock: -------------------------------------------------------------------------------- 1 | # This file is automatically @generated by Cargo. 2 | # It is not intended for manual editing. 3 | version = 3 4 | 5 | [[package]] 6 | name = "ansi_rgb" 7 | version = "0.3.2-alpha" 8 | dependencies = [ 9 | "rgb", 10 | ] 11 | 12 | [[package]] 13 | name = "rgb" 14 | version = "0.8.33" 15 | source = "registry+https://github.com/rust-lang/crates.io-index" 16 | checksum = "c3b221de559e4a29df3b957eec92bc0de6bc8eaf6ca9cfed43e5e1d67ff65a34" 17 | -------------------------------------------------------------------------------- /Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "ansi_rgb" 3 | version = "0.3.2-alpha" 4 | authors = ["Matt Thomas "] 5 | edition = "2021" 6 | description = "Colorful terminal text using ANSI escape sequences" 7 | license = "MIT" 8 | categories = ["no-std", "command-line-interface"] 9 | keywords = ["ansi", "color", "rgb", "no_std", "terminal"] 10 | readme = "README.md" 11 | repository = "https://github.com/rust-osdev/ansi_rgb" 12 | homepage = "https://github.com/rust-osdev/ansi_rgb" 13 | documentation = "https://docs.rs/ansi_rgb" 14 | 15 | [badges] 16 | maintenance = { status = "actively-developed" } 17 | 18 | # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html 19 | 20 | [dependencies] 21 | rgb = { version = "0.8", default-features = false, optional = true } 22 | 23 | [features] 24 | default = ["rgb"] -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2019 Matthew Thomas 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # ansi_rgb 2 | 3 | Colorful terminal text using [ANSI escape sequences](https://en.wikipedia.org/wiki/ANSI_escape_code#SGR_parameters). 4 | 5 | * Very simple API 6 | * 3-, 4-, 8-, and 24-bit colors 7 | * Colors all the [formatting traits](https://doc.rust-lang.org/std/fmt/#formatting-traits) 8 | * Easy to add your own color types 9 | * `no_std` compliant 10 | 11 | [![crates.io badge](https://img.shields.io/crates/v/ansi_rgb.svg)](https://crates.io/crates/ansi_rgb)
12 | [![docs.rs badge](https://docs.rs/ansi_rgb/badge.svg)](https://docs.rs/ansi_rgb)
13 | [![Downloads badge](https://img.shields.io/crates/d/ansi_rgb.svg)](https://crates.io/crates/ansi_rgb) 14 | 15 | Full documentation: 16 | 17 | [https://docs.rs/ansi_rgb](https://docs.rs/ansi_rgb) -------------------------------------------------------------------------------- /src/color.rs: -------------------------------------------------------------------------------- 1 | use core::fmt; 2 | 3 | /// The location for applying a color 4 | #[derive(Copy, Clone, Debug, Eq, PartialEq)] 5 | pub enum Canvas { 6 | Background, 7 | Foreground, 8 | } 9 | 10 | /// Generates ANSI escape sequences using a specific color 11 | pub trait FormatColor { 12 | /// Apply the color 13 | fn prelude(&self, f: &mut fmt::Formatter, canvas: Canvas) -> fmt::Result; 14 | 15 | /// Undo the color application 16 | fn epilogue(&self, f: &mut fmt::Formatter, canvas: Canvas) -> fmt::Result { 17 | f.write_str(match canvas { 18 | Canvas::Foreground => "\x1B[39m", 19 | Canvas::Background => "\x1B[49m" 20 | }) 21 | } 22 | } 23 | 24 | /// Something that will have a foreground color applied 25 | pub struct WithForeground { 26 | item: Item, 27 | formatter: Formatter 28 | } 29 | 30 | /// Something that will have a background color applied 31 | pub struct WithBackground { 32 | item: Item, 33 | formatter: Formatter 34 | } 35 | 36 | /// Adds a foreground or background color 37 | pub trait Colorable: Sized { 38 | /// Add a background color 39 | fn bg(self, formatter: TFormatColor) -> WithBackground { 40 | WithBackground { 41 | item: self, 42 | formatter 43 | } 44 | } 45 | 46 | /// Add a foreground color 47 | fn fg(self, formatter: TFormatColor) -> WithForeground { 48 | WithForeground { 49 | item: self, 50 | formatter 51 | } 52 | } 53 | } 54 | 55 | impl Colorable for T {} 56 | 57 | macro_rules! impl_me { 58 | ($bound:path) => { 59 | impl $bound for WithForeground { 60 | fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { 61 | self.formatter.prelude(f, Canvas::Foreground) 62 | .and_then(|_| self.item.fmt(f)) 63 | .and_then(|_| self.formatter.epilogue(f, Canvas::Foreground)) 64 | } 65 | } 66 | impl $bound for WithBackground { 67 | fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { 68 | self.formatter.prelude(f, Canvas::Background) 69 | .and_then(|_| self.item.fmt(f)) 70 | .and_then(|_| self.formatter.epilogue(f, Canvas::Background)) 71 | } 72 | } 73 | }; 74 | } 75 | 76 | impl_me!(fmt::Binary); 77 | impl_me!(fmt::Debug); 78 | impl_me!(fmt::Display); 79 | impl_me!(fmt::LowerExp); 80 | impl_me!(fmt::LowerHex); 81 | impl_me!(fmt::Octal); 82 | impl_me!(fmt::Pointer); 83 | impl_me!(fmt::UpperExp); 84 | impl_me!(fmt::UpperHex); 85 | -------------------------------------------------------------------------------- /src/colors.rs: -------------------------------------------------------------------------------- 1 | use crate::Canvas; 2 | use crate::FormatColor; 3 | use core::fmt; 4 | use rgb::RGB8; 5 | 6 | impl FormatColor for RGB8 { 7 | fn prelude(&self, f: &mut fmt::Formatter, canvas: crate::Canvas) -> fmt::Result { 8 | match canvas { 9 | Canvas::Foreground => write!(f, "\x1B[38;2;{};{};{}m", self.r, self.g, self.b), 10 | Canvas::Background => write!(f, "\x1B[48;2;{};{};{}m", self.r, self.g, self.b), 11 | } 12 | } 13 | } 14 | 15 | /// Makes white 16 | pub const fn white() -> RGB8 { 17 | RGB8::new(255, 255, 255) 18 | } 19 | 20 | /// Makes black 21 | pub const fn black() -> RGB8 { 22 | RGB8::new(0, 0, 0) 23 | } 24 | 25 | /// Makes red 26 | pub const fn red() -> RGB8 { 27 | RGB8::new(255, 0, 0) 28 | } 29 | 30 | /// Makes orange 31 | pub const fn orange() -> RGB8 { 32 | RGB8::new(255, 128, 0) 33 | } 34 | 35 | /// Makes yellow 36 | pub const fn yellow() -> RGB8 { 37 | RGB8::new(255, 255, 0) 38 | } 39 | 40 | /// Makes yellow green 41 | pub const fn yellow_green() -> RGB8 { 42 | RGB8::new(128, 255, 0) 43 | } 44 | 45 | /// Makes green 46 | pub const fn green() -> RGB8 { 47 | RGB8::new(0, 255, 0) 48 | } 49 | 50 | /// Makes green cyan 51 | pub const fn green_cyan() -> RGB8 { 52 | RGB8::new(0, 255, 128) 53 | } 54 | 55 | /// Makes cyan 56 | pub const fn cyan() -> RGB8 { 57 | RGB8::new(0, 255, 255) 58 | } 59 | 60 | /// Makes cyan blue 61 | pub const fn cyan_blue() -> RGB8 { 62 | RGB8::new(0, 128, 255) 63 | } 64 | 65 | /// Makes blue 66 | pub const fn blue() -> RGB8 { 67 | RGB8::new(0, 0, 255) 68 | } 69 | 70 | /// Makes blue magenta 71 | pub const fn blue_magenta() -> RGB8 { 72 | RGB8::new(128, 0, 255) 73 | } 74 | 75 | /// Makes magenta 76 | pub const fn magenta() -> RGB8 { 77 | RGB8::new(255, 0, 255) 78 | } 79 | 80 | /// Makes magenta pink 81 | pub const fn magenta_pink() -> RGB8 { 82 | RGB8::new(255, 0, 128) 83 | } 84 | 85 | /// A 3-bit color type 86 | /// 87 | /// The exact colors usually depend on the terminal color scheme. 88 | #[derive(Copy, Clone, Debug, Eq, PartialEq)] 89 | pub enum Color3 { 90 | BLACK = 0, 91 | RED = 1, 92 | GREEN = 2, 93 | YELLOW = 3, 94 | BLUE = 4, 95 | MAGENTA = 5, 96 | CYAN = 6, 97 | WHITE = 7, 98 | } 99 | 100 | impl FormatColor for Color3 { 101 | fn prelude(&self, f: &mut fmt::Formatter, canvas: crate::Canvas) -> fmt::Result { 102 | match canvas { 103 | Canvas::Foreground => write!(f, "\x1B[{}m", 30 + *self as u8), 104 | Canvas::Background => write!(f, "\x1B[{}m", 40 + *self as u8), 105 | } 106 | } 107 | } 108 | 109 | /// A 4-bit color type 110 | /// 111 | /// The different possibilities are available through associated constants; 112 | /// their exact colors usually depend on the terminal color scheme. A 4-bit 113 | /// color without its bright bit set is identical to its corresponding 3-bit 114 | /// color (not necessarily the one with the same name). 115 | #[derive(Copy, Clone, Debug, Eq, PartialEq)] 116 | pub struct Color4 { 117 | color3: Color3, 118 | bright: bool, 119 | } 120 | 121 | impl Color4 { 122 | /// Build a Color4 based on [`Color3`] and a bright bit 123 | pub const fn new(color3: Color3, bright: bool) -> Self { 124 | Self { color3, bright } 125 | } 126 | 127 | pub const BLACK: Self = Self::new(Color3::BLACK, false); 128 | pub const RED: Self = Self::new(Color3::RED, false); 129 | pub const GREEN: Self = Self::new(Color3::GREEN, false); 130 | pub const YELLOW: Self = Self::new(Color3::YELLOW, false); 131 | pub const BLUE: Self = Self::new(Color3::BLUE, false); 132 | pub const MAGENTA: Self = Self::new(Color3::MAGENTA, false); 133 | pub const CYAN: Self = Self::new(Color3::CYAN, false); 134 | pub const LIGHT_GRAY: Self = Self::new(Color3::WHITE, false); 135 | pub const DARK_GRAY: Self = Self::new(Color3::BLACK, true); 136 | pub const BRIGHT_RED: Self = Self::new(Color3::RED, true); 137 | pub const BRIGHT_GREEN: Self = Self::new(Color3::GREEN, true); 138 | pub const BRIGHT_YELLOW: Self = Self::new(Color3::YELLOW, true); 139 | pub const BRIGHT_BLUE: Self = Self::new(Color3::BLUE, true); 140 | pub const BRIGHT_MAGENTA: Self = Self::new(Color3::MAGENTA, true); 141 | pub const BRIGHT_CYAN: Self = Self::new(Color3::CYAN, true); 142 | pub const WHITE: Self = Self::new(Color3::WHITE, true); 143 | } 144 | 145 | impl FormatColor for Color4 { 146 | fn prelude(&self, f: &mut fmt::Formatter, canvas: crate::Canvas) -> fmt::Result { 147 | match canvas { 148 | Canvas::Foreground => write!( 149 | f, 150 | "\x1B[{}m", 151 | if self.bright { 90 } else { 30 } + self.color3 as u8 152 | ), 153 | Canvas::Background => write!( 154 | f, 155 | "\x1B[{}m", 156 | if self.bright { 100 } else { 40 } + self.color3 as u8 157 | ), 158 | } 159 | } 160 | } 161 | 162 | impl From for Color4 { 163 | fn from(color3: Color3) -> Self { 164 | Self::new(color3, false) 165 | } 166 | } 167 | 168 | /// Error type indicating an input argument was out of bounds 169 | #[derive(Debug)] 170 | pub struct OutOfBoundsError(); 171 | 172 | /// An 8-bit color 173 | #[derive(Copy, Clone, Debug, Eq, PartialEq)] 174 | pub struct Color8 { 175 | byte: u8 176 | } 177 | 178 | impl Color8 { 179 | /// Create a `Color8` using the given 8-bit color code. 180 | /// See [https://en.wikipedia.org/wiki/ANSI_escape_code#8-bit](https://en.wikipedia.org/wiki/ANSI_escape_code#8-bit) 181 | pub const fn new(byte: u8) -> Self { 182 | Self { byte } 183 | } 184 | 185 | /// New RGB color, each channel in range `0..6` 186 | pub fn new_rgb(r: u8, g: u8, b: u8) -> Result { 187 | if r < 6 && g < 6 && b < 6 { 188 | Ok(Self { 189 | byte: 16 + r * 36 + g * 6 + b, 190 | }) 191 | } else { 192 | Err(OutOfBoundsError()) 193 | } 194 | } 195 | 196 | /// New gray color in range `0..24` 197 | pub fn new_gray(gray: u8) -> Result { 198 | if gray < 24 { 199 | Ok(Self { byte: 232 + gray }) 200 | } else { 201 | Err(OutOfBoundsError()) 202 | } 203 | } 204 | } 205 | 206 | impl FormatColor for Color8 { 207 | fn prelude(&self, f: &mut fmt::Formatter, canvas: Canvas) -> fmt::Result { 208 | write!( 209 | f, 210 | "\x1B[{};5;{}m", 211 | match canvas { 212 | Canvas::Foreground => 38, 213 | Canvas::Background => 48 214 | }, 215 | self.byte 216 | ) 217 | } 218 | } 219 | 220 | impl From for Color8 { 221 | fn from(color3: Color3) -> Self { 222 | Self::new(color3 as u8) 223 | } 224 | } 225 | 226 | impl From for Color8 { 227 | fn from(color4: Color4) -> Self { 228 | Self::new( 229 | (color4.color3 as u8) + match color4.bright { 230 | true => 8, 231 | false => 0 232 | } 233 | ) 234 | } 235 | } 236 | -------------------------------------------------------------------------------- /src/lib.rs: -------------------------------------------------------------------------------- 1 | #![no_std] 2 | #![doc = include_str!("../README.md")] 3 | /*! 4 | # Foreground colors 5 | 6 | ```rust 7 | use ansi_rgb::{ Colorable, red }; 8 | 9 | println!("{}", "Hello, world!".fg(red())); 10 | ``` 11 | 12 | Output: 13 | 14 | Hello, world! 15 | 16 | # Background colors 17 | 18 | ```rust 19 | use ansi_rgb::{ Colorable, red }; 20 | 21 | println!("{}", "Hello, world!".bg(red())); 22 | ``` 23 | 24 | Output: 25 | 26 | Hello, world! 27 | 28 | # Nesting 29 | 30 | ```rust 31 | use ansi_rgb::{ Colorable, blue, green, red }; 32 | 33 | let formatted = format!( 34 | "Hello, world! {}", 35 | format!( 36 | "{} is an interesting {}", 37 | "This".fg(blue()), 38 | "day".fg(red()) 39 | ).bg(green()) 40 | ); 41 | 42 | println!("{}", formatted); 43 | # assert_eq!( 44 | # "Hello, world! \u{1b}[48;2;0;255;0m\u{1b}[38;2;0;0;255mThis\u{1b}[39m is an interesting \u{1b}[38;2;255;0;0mday\u{1b}[39m\u{1b}[49m", 45 | # formatted 46 | # ) 47 | ``` 48 | 49 | Output: 50 | 51 | Hello, world! This is an interesting day 52 | 53 | # Anything formattable 54 | 55 | ```rust 56 | use ansi_rgb::*; 57 | 58 | #[derive(Debug)] 59 | struct Foo(i32, i32); 60 | 61 | let foo = Foo(1, 2); 62 | println!("{:?}", foo.fg(green())); 63 | ``` 64 | 65 | Output: 66 | 67 | Foo(1, 2) 68 | 69 | # 3-bit colors 70 | 71 | ```rust 72 | use ansi_rgb::{ Colorable, Color3 }; 73 | 74 | println!("{}", "Hello, world!".fg(Color3::RED).bg(Color3::BLACK)); 75 | ``` 76 | 77 | Output: 78 | 79 | Hello, world! 80 | 81 | # 4-bit colors 82 | 83 | ```rust 84 | use ansi_rgb::{ Colorable, Color4 }; 85 | 86 | println!("{}", "Hello, world!".fg(Color4::BRIGHT_RED).bg(Color4::BLACK)); 87 | ``` 88 | 89 | Output: 90 | 91 | Hello, world! 92 | 93 | # 8-bit colors 94 | 95 | ```rust 96 | use ansi_rgb::{ Colorable, Color8 }; 97 | 98 | println!("{}", "Hello, world!".fg(Color8::new(160)).bg(Color8::new(0))); 99 | ``` 100 | 101 | Output: 102 | 103 | Hello, world! 104 | 105 | # 24-bit colors 106 | 107 | Built-in support for [the `rgb` crate](https://crates.io/crates/rgb). 108 | 109 | ```toml 110 | # Cargo.toml 111 | [dependencies] 112 | rgb = { version = "0.8", default-features = false } 113 | ``` 114 | 115 | ```rust 116 | use ansi_rgb::{ Colorable }; 117 | use rgb::RGB8; 118 | 119 | let fg = RGB8::new(123, 231, 111); 120 | let bg = RGB8::new(10, 100, 20); 121 | println!("{}", "Yuck".fg(fg).bg(bg)); 122 | ``` 123 | 124 | Output: 125 | 126 | Yuck 127 | 128 | # Extending to other color types 129 | 130 | If you have your own color type and you know how to turn it into ANSI escape 131 | sequences then just implement `FormatColor`: 132 | 133 | ```rust 134 | use ansi_rgb::{ Canvas, Colorable, FormatColor }; 135 | use core::fmt; 136 | 137 | enum FavoriteColors { 138 | SkyBlue, 139 | RocketPlumeYellow, 140 | TitaniumGray 141 | } 142 | 143 | impl FormatColor for FavoriteColors { 144 | fn prelude(&self, f: &mut fmt::Formatter, canvas: Canvas) -> fmt::Result { 145 | let (r, g, b) = match self { 146 | FavoriteColors::SkyBlue => (135, 206, 235), 147 | FavoriteColors::RocketPlumeYellow => (255, 255, 0), 148 | FavoriteColors::TitaniumGray => (86, 95, 107) 149 | }; 150 | write!( 151 | f, 152 | "\x1B[{};2;{};{};{}m", 153 | match canvas { 154 | Canvas::Foreground => 38, 155 | Canvas::Background => 48 156 | }, 157 | r, 158 | g, 159 | b 160 | ) 161 | } 162 | } 163 | 164 | println!( 165 | "The sky is {}", 166 | "blue".fg(FavoriteColors::SkyBlue) 167 | ); 168 | # assert_eq!("The sky is \x1B[38;2;135;206;235mblue\x1B[39m", format!("The sky is {}", "blue".fg(FavoriteColors::SkyBlue))) 169 | ``` 170 | 171 | Output: 172 | 173 | The sky is blue 174 | 175 | # Features 176 | 177 | `default` includes 3-, 4-, 8-, and 24-bit colors and depends on the `rgb` crate, 178 | giving you the following things: 179 | 180 | * Dependency on `rgb` crate 181 | * Implementation of `FormatColor` for `rgb::RGB8` type 182 | * `Color3` enum and its implementation of `FormatColor` 183 | * `Color4` struct and its implementation of `FormatColor` 184 | * `Color8` struct and its implementation of `FormatColor` 185 | * Color functions (`red()`, `orange()`, etc) 186 | 187 | # Windows users 188 | 189 | You need to [set your console mode](https://docs.microsoft.com/en-us/windows/console/console-modes). Otherwise you'll get garbage like this: 190 | 191 | `�[48;2;159;114;0m �[0m` 192 | */ 193 | 194 | mod color; 195 | #[cfg(feature = "default")] 196 | mod colors; 197 | 198 | pub use color::*; 199 | #[cfg(feature = "default")] 200 | pub use colors::*; 201 | -------------------------------------------------------------------------------- /tests/tests.rs: -------------------------------------------------------------------------------- 1 | use ansi_rgb::*; 2 | use rgb::RGB8; 3 | 4 | #[test] 5 | fn use_all_colors() { 6 | println!( 7 | "{}\n{}\n{}\n{}\n{}\n{}\n{}\n{}\n{}\n{}\n{}\n{}\n{}", 8 | "Red".fg(red()), 9 | "Orange".fg(orange()), 10 | "Yellow".fg(yellow()), 11 | "Yellow green".fg(yellow_green()), 12 | "Green".fg(green()), 13 | "Green cyan".fg(green_cyan()), 14 | "Cyan".fg(cyan()), 15 | "Cyan blue".fg(white()).bg(cyan_blue()), 16 | "Blue".fg(white()).bg(blue()), 17 | "Blue magenta".fg(white()).bg(blue_magenta()), 18 | "Magenta".fg(magenta()), 19 | "Magenta pink".fg(magenta_pink()), 20 | "Custom color" 21 | .fg(RGB8::new(123, 231, 111)) 22 | .bg(RGB8::new(10, 100, 20)) 23 | ); 24 | } 25 | 26 | #[test] 27 | fn temporary_value_dropped_while_borrowed() { 28 | // https://github.com/rust-osdev/ansi_rgb/issues/3 29 | let foo = "Hello, world!".fg(green()).bg(red()); 30 | println!("{}", foo); 31 | } 32 | 33 | #[test] 34 | fn formatting_of_pointers() { 35 | // https://github.com/rust-osdev/ansi_rgb/issues/2 36 | let hello_world = "Hello, world"; 37 | let formatted = hello_world.fg(red()).bg(blue()); 38 | assert_eq!( 39 | "\u{1b}[48;2;0;0;255m\u{1b}[38;2;255;0;0mHello, world\u{1b}[39m\u{1b}[49m", 40 | format!("{}", formatted) 41 | ); 42 | } 43 | 44 | #[test] 45 | fn foo() { 46 | use ansi_rgb::*; 47 | #[derive(Debug)] 48 | struct Foo(i32, i32); 49 | 50 | let foo = Foo(1, 2); 51 | println!("{:?}", foo.fg(green())); 52 | } 53 | 54 | #[test] 55 | fn color3() { 56 | let hello_world = "Hello, world"; 57 | let formatted = hello_world.fg(Color3::BLUE); 58 | assert_eq!("\u{1b}[34mHello, world\u{1b}[39m", format!("{}", formatted)); 59 | } 60 | 61 | #[test] 62 | fn color4() { 63 | let hello_world = "Hello, world"; 64 | let formatted = hello_world.fg(Color4::BLACK).bg(Color4::WHITE); 65 | assert_eq!( 66 | "\u{1b}[107m\u{1b}[30mHello, world\u{1b}[39m\u{1b}[49m", 67 | format!("{}", formatted) 68 | ); 69 | } 70 | 71 | #[test] 72 | fn color8_background() { 73 | assert_eq!( 74 | "\u{1b}[48;5;0mHello, world\u{1b}[49m", 75 | format!("{}", "Hello, world".bg(Color8::new(0))) 76 | ); 77 | } 78 | 79 | #[test] 80 | fn color8_foreground() { 81 | assert_eq!( 82 | "\u{1b}[38;5;0mHello, world\u{1b}[39m", 83 | format!("{}", "Hello, world".fg(Color8::new(0))) 84 | ); 85 | } 86 | 87 | #[test] 88 | fn convert_color3_to_color4() { 89 | assert_eq!( 90 | Color4::new(Color3::RED, false), 91 | Color3::RED.into() 92 | ) 93 | } 94 | 95 | #[test] 96 | fn convert_color3_to_color8() { 97 | assert_eq!( 98 | Color8::new(0), 99 | Color3::BLACK.into() 100 | ) 101 | } 102 | 103 | #[test] 104 | fn convert_color4_to_color8() { 105 | assert_eq!( 106 | Color8::new(15), 107 | Color4::WHITE.into() 108 | ) 109 | } 110 | 111 | #[test] 112 | fn format_padding() { 113 | assert_eq!( 114 | "\u{1b}[38;2;0;0;0mX \u{1b}[39m", 115 | format!("{:5}", "X".fg(black())) 116 | ) 117 | } 118 | 119 | #[test] 120 | fn convert_rgb_to_color8() { 121 | assert_eq!(Color8::new_rgb(5, 2, 0).unwrap(), Color8::new(208)); 122 | } 123 | 124 | #[test] 125 | fn convert_gray_to_color8() { 126 | assert_eq!(Color8::new_gray(23).unwrap(), Color8::new(255)); 127 | } 128 | 129 | #[test] 130 | fn color8_new_rgb() { 131 | assert!(Color8::new_rgb(6, 5, 5).is_err()); 132 | assert!(Color8::new_rgb(5, 6, 5).is_err()); 133 | assert!(Color8::new_rgb(5, 5, 6).is_err()); 134 | assert!(Color8::new_rgb(5, 5, 5).is_ok()); 135 | } 136 | --------------------------------------------------------------------------------