yansi-term-0.1.2/.cargo_vcs_info.json0000644000000001121366472367000132320ustar00{ "git": { "sha1": "b30235f332c1861316b3b812643441942d84fe1c" } } yansi-term-0.1.2/.github/workflows/checks.yml010064400017500001750000000015341366472342400174210ustar0000000000000000name: Checks on: push: pull_request: schedule: [cron: "40 1 * * *"] jobs: clippy: name: Clippy runs-on: ubuntu-latest steps: - uses: actions/checkout@v2 - uses: actions-rs/toolchain@v1 with: toolchain: nightly components: clippy override: true - uses: actions-rs/clippy-check@v1 with: token: ${{ secrets.GITHUB_TOKEN }} args: --all-features fmt: name: Rustfmt runs-on: ubuntu-latest strategy: matrix: rust: - stable steps: - uses: actions/checkout@v2 - uses: actions-rs/toolchain@v1 with: profile: minimal toolchain: ${{ matrix.rust }} override: true - uses: actions-rs/cargo@v1 with: command: fmt args: --all -- --check yansi-term-0.1.2/.github/workflows/linux.yml010064400017500001750000000031351366472342400173170ustar0000000000000000name: CI (Linux) on: push: pull_request: schedule: [cron: "40 1 * * *"] jobs: build_and_test: strategy: fail-fast: false matrix: version: - 1.42.0 # MSRV - stable - nightly name: ${{ matrix.version }} - x86_64-unknown-linux-gnu runs-on: ubuntu-latest steps: - uses: actions/checkout@master - name: Install ${{ matrix.version }} uses: actions-rs/toolchain@v1 with: toolchain: ${{ matrix.version }}-x86_64-unknown-linux-gnu profile: minimal components: rustfmt override: true - name: Generate Cargo.lock uses: actions-rs/cargo@v1 with: command: generate-lockfile - name: Cache cargo registry uses: actions/cache@v1 with: path: ~/.cargo/registry key: ${{ matrix.version }}-x86_64-unknown-linux-gnu-cargo-registry-trimmed-${{ hashFiles('**/Cargo.lock') }} - name: Cache cargo index uses: actions/cache@v1 with: path: ~/.cargo/git key: ${{ matrix.version }}-x86_64-unknown-linux-gnu-cargo-index-trimmed-${{ hashFiles('**/Cargo.lock') }} - name: Run tests uses: actions-rs/cargo@v1 timeout-minutes: 40 with: command: test args: --all --all-features --no-fail-fast -- --nocapture - name: Install cargo-cache continue-on-error: true run: | cargo install cargo-cache --no-default-features --features ci-autoclean - name: Clear the cargo caches run: | cargo-cache yansi-term-0.1.2/.github/workflows/osx.yml010064400017500001750000000026751366472342400170010ustar0000000000000000name: CI (OSX) on: push: pull_request: schedule: [cron: "40 1 * * *"] jobs: build_and_test: strategy: fail-fast: false matrix: version: - stable - nightly name: ${{ matrix.version }} - x86_64-apple-darwin runs-on: macOS-latest steps: - uses: actions/checkout@master - name: Install ${{ matrix.version }} uses: actions-rs/toolchain@v1 with: toolchain: ${{ matrix.version }}-x86_64-apple-darwin profile: minimal components: rustfmt override: true - name: Generate Cargo.lock uses: actions-rs/cargo@v1 with: command: generate-lockfile - name: Cache cargo registry uses: actions/cache@v1 with: path: ~/.cargo/registry key: ${{ matrix.version }}-x86_64-apple-darwin-cargo-registry-trimmed-${{ hashFiles('**/Cargo.lock') }} - name: Cache cargo index uses: actions/cache@v1 with: path: ~/.cargo/git key: ${{ matrix.version }}-x86_64-apple-darwin-cargo-index-trimmed-${{ hashFiles('**/Cargo.lock') }} - name: Run tests uses: actions-rs/cargo@v1 with: command: test args: --all --all-features --no-fail-fast -- --nocapture - name: Clear the cargo caches run: | cargo install cargo-cache --no-default-features --features ci-autoclean cargo-cache yansi-term-0.1.2/.gitignore010064400017500001750000000000311366464674500140320ustar0000000000000000target Cargo.lock /.idea yansi-term-0.1.2/.travis.yml010064400017500001750000000010211366464674500141530ustar0000000000000000language: rust sudo: false dist: trusty cache: cargo: false matrix: include: - rust: stable - rust: beta - rust: 1.40.0 - rust: nightly before_script: - | if [[ "$TRAVIS_RUST_VERSION" != "nightly" ]]; then rustup component add rustfmt rustup component add clippy fi script: - | if [[ "$TRAVIS_RUST_VERSION" != "nightly" ]]; then cargo fmt -- --check cargo clippy --all-targets --all-features -- -D warnings fi - cargo test --all-features --all -- --nocapture yansi-term-0.1.2/Cargo.lock0000644000000104771366472367000112240ustar00# This file is automatically @generated by Cargo. # It is not intended for manual editing. [[package]] name = "aho-corasick" version = "0.7.10" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8716408b8bc624ed7f65d223ddb9ac2d044c0547b6fa4b0d554f3a9540496ada" dependencies = [ "memchr", ] [[package]] name = "doc-comment" version = "0.3.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "fea41bba32d969b513997752735605054bc0dfa92b4c56bf1189f2e174be7a10" [[package]] name = "itoa" version = "0.4.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b8b7a7c0c47db5545ed3fef7468ee7bb5b74691498139e4b3f6a20685dc6dd8e" [[package]] name = "lazy_static" version = "1.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646" [[package]] name = "memchr" version = "2.3.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3728d817d99e5ac407411fa471ff9800a778d88a24685968b36824eaf4bee400" [[package]] name = "proc-macro2" version = "1.0.17" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1502d12e458c49a4c9cbff560d0fe0060c252bc29799ed94ca2ed4bb665a0101" dependencies = [ "unicode-xid", ] [[package]] name = "quote" version = "1.0.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "54a21852a652ad6f610c9510194f398ff6f8692e334fd1145fed931f7fbe44ea" dependencies = [ "proc-macro2", ] [[package]] name = "regex" version = "1.3.9" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9c3780fcf44b193bc4d09f36d2a3c87b251da4a046c87795a0d35f4f927ad8e6" dependencies = [ "aho-corasick", "memchr", "regex-syntax", "thread_local", ] [[package]] name = "regex-syntax" version = "0.6.18" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "26412eb97c6b088a6997e05f69403a802a92d520de2f8e63c2b65f9e0f47c4e8" [[package]] name = "ryu" version = "1.0.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ed3d612bc64430efeb3f7ee6ef26d590dce0c43249217bddc62112540c7941e1" [[package]] name = "serde" version = "1.0.111" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c9124df5b40cbd380080b2cc6ab894c040a3070d995f5c9dc77e18c34a8ae37d" dependencies = [ "serde_derive", ] [[package]] name = "serde_derive" version = "1.0.111" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3f2c3ac8e6ca1e9c80b8be1023940162bf81ae3cffbb1809474152f2ce1eb250" dependencies = [ "proc-macro2", "quote", "syn", ] [[package]] name = "serde_json" version = "1.0.53" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "993948e75b189211a9b31a7528f950c6adc21f9720b6438ff80a7fa2f864cea2" dependencies = [ "itoa", "ryu", "serde", ] [[package]] name = "syn" version = "1.0.29" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "bb37da98a55b1d08529362d9cbb863be17556873df2585904ab9d2bc951291d0" dependencies = [ "proc-macro2", "quote", "unicode-xid", ] [[package]] name = "thread_local" version = "1.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d40c6d1b69745a6ec6fb1ca717914848da4b44ae29d9b3080cbee91d72a69b14" dependencies = [ "lazy_static", ] [[package]] name = "unicode-xid" version = "0.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "826e7639553986605ec5979c7dd957c7895e93eabed50ab2ffa7f6128a75097c" [[package]] name = "winapi" version = "0.3.8" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8093091eeb260906a183e6ae1abdba2ef5ef2257a21801128899c3fc699229c6" dependencies = [ "winapi-i686-pc-windows-gnu", "winapi-x86_64-pc-windows-gnu", ] [[package]] name = "winapi-i686-pc-windows-gnu" version = "0.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6" [[package]] name = "winapi-x86_64-pc-windows-gnu" version = "0.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" [[package]] name = "yansi-term" version = "0.1.2" dependencies = [ "doc-comment", "regex", "serde", "serde_json", "winapi", ] yansi-term-0.1.2/Cargo.toml0000644000000030151366472367000112350ustar00# THIS FILE IS AUTOMATICALLY GENERATED BY CARGO # # When uploading crates to the registry Cargo will automatically # "normalize" Cargo.toml files for maximal compatibility # with all versions of Cargo and also rewrite `path` dependencies # to registry (e.g., crates.io) dependencies # # If you believe there's an error in this file please file an # issue against the rust-lang/cargo repository. If you're # editing this file be aware that the upstream Cargo.toml # will likely look very different (and much more reasonable) [package] edition = "2018" name = "yansi-term" version = "0.1.2" authors = ["ogham@bsago.me", "Ryan Scheel (Havvy) ", "Josh Triplett ", "Juan Aguilar Santillana "] description = "Library for ANSI terminal colours and styles (bold, underline)" homepage = "https://github.com/botika/yansi-term" documentation = "https://docs.rs/yansi-term" readme = "README.md" license = "MIT" repository = "https://github.com/botika/yansi-term" [dependencies.serde] version = "1.0" features = ["derive"] optional = true [dev-dependencies.doc-comment] version = "0.3" [dev-dependencies.regex] version = "1.1" [dev-dependencies.serde_json] version = "1.0" [features] derive_serde_style = ["serde"] [target."cfg(target_os=\"windows\")".dependencies.winapi] version = "0.3.4" features = ["consoleapi", "errhandlingapi", "fileapi", "handleapi", "processenv"] [badges.maintenance] status = "actively-developed" [badges.travis-ci] branch = "master" repository = "botika/yansi-term" yansi-term-0.1.2/Cargo.toml.orig010064400017500001750000000017271366472343000147310ustar0000000000000000[package] name = "yansi-term" description = "Library for ANSI terminal colours and styles (bold, underline)" authors = [ "ogham@bsago.me", "Ryan Scheel (Havvy) ", "Josh Triplett ", "Juan Aguilar Santillana " ] documentation = "https://docs.rs/yansi-term" homepage = "https://github.com/botika/yansi-term" license = "MIT" readme = "README.md" version = "0.1.2" repository = "https://github.com/botika/yansi-term" edition = "2018" [badges] travis-ci = { repository = "botika/yansi-term", branch = "master" } maintenance = { status = "actively-developed" } [features] derive_serde_style = ["serde"] [dependencies.serde] version = "1.0" features = ["derive"] optional = true [target.'cfg(target_os="windows")'.dependencies.winapi] version = "0.3.4" features = ["consoleapi", "errhandlingapi", "fileapi", "handleapi", "processenv"] [dev-dependencies] doc-comment = "0.3" regex = "1.1" serde_json = "1.0" yansi-term-0.1.2/LICENCE010064400017500001750000000020701366464674500130340ustar0000000000000000The MIT License (MIT) Copyright (c) 2014 Benjamin Sago Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. yansi-term-0.1.2/README.md010064400017500001750000000101531366464674500133270ustar0000000000000000# yansi-term [![Latest version](https://img.shields.io/crates/v/yansi-term.svg)](https://crates.io/crates/yansi-term) [![Build Status](https://travis-ci.org/botika/yansi-term.svg?branch=master)](https://travis-ci.org/botika/yansi-term) > Adapted from [`rust-ansi-term`](https://github.com/ogham/rust-ansi-term) Refactor for use [`fmt::Display`](https://doc.rust-lang.org/std/fmt/trait.Display.html) and `FnOnce(&mut fmt::Formatter) -> fmt::Result` This is a library for controlling colours and formatting, such as red bold text or blue underlined text, on ANSI terminals. ### [View the Rustdoc](https://docs.rs/yansi-term) # Installation This crate works with [Cargo](http://crates.io). Add the following to your `Cargo.toml` dependencies section: ```toml [dependencies] yansi-term = "0.1" ``` ## Basic usage There are two main types in this crate that you need to be concerned with: `Style`, and `Colour`. A `Style` holds stylistic information: foreground and background colours, whether the text should be bold, or blinking, or other properties. The `Colour` enum represents the available colours. `Color` is also available as an alias to `Colour`. To format a string, call the `paint` method on a `Style` or a `Colour`, passing in the string you want to format as the argument. For example, here’s how to get some red text: ```rust use yansi_term::Colour::Red; println!("This is in red: {}", Red.paint("a red string")); ``` **Note for Windows 10 users:** On Windows 10, the application must enable ANSI support first: ```rust,ignore let enabled = yansi_term::enable_ansi_support(); ``` ## Bold, underline, background, and other styles For anything more complex than plain foreground colour changes, you need to construct `Style` values themselves, rather than beginning with a `Colour`. You can do this by chaining methods based on a new `Style`, created with `Style::new()`. Each method creates a new style that has that specific property set. For example: ```rust use yansi_term::Style; println!("How about some {} and {}?", Style::new().bold().paint("bold"), Style::new().underline().paint("underline")); ``` For brevity, these methods have also been implemented for `Colour` values, so you can give your styles a foreground colour without having to begin with an empty `Style` value: ```rust use yansi_term::Colour::{Blue, Yellow}; println!("Demonstrating {} and {}!", Blue.bold().paint("blue bold"), Yellow.underline().paint("yellow underline")); println!("Yellow on blue: {}", Yellow.on(Blue).paint("wow!")); ``` The complete list of styles you can use are: `bold`, `dimmed`, `italic`, `underline`, `blink`, `reverse`, `hidden`, and `on` for background colours. In some cases, you may find it easier to change the foreground on an existing `Style` rather than starting from the appropriate `Colour`. You can do this using the `fg` method: ```rust use yansi_term::Style; use yansi_term::Colour::{Blue, Cyan, Yellow}; println!("Yellow on blue: {}", Style::new().on(Blue).fg(Yellow).paint("yow!")); println!("Also yellow on blue: {}", Cyan.on(Blue).fg(Yellow).paint("zow!")); ``` You can turn a `Colour` into a `Style` with the `normal` method. ```rust use yansi_term::Style; use yansi_term::Colour::Red; Red.normal().paint("yet another red string"); Style::default().paint("a completely regular string"); ``` ## Extended colours You can access the extended range of 256 colours by using the `Colour::Fixed` variant, which takes an argument of the colour number to use. This can be included wherever you would use a `Colour`: ```rust use yansi_term::Colour::Fixed; Fixed(134).paint("A sort of light purple"); Fixed(221).on(Fixed(124)).paint("Mustard in the ketchup"); ``` The first sixteen of these values are the same as the normal and bold standard colour variants. There’s nothing stopping you from using these as `Fixed` colours instead, but there’s nothing to be gained by doing so either. You can also access full 24-bit colour by using the `Colour::RGB` variant, which takes separate `u8` arguments for red, green, and blue: ```rust use yansi_term::Colour::RGB; RGB(70, 130, 180).paint("Steel blue"); ``` yansi-term-0.1.2/examples/256_colours.rs010064400017500001750000000031321366464674500163150ustar0000000000000000extern crate yansi_term; use yansi_term::Colour; // This example prints out the 256 colours. // They're arranged like this: // // - 0 to 8 are the eight standard colours. // - 9 to 15 are the eight bold colours. // - 16 to 231 are six blocks of six-by-six colour squares. // - 232 to 255 are shades of grey. fn main() { // First two lines for c in 0..8 { glow(c, c != 0); print!(" "); } println!(); for c in 8..16 { glow(c, c != 8); print!(" "); } println!("\n"); // Six lines of the first three squares for row in 0..6 { for square in 0..3 { for column in 0..6 { glow(16 + square * 36 + row * 6 + column, row >= 3); print!(" "); } print!(" "); } println!(); } println!(); // Six more lines of the other three squares for row in 0..6 { for square in 0..3 { for column in 0..6 { glow(124 + square * 36 + row * 6 + column, row >= 3); print!(" "); } print!(" "); } println!(); } println!(); // The last greyscale lines for c in 232..=243 { glow(c, false); print!(" "); } println!(); for c in 244..=255 { glow(c, true); print!(" "); } println!(); } fn glow(c: u8, light_bg: bool) { let base = if light_bg { Colour::Black } else { Colour::White }; let style = base.on(Colour::Fixed(c)); print!("{}", style.paint_fn(|f| write!(f, " {:3} ", c))); } yansi-term-0.1.2/examples/basic_colours.rs010064400017500001750000000014601366464674500170640ustar0000000000000000extern crate yansi_term; use yansi_term::{Colour::*, Style}; // This example prints out the 16 basic colours. fn main() { let normal = Style::default(); println!("{} {}", normal.paint("Normal"), normal.bold().paint("bold")); println!("{} {}", Black.paint("Black"), Black.bold().paint("bold")); println!("{} {}", Red.paint("Red"), Red.bold().paint("bold")); println!("{} {}", Green.paint("Green"), Green.bold().paint("bold")); println!("{} {}", Yellow.paint("Yellow"), Yellow.bold().paint("bold")); println!("{} {}", Blue.paint("Blue"), Blue.bold().paint("bold")); println!("{} {}", Purple.paint("Purple"), Purple.bold().paint("bold")); println!("{} {}", Cyan.paint("Cyan"), Cyan.bold().paint("bold")); println!("{} {}", White.paint("White"), White.bold().paint("bold")); } yansi-term-0.1.2/examples/overwrite.rs010064400017500001750000000006511366472342400162520ustar0000000000000000extern crate yansi_term; use yansi_term::{Colour::*, Style}; // This example prints out the 16 basic colours. fn main() { println!( "{}", Red.paint_fn(|f| { f.write_str("RED")?; Style::new().bold().write_prefix(f)?; f.write_str("RED_BOLD")?; Style::write_reset(f)?; Black.write_prefix(f)?; f.write_str("BLACK") }) ); } yansi-term-0.1.2/examples/rgb_colours.rs010064400017500001750000000011201366464674500165460ustar0000000000000000extern crate yansi_term; use yansi_term::{Colour, Style}; // This example prints out a colour gradient in a grid by calculating each // character’s red, green, and blue components, and using 24-bit colour codes // to display them. const WIDTH: i32 = 80; const HEIGHT: i32 = 24; fn main() { for row in 0..HEIGHT { for col in 0..WIDTH { let r = (row * 255 / HEIGHT) as u8; let g = (col * 255 / WIDTH) as u8; let b = 128; print!("{}", Style::default().on(Colour::RGB(r, g, b)).paint(" ")); } println!(); } } yansi-term-0.1.2/src/ansi.rs010064400017500001750000000312121366472342400141240ustar0000000000000000use std::fmt::{self, Display, Write}; use crate::{Colour, Style}; impl Style { /// Write any bytes that go *before* a piece of text to the given writer. pub fn write_prefix(&self, f: &mut fmt::Formatter) -> Result { let mut written_anything = false; macro_rules! write_anything { () => { if written_anything { f.write_char(';')?; } else { // Write the codes’ prefix, then write numbers, separated by // semicolons, for each text style we want to apply. f.write_str("\x1B[")?; written_anything = true; } }; } macro_rules! write_char { ($cond:ident, $c:expr) => { if self.$cond { write_anything!(); f.write_char($c)?; } }; } macro_rules! write_chars { ($cond:ident => $c:expr) => { write_char!($cond, $c); }; ($cond:ident => $c:expr, $($t:tt)+) => { write_char!($cond, $c); write_chars!($($t)+); }; } write_chars!( is_bold => '1', is_dimmed => '2', is_italic => '3', is_underline => '4', is_blink => '5', is_reverse => '7', is_hidden => '8', is_strikethrough => '9' ); // The foreground and background colours, if specified, need to be // handled specially because the number codes are more complicated. // (see `write_background_code` and `write_foreground_code`) if let Some(bg) = self.background { write_anything!(); bg.write_background_code(f)?; } if let Some(fg) = self.foreground { write_anything!(); fg.write_foreground_code(f)?; } if written_anything { // All the codes end with an `m`, because reasons. f.write_char('m')?; } Ok(written_anything) } /// Write any bytes that go *after* a piece of text to the given writer. #[inline] pub fn write_reset(f: &mut fmt::Formatter) -> fmt::Result { f.write_str(RESET) } } impl Colour { /// Write any bytes that go *before* a piece of text to the given writer. #[inline] pub fn write_prefix(self, f: &mut fmt::Formatter) -> Result { self.normal().write_prefix(f) } } /// The code to send to reset all styles and return to `Style::default()`. pub static RESET: &str = "\x1B[0m"; macro_rules! write_color { ($_self:ident, $f:ident => $black:expr, $red:expr, $green:expr, $yellow:expr, $blue:expr, $purple:expr, $cyan:expr, $white:expr, $fixed:expr, $rgb:expr) => {{ use Colour::*; match $_self { Black => $f.write_str($black), Red => $f.write_str($red), Green => $f.write_str($green), Yellow => $f.write_str($yellow), Blue => $f.write_str($blue), Purple => $f.write_str($purple), Cyan => $f.write_str($cyan), White => $f.write_str($white), Fixed(num) => { $f.write_str($fixed)?; num.fmt($f) } RGB(r, g, b) => { $f.write_str($rgb)?; r.fmt($f)?; $f.write_char(';')?; g.fmt($f)?; $f.write_char(';')?; b.fmt($f) } } }}; } impl Colour { #[inline] fn write_foreground_code(self, f: &mut fmt::Formatter) -> fmt::Result { write_color!(self, f => "30", "31", "32", "33", "34", "35", "36", "37", "38;5;", "38;2;") } #[inline] fn write_background_code(self, f: &mut fmt::Formatter) -> fmt::Result { write_color!(self, f => "40", "41", "42", "43", "44", "45", "46", "47", "48;5;", "48;2;") } } #[cfg(test)] mod test { use crate::{Colour::*, Style}; macro_rules! test { ($name: ident: $style: expr; $input: expr => $result: expr) => { #[test] fn $name() { assert_eq!($style.paint($input).to_string(), $result.to_string()); } }; } test!(plain: Style::default(); "text/plain" => "text/plain"); test!(red: Red; "hi" => "\x1B[31mhi\x1B[0m"); test!(black: Black.normal(); "hi" => "\x1B[30mhi\x1B[0m"); test!(yellow_bold: Yellow.bold(); "hi" => "\x1B[1;33mhi\x1B[0m"); test!(yellow_bold_2: Yellow.normal().bold(); "hi" => "\x1B[1;33mhi\x1B[0m"); test!(blue_underline: Blue.underline(); "hi" => "\x1B[4;34mhi\x1B[0m"); test!(green_bold_ul: Green.bold().underline(); "hi" => "\x1B[1;4;32mhi\x1B[0m"); test!(green_bold_ul_2: Green.underline().bold(); "hi" => "\x1B[1;4;32mhi\x1B[0m"); test!(purple_on_white: Purple.on(White); "hi" => "\x1B[47;35mhi\x1B[0m"); test!(purple_on_white_2: Purple.normal().on(White); "hi" => "\x1B[47;35mhi\x1B[0m"); test!(yellow_on_blue: Style::new().on(Blue).fg(Yellow); "hi" => "\x1B[44;33mhi\x1B[0m"); test!(yellow_on_blue_2: Cyan.on(Blue).fg(Yellow); "hi" => "\x1B[44;33mhi\x1B[0m"); test!(cyan_bold_on_white: Cyan.bold().on(White); "hi" => "\x1B[1;47;36mhi\x1B[0m"); test!(cyan_ul_on_white: Cyan.underline().on(White); "hi" => "\x1B[4;47;36mhi\x1B[0m"); test!(cyan_bold_ul_on_white: Cyan.bold().underline().on(White); "hi" => "\x1B[1;4;47;36mhi\x1B[0m"); test!(cyan_ul_bold_on_white: Cyan.underline().bold().on(White); "hi" => "\x1B[1;4;47;36mhi\x1B[0m"); test!(fixed: Fixed(100); "hi" => "\x1B[38;5;100mhi\x1B[0m"); test!(fixed_on_purple: Fixed(100).on(Purple); "hi" => "\x1B[45;38;5;100mhi\x1B[0m"); test!(fixed_on_fixed: Fixed(100).on(Fixed(200)); "hi" => "\x1B[48;5;200;38;5;100mhi\x1B[0m"); test!(rgb: RGB(70,130,180); "hi" => "\x1B[38;2;70;130;180mhi\x1B[0m"); test!(rgb_on_blue: RGB(70,130,180).on(Blue); "hi" => "\x1B[44;38;2;70;130;180mhi\x1B[0m"); test!(blue_on_rgb: Blue.on(RGB(70,130,180)); "hi" => "\x1B[48;2;70;130;180;34mhi\x1B[0m"); test!(rgb_on_rgb: RGB(70,130,180).on(RGB(5,10,15)); "hi" => "\x1B[48;2;5;10;15;38;2;70;130;180mhi\x1B[0m"); test!(bold: Style::new().bold(); "hi" => "\x1B[1mhi\x1B[0m"); test!(underline: Style::new().underline(); "hi" => "\x1B[4mhi\x1B[0m"); test!(bunderline: Style::new().bold().underline(); "hi" => "\x1B[1;4mhi\x1B[0m"); test!(dimmed: Style::new().dimmed(); "hi" => "\x1B[2mhi\x1B[0m"); test!(italic: Style::new().italic(); "hi" => "\x1B[3mhi\x1B[0m"); test!(blink: Style::new().blink(); "hi" => "\x1B[5mhi\x1B[0m"); test!(reverse: Style::new().reverse(); "hi" => "\x1B[7mhi\x1B[0m"); test!(hidden: Style::new().hidden(); "hi" => "\x1B[8mhi\x1B[0m"); test!(stricken: Style::new().strikethrough(); "hi" => "\x1B[9mhi\x1B[0m"); macro_rules! test_fn { ($name:ident: $style:expr; $result:expr) => { #[test] fn $name() { let string = String::from("hi"); let string: &str = &string; assert_eq!( $style.paint_fn(|f| f.write_str(string)).to_string(), $result.to_string() ); } }; } test_fn!(plain_fn: Style::default(); "hi"); test_fn!(red_fn: Red; "\x1B[31mhi\x1B[0m"); test_fn!(black_fn: Black.normal(); "\x1B[30mhi\x1B[0m"); test_fn!(yellow_bold_fn: Yellow.bold(); "\x1B[1;33mhi\x1B[0m"); test_fn!(yellow_bold_2_fn: Yellow.normal().bold(); "\x1B[1;33mhi\x1B[0m"); test_fn!(blue_underline_fn: Blue.underline(); "\x1B[4;34mhi\x1B[0m"); test_fn!(green_bold_ul_fn: Green.bold().underline(); "\x1B[1;4;32mhi\x1B[0m"); test_fn!(green_bold_ul_2_fn: Green.underline().bold(); "\x1B[1;4;32mhi\x1B[0m"); test_fn!(purple_on_white_fn: Purple.on(White); "\x1B[47;35mhi\x1B[0m"); test_fn!(purple_on_white_2_fn: Purple.normal().on(White); "\x1B[47;35mhi\x1B[0m"); test_fn!(yellow_on_blue_fn: Style::new().on(Blue).fg(Yellow); "\x1B[44;33mhi\x1B[0m"); test_fn!(yellow_on_blue_2_fn: Cyan.on(Blue).fg(Yellow); "\x1B[44;33mhi\x1B[0m"); test_fn!(cyan_bold_on_white_fn: Cyan.bold().on(White); "\x1B[1;47;36mhi\x1B[0m"); test_fn!(cyan_ul_on_white_fn: Cyan.underline().on(White); "\x1B[4;47;36mhi\x1B[0m"); test_fn!(cyan_bold_ul_on_white_fn: Cyan.bold().underline().on(White); "\x1B[1;4;47;36mhi\x1B[0m"); test_fn!(cyan_ul_bold_on_white_fn: Cyan.underline().bold().on(White); "\x1B[1;4;47;36mhi\x1B[0m"); test_fn!(fixed_fn: Fixed(100); "\x1B[38;5;100mhi\x1B[0m"); test_fn!(fixed_on_purple_fn: Fixed(100).on(Purple); "\x1B[45;38;5;100mhi\x1B[0m"); test_fn!(fixed_on_fixed_fn: Fixed(100).on(Fixed(200)); "\x1B[48;5;200;38;5;100mhi\x1B[0m"); test_fn!(rgb_fn: RGB(70,130,180); "\x1B[38;2;70;130;180mhi\x1B[0m"); test_fn!(rgb_on_blue_fn: RGB(70,130,180).on(Blue); "\x1B[44;38;2;70;130;180mhi\x1B[0m"); test_fn!(blue_on_rgb_fn: Blue.on(RGB(70,130,180)); "\x1B[48;2;70;130;180;34mhi\x1B[0m"); test_fn!(rgb_on_rgb_fn: RGB(70,130,180).on(RGB(5,10,15)); "\x1B[48;2;5;10;15;38;2;70;130;180mhi\x1B[0m"); test_fn!(bold_fn: Style::new().bold(); "\x1B[1mhi\x1B[0m"); test_fn!(underline_fn: Style::new().underline(); "\x1B[4mhi\x1B[0m"); test_fn!(bunderline_fn: Style::new().bold().underline(); "\x1B[1;4mhi\x1B[0m"); test_fn!(dimmed_fn: Style::new().dimmed(); "\x1B[2mhi\x1B[0m"); test_fn!(italic_fn: Style::new().italic(); "\x1B[3mhi\x1B[0m"); test_fn!(blink_fn: Style::new().blink(); "\x1B[5mhi\x1B[0m"); test_fn!(reverse_fn: Style::new().reverse(); "\x1B[7mhi\x1B[0m"); test_fn!(hidden_fn: Style::new().hidden(); "\x1B[8mhi\x1B[0m"); test_fn!(stricken_fn: Style::new().strikethrough(); "\x1B[9mhi\x1B[0m"); #[test] fn test_move() { let string = String::from("hi"); assert_eq!( Style::default() .paint_fn(|f| f.write_str(&string)) .to_string(), "hi" ); } #[test] fn test_ref() { let string = &String::from("hi"); assert_eq!( Style::default() .paint_fn(|f| f.write_str(string)) .to_string(), "hi" ); } #[test] fn test_debug() { let a = vec![1, 2, 3]; assert_eq!( Style::default() .paint_fn(|f| std::fmt::Debug::fmt(&a, f)) .to_string(), "[1, 2, 3]" ); assert_eq!( Style::default() .bold() .paint_fn(|f| std::fmt::Debug::fmt(&a, f)) .to_string(), "\x1B[1m[1, 2, 3]\x1B[0m" ); } #[test] fn test_write() { assert_eq!( Style::default() .paint_fn(|f| write!(f, "{:.5}", 1.0)) .to_string(), "1.00000" ); assert_eq!( Style::default() .bold() .paint_fn(|f| write!(f, "{:.5}", 1.0)) .to_string(), "\x1B[1m1.00000\x1B[0m" ); } /// Can not write the same `impl Display` two or more times /// else return error #[test] fn test_error() { use std::fmt::Write; let a = Style::default().paint("foo"); let _ = a.to_string(); let mut b = String::new(); assert!(write!(b, "{}", a).is_err()); } } yansi-term-0.1.2/src/display.rs010064400017500001750000000040671366472342400146470ustar0000000000000000use std::{cell::Cell, fmt}; use crate::{Colour, Style}; /// An `DisplayANSI` includes a format function and a `Style` struct DisplayANSI fmt::Result> { style: Style, f: Cell>, } impl fmt::Result> fmt::Display for DisplayANSI { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { let written = self.style.write_prefix(f)?; self.f.take().ok_or(fmt::Error).and_then(|c| c(f))?; if written { Style::write_reset(f)?; } Ok(()) } } impl Style { /// Paints the given text with this style #[inline] pub fn paint<'a>(self, input: &'a str) -> impl fmt::Display + 'a { DisplayANSI { f: Cell::new(Some(move |f: &mut fmt::Formatter| f.write_str(input))), style: self, } } /// Paints the given format function with this style #[inline] pub fn paint_fn fmt::Result>( self, f: F, ) -> impl fmt::Display { DisplayANSI { f: Cell::new(Some(f)), style: self, } } } impl Colour { /// Paints the given text with this colour /// This is a short-cut so you don’t have to use `Blue.normal()` just /// to get blue text. /// /// ``` /// use yansi_term::Colour::Blue; /// println!("{}", Blue.paint("da ba dee")); /// ``` #[inline] pub fn paint<'a>(self, input: &'a str) -> impl fmt::Display + 'a { self.normal().paint(input) } /// Paints the given format function with this colour #[inline] pub fn paint_fn fmt::Result>( self, f: F, ) -> impl fmt::Display { self.normal().paint_fn(f) } } #[cfg(test)] mod tests { use super::*; #[test] fn no_control_codes_for_plain() { let one = Style::default().paint("one"); let two = Style::default().paint("two"); let output = format!("{}{}", one, two); assert_eq!(output, "onetwo"); } } yansi-term-0.1.2/src/lib.rs010064400017500001750000000135571366464674500137660ustar0000000000000000//! > Adapted from [`rust-ansi-term`](https://github.com/ogham/rust-ansi-term) //! > //! > Refactor for use [`fmt::Display`](https://doc.rust-lang.org/std/fmt/trait.Display.html) //! and `FnOnce(&mut fmt::Formatter) -> fmt::Result` //! This is a library for controlling colours and formatting, such as //! red bold text or blue underlined text, on ANSI terminals. //! //! //! ## Basic usage //! //! There are three main types in this crate that you need to be //! concerned with: [`ANSIString`], [`Style`], and [`Colour`]. //! //! A `Style` holds stylistic information: foreground and background colours, //! whether the text should be bold, or blinking, or other properties. The //! [`Colour`] enum represents the available colours. And an [`ANSIString`] is a //! string paired with a [`Style`]. //! //! [`Color`] is also available as an alias to `Colour`. //! //! To format a string, call the `paint` method on a `Style` or a `Colour`, //! passing in the string you want to format as the argument. For example, //! here’s how to get some red text: //! //! ``` //! use yansi_term::Colour::Red; //! //! println!("This is in red: {}", Red.paint("a red string")); //! ``` //! //! It’s important to note that the `paint` method does *not* actually return a //! string with the ANSI control characters surrounding it. Instead, it returns //! that has a [`Display`] implementation that, when formatted, returns the characters. //! ``` //! use yansi_term::Colour::Red; //! //! let red_string = Red.paint("a red string").to_string(); //! ``` //! //! //! ## Bold, underline, background, and other styles //! //! For anything more complex than plain foreground colour changes, you need to //! construct `Style` values themselves, rather than beginning with a `Colour`. //! You can do this by chaining methods based on a new `Style`, created with //! [`Style::new()`]. Each method creates a new style that has that specific //! property set. For example: //! //! ``` //! use yansi_term::Style; //! //! println!("How about some {} and {}?", //! Style::new().bold().paint("bold"), //! Style::new().underline().paint("underline")); //! ``` //! //! For brevity, these methods have also been implemented for `Colour` values, //! so you can give your styles a foreground colour without having to begin with //! an empty `Style` value: //! //! ``` //! use yansi_term::Colour::{Blue, Yellow}; //! //! println!("Demonstrating {} and {}!", //! Blue.bold().paint("blue bold"), //! Yellow.underline().paint("yellow underline")); //! //! println!("Yellow on blue: {}", Yellow.on(Blue).paint("wow!")); //! ``` //! //! The complete list of styles you can use are: [`bold`], [`dimmed`], [`italic`], //! [`underline`], [`blink`], [`reverse`], [`hidden`], [`strikethrough`], and [`on`] for //! background colours. //! //! In some cases, you may find it easier to change the foreground on an //! existing `Style` rather than starting from the appropriate `Colour`. //! You can do this using the [`fg`] method: //! //! ``` //! use yansi_term::Style; //! use yansi_term::Colour::{Blue, Cyan, Yellow}; //! //! println!("Yellow on blue: {}", Style::new().on(Blue).fg(Yellow).paint("yow!")); //! println!("Also yellow on blue: {}", Cyan.on(Blue).fg(Yellow).paint("zow!")); //! ``` //! //! You can turn a `Colour` into a `Style` with the [`normal`] method. //! This will produce the exact same `ANSIString` as if you just used the //! `paint` method on the `Colour` directly, but it’s useful in certain cases: //! for example, you may have a method that returns `Styles`, and need to //! represent both the “red bold” and “red, but not bold” styles with values of //! the same type. The `Style` struct also has a [`Default`] implementation if you //! want to have a style with *nothing* set. //! //! ``` //! use yansi_term::Style; //! use yansi_term::Colour::Red; //! //! Red.normal().paint("yet another red string"); //! Style::default().paint("a completely regular string"); //! ``` //! //! //! ## Extended colours //! //! You can access the extended range of 256 colours by using the `Colour::Fixed` //! variant, which takes an argument of the colour number to use. This can be //! included wherever you would use a `Colour`: //! //! ``` //! use yansi_term::Colour::Fixed; //! //! Fixed(134).paint("A sort of light purple"); //! Fixed(221).on(Fixed(124)).paint("Mustard in the ketchup"); //! ``` //! //! The first sixteen of these values are the same as the normal and bold //! standard colour variants. There’s nothing stopping you from using these as //! `Fixed` colours instead, but there’s nothing to be gained by doing so //! either. //! //! You can also access full 24-bit colour by using the `Colour::RGB` variant, //! which takes separate `u8` arguments for red, green, and blue: //! //! ``` //! use yansi_term::Colour::RGB; //! //! RGB(70, 130, 180).paint("Steel blue"); //! ``` //! [`Display`]: https://doc.rust-lang.org/std/fmt/trait.Display.html //! [`Default`]: https://doc.rust-lang.org/std/default/trait.Default.html //! [`Style`]: struct.Style.html //! [`Style::new()`]: struct.Style.html#method.new //! [`Color`]: enum.Color.html //! [`Colour`]: enum.Colour.html //! //! [`bold`]: struct.Style.html#method.bold //! [`dimmed`]: struct.Style.html#method.dimmed //! [`italic`]: struct.Style.html#method.italic //! [`underline`]: struct.Style.html#method.underline //! [`blink`]: struct.Style.html#method.blink //! [`reverse`]: struct.Style.html#method.reverse //! [`hidden`]: struct.Style.html#method.hidden //! [`strikethrough`]: struct.Style.html#method.strikethrough //! [`fg`]: struct.Style.html#method.fg //! [`on`]: struct.Style.html#method.on #[cfg(target_os = "windows")] extern crate winapi; #[cfg(test)] #[macro_use] extern crate doc_comment; #[cfg(test)] doctest!("../README.md"); mod ansi; mod style; pub use style::{Colour, Style}; /// Color is a type alias for `Colour`. pub use Colour as Color; mod display; mod windows; pub use windows::*; yansi-term-0.1.2/src/style.rs010064400017500001750000000336011366464674500143500ustar0000000000000000/// A style is a collection of properties that can format a string /// using ANSI escape codes. /// /// # Examples /// /// ``` /// use yansi_term::{Style, Colour}; /// /// let style = Style::new().bold().on(Colour::Black); /// println!("{}", style.paint("Bold on black")); /// ``` #[derive(PartialEq, Clone, Copy, Default, Debug)] #[cfg_attr( feature = "derive_serde_style", derive(serde::Deserialize, serde::Serialize) )] pub struct Style { /// The style's foreground colour, if it has one. pub foreground: Option, /// The style's background colour, if it has one. pub background: Option, /// Whether this style is bold. pub is_bold: bool, /// Whether this style is dimmed. pub is_dimmed: bool, /// Whether this style is italic. pub is_italic: bool, /// Whether this style is underlined. pub is_underline: bool, /// Whether this style is blinking. pub is_blink: bool, /// Whether this style has reverse colours. pub is_reverse: bool, /// Whether this style is hidden. pub is_hidden: bool, /// Whether this style is struckthrough. pub is_strikethrough: bool, } impl Style { /// Creates a new Style with no properties set. /// /// # Examples /// /// ``` /// use yansi_term::Style; /// /// let style = Style::new(); /// println!("{}", style.paint("hi")); /// ``` pub fn new() -> Style { Style::default() } /// Returns a `Style` with the bold property set. /// /// # Examples /// /// ``` /// use yansi_term::Style; /// /// let style = Style::new().bold(); /// println!("{}", style.paint("hey")); /// ``` pub fn bold(mut self) -> Self { self.is_bold = true; self } /// Returns a `Style` with the dimmed property set. /// /// # Examples /// /// ``` /// use yansi_term::Style; /// /// let style = Style::new().dimmed(); /// println!("{}", style.paint("sup")); /// ``` pub fn dimmed(mut self) -> Self { self.is_dimmed = true; self } /// Returns a `Style` with the italic property set. /// /// # Examples /// /// ``` /// use yansi_term::Style; /// /// let style = Style::new().italic(); /// println!("{}", style.paint("greetings")); /// ``` pub fn italic(mut self) -> Self { self.is_italic = true; self } /// Returns a `Style` with the underline property set. /// /// # Examples /// /// ``` /// use yansi_term::Style; /// /// let style = Style::new().underline(); /// println!("{}", style.paint("salutations")); /// ``` pub fn underline(mut self) -> Self { self.is_underline = true; self } /// Returns a `Style` with the blink property set. /// # Examples /// /// ``` /// use yansi_term::Style; /// /// let style = Style::new().blink(); /// println!("{}", style.paint("wazzup")); /// ``` pub fn blink(mut self) -> Self { self.is_blink = true; self } /// Returns a `Style` with the reverse property set. /// /// # Examples /// /// ``` /// use yansi_term::Style; /// /// let style = Style::new().reverse(); /// println!("{}", style.paint("aloha")); /// ``` pub fn reverse(mut self) -> Self { self.is_reverse = true; self } /// Returns a `Style` with the hidden property set. /// /// # Examples /// /// ``` /// use yansi_term::Style; /// /// let style = Style::new().hidden(); /// println!("{}", style.paint("ahoy")); /// ``` pub fn hidden(mut self) -> Self { self.is_hidden = true; self } /// Returns a `Style` with the strikethrough property set. /// /// # Examples /// /// ``` /// use yansi_term::Style; /// /// let style = Style::new().strikethrough(); /// println!("{}", style.paint("yo")); /// ``` pub fn strikethrough(mut self) -> Self { self.is_strikethrough = true; self } /// Returns a `Style` with the foreground colour property set. /// /// # Examples /// /// ``` /// use yansi_term::{Style, Colour}; /// /// let style = Style::new().fg(Colour::Yellow); /// println!("{}", style.paint("hi")); /// ``` pub fn fg(mut self, foreground: Colour) -> Self { self.foreground = Some(foreground); self } /// Returns a `Style` with the background colour property set. /// /// # Examples /// /// ``` /// use yansi_term::{Style, Colour}; /// /// let style = Style::new().on(Colour::Blue); /// println!("{}", style.paint("eyyyy")); /// ``` pub fn on(mut self, background: Colour) -> Self { self.background = Some(background); self } /// Return true if this `Style` has no actual styles, and can be written /// without any control characters. /// /// # Examples /// /// ``` /// use yansi_term::Style; /// /// assert_eq!(true, Style::default().is_plain()); /// assert_eq!(false, Style::default().bold().is_plain()); /// ``` pub fn is_plain(&self) -> bool { *self == Style::default() } } /// A colour is one specific type of ANSI escape code, and can refer /// to either the foreground or background colour. /// /// These use the standard numeric sequences. /// See #[derive(PartialEq, Clone, Copy, Debug)] #[cfg_attr( feature = "derive_serde_style", derive(serde::Deserialize, serde::Serialize) )] pub enum Colour { /// Colour #0 (foreground code `30`, background code `40`). /// /// This is not necessarily the background colour, and using it as one may /// render the text hard to read on terminals with dark backgrounds. Black, /// Colour #1 (foreground code `31`, background code `41`). Red, /// Colour #2 (foreground code `32`, background code `42`). Green, /// Colour #3 (foreground code `33`, background code `43`). Yellow, /// Colour #4 (foreground code `34`, background code `44`). Blue, /// Colour #5 (foreground code `35`, background code `45`). Purple, /// Colour #6 (foreground code `36`, background code `46`). Cyan, /// Colour #7 (foreground code `37`, background code `47`). /// /// As above, this is not necessarily the foreground colour, and may be /// hard to read on terminals with light backgrounds. White, /// A colour number from 0 to 255, for use in 256-colour terminal /// environments. /// /// - Colours 0 to 7 are the `Black` to `White` variants respectively. /// These colours can usually be changed in the terminal emulator. /// - Colours 8 to 15 are brighter versions of the eight colours above. /// These can also usually be changed in the terminal emulator, or it /// could be configured to use the original colours and show the text in /// bold instead. It varies depending on the program. /// - Colours 16 to 231 contain several palettes of bright colours, /// arranged in six squares measuring six by six each. /// - Colours 232 to 255 are shades of grey from black to white. /// /// It might make more sense to look at a [colour chart][cc]. /// /// [cc]: https://upload.wikimedia.org/wikipedia/commons/1/15/Xterm_256color_chart.svg Fixed(u8), /// A 24-bit RGB color, as specified by ISO-8613-3. RGB(u8, u8, u8), } impl Colour { /// Returns a `Style` with the foreground colour set to this colour. /// /// # Examples /// /// ``` /// use yansi_term::Colour; /// /// let style = Colour::Red.normal(); /// println!("{}", style.paint("hi")); /// ``` pub fn normal(self) -> Style { Style { foreground: Some(self), ..Style::default() } } /// Returns a `Style` with the foreground colour set to this colour and the /// bold property set. /// /// # Examples /// /// ``` /// use yansi_term::Colour; /// /// let style = Colour::Green.bold(); /// println!("{}", style.paint("hey")); /// ``` pub fn bold(self) -> Style { Style { foreground: Some(self), is_bold: true, ..Style::default() } } /// Returns a `Style` with the foreground colour set to this colour and the /// dimmed property set. /// /// # Examples /// /// ``` /// use yansi_term::Colour; /// /// let style = Colour::Yellow.dimmed(); /// println!("{}", style.paint("sup")); /// ``` pub fn dimmed(self) -> Style { Style { foreground: Some(self), is_dimmed: true, ..Style::default() } } /// Returns a `Style` with the foreground colour set to this colour and the /// italic property set. /// /// # Examples /// /// ``` /// use yansi_term::Colour; /// /// let style = Colour::Blue.italic(); /// println!("{}", style.paint("greetings")); /// ``` pub fn italic(self) -> Style { Style { foreground: Some(self), is_italic: true, ..Style::default() } } /// Returns a `Style` with the foreground colour set to this colour and the /// underline property set. /// /// # Examples /// /// ``` /// use yansi_term::Colour; /// /// let style = Colour::Purple.underline(); /// println!("{}", style.paint("salutations")); /// ``` pub fn underline(self) -> Style { Style { foreground: Some(self), is_underline: true, ..Style::default() } } /// Returns a `Style` with the foreground colour set to this colour and the /// blink property set. /// /// # Examples /// /// ``` /// use yansi_term::Colour; /// /// let style = Colour::Cyan.blink(); /// println!("{}", style.paint("wazzup")); /// ``` pub fn blink(self) -> Style { Style { foreground: Some(self), is_blink: true, ..Style::default() } } /// Returns a `Style` with the foreground colour set to this colour and the /// reverse property set. /// /// # Examples /// /// ``` /// use yansi_term::Colour; /// /// let style = Colour::Black.reverse(); /// println!("{}", style.paint("aloha")); /// ``` pub fn reverse(self) -> Style { Style { foreground: Some(self), is_reverse: true, ..Style::default() } } /// Returns a `Style` with the foreground colour set to this colour and the /// hidden property set. /// /// # Examples /// /// ``` /// use yansi_term::Colour; /// /// let style = Colour::White.hidden(); /// println!("{}", style.paint("ahoy")); /// ``` pub fn hidden(self) -> Style { Style { foreground: Some(self), is_hidden: true, ..Style::default() } } /// Returns a `Style` with the foreground colour set to this colour and the /// strikethrough property set. /// /// # Examples /// /// ``` /// use yansi_term::Colour; /// /// let style = Colour::Fixed(244).strikethrough(); /// println!("{}", style.paint("yo")); /// ``` pub fn strikethrough(self) -> Style { Style { foreground: Some(self), is_strikethrough: true, ..Style::default() } } /// Returns a `Style` with the foreground colour set to this colour and the /// background colour property set to the given colour. /// /// # Examples /// /// ``` /// use yansi_term::Colour; /// /// let style = Colour::RGB(31, 31, 31).on(Colour::White); /// println!("{}", style.paint("eyyyy")); /// ``` pub fn on(self, background: Colour) -> Style { Style { foreground: Some(self), background: Some(background), ..Style::default() } } } impl From for Style { /// You can turn a `Colour` into a `Style` with the foreground colour set /// with the `From` trait. /// /// ``` /// use yansi_term::{Style, Colour}; /// let green_foreground = Style::default().fg(Colour::Green); /// assert_eq!(green_foreground, Colour::Green.normal()); /// assert_eq!(green_foreground, Colour::Green.into()); /// assert_eq!(green_foreground, Style::from(Colour::Green)); /// ``` fn from(colour: Colour) -> Style { colour.normal() } } #[cfg(test)] #[cfg(feature = "derive_serde_style")] mod serde_json_tests { use super::{Colour, Style}; #[test] fn colour_serialization() { let colours = &[ Colour::Red, Colour::Blue, Colour::RGB(123, 123, 123), Colour::Fixed(255), ]; assert_eq!( serde_json::to_string(&colours).unwrap(), String::from("[\"Red\",\"Blue\",{\"RGB\":[123,123,123]},{\"Fixed\":255}]") ); } #[test] fn colour_deserialization() { let colours = &[ Colour::Red, Colour::Blue, Colour::RGB(123, 123, 123), Colour::Fixed(255), ]; for colour in colours { let serialized = serde_json::to_string(&colour).unwrap(); let deserialized: Colour = serde_json::from_str(&serialized).unwrap(); assert_eq!(colour, &deserialized); } } #[test] fn style_serialization() { let style = Style::default(); assert_eq!(serde_json::to_string(&style).unwrap(), "{\"foreground\":null,\"background\":null,\"is_bold\":false,\"is_dimmed\":false,\"is_italic\":false,\"is_underline\":false,\"is_blink\":false,\"is_reverse\":false,\"is_hidden\":false,\"is_strikethrough\":false}".to_string()); } } yansi-term-0.1.2/src/windows.rs010064400017500001750000000045071366464674500147050ustar0000000000000000/// Enables ANSI code support on Windows 10. /// /// This uses Windows API calls to alter the properties of the console that /// the program is running in. /// /// https://msdn.microsoft.com/en-us/library/windows/desktop/mt638032(v=vs.85).aspx /// /// Returns a `Result` with the Windows error code if unsuccessful. #[cfg(windows)] pub fn enable_ansi_support() -> Result<(), u32> { // ref: https://docs.microsoft.com/en-us/windows/console/console-virtual-terminal-sequences#EXAMPLE_OF_ENABLING_VIRTUAL_TERMINAL_PROCESSING @@ https://archive.is/L7wRJ#76% use std::{ffi::OsStr, iter::once, os::windows::ffi::OsStrExt, ptr::null_mut}; use winapi::um::{ consoleapi::{GetConsoleMode, SetConsoleMode}, errhandlingapi::GetLastError, fileapi::{CreateFileW, OPEN_EXISTING}, handleapi::INVALID_HANDLE_VALUE, winnt::{FILE_SHARE_WRITE, GENERIC_READ, GENERIC_WRITE}, }; const ENABLE_VIRTUAL_TERMINAL_PROCESSING: u32 = 0x0004; unsafe { // ref: https://docs.microsoft.com/en-us/windows/win32/api/fileapi/nf-fileapi-createfilew // Using `CreateFileW("CONOUT$", ...)` to retrieve the console handle works correctly even if STDOUT and/or STDERR are redirected let console_out_name: Vec = OsStr::new("CONOUT$").encode_wide().chain(once(0)).collect(); let console_handle = CreateFileW( console_out_name.as_ptr(), GENERIC_READ | GENERIC_WRITE, FILE_SHARE_WRITE, null_mut(), OPEN_EXISTING, 0, null_mut(), ); if console_handle == INVALID_HANDLE_VALUE { return Err(GetLastError()); } // ref: https://docs.microsoft.com/en-us/windows/console/getconsolemode let mut console_mode: u32 = 0; if 0 == GetConsoleMode(console_handle, &mut console_mode) { return Err(GetLastError()); } // VT processing not already enabled? if console_mode & ENABLE_VIRTUAL_TERMINAL_PROCESSING == 0 { // https://docs.microsoft.com/en-us/windows/console/setconsolemode if 0 == SetConsoleMode( console_handle, console_mode | ENABLE_VIRTUAL_TERMINAL_PROCESSING, ) { return Err(GetLastError()); } } } return Ok(()); }