colored-1.6.1/.gitignore010064400007650000024000000000271332070115100133450ustar0000000000000000target Cargo.lock *.bk colored-1.6.1/.travis.yml010064400007650000024000000001451332070115100134670ustar0000000000000000language: rust rust: - nightly - beta - stable matrix: allow_failures: - rust: nightly colored-1.6.1/Cargo.toml.orig010064400007650000024000000010411332070457300142540ustar0000000000000000[package] name = "colored" description = "The most simple way to add colors in your terminal" version = "1.6.1" authors = ["Thomas Wickham "] license = "MPL-2.0" homepage = "https://github.com/mackwic/colored" repository = "https://github.com/mackwic/colored" readme = "README.md" keywords = ["color", "string", "term", "ansi_term", "term-painter"] [features] # with this feature, no color will ever be written no-color = [] [dependencies] lazy_static = "^1.0" [dev_dependencies] ansi_term = "^0.9" rspec = "=1.0.0-beta.3" colored-1.6.1/Cargo.toml0000644000000020440000000000000105250ustar00# 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] name = "colored" version = "1.6.1" authors = ["Thomas Wickham "] description = "The most simple way to add colors in your terminal" homepage = "https://github.com/mackwic/colored" readme = "README.md" keywords = ["color", "string", "term", "ansi_term", "term-painter"] license = "MPL-2.0" repository = "https://github.com/mackwic/colored" [dependencies.lazy_static] version = "^1.0" [dev-dependencies.ansi_term] version = "^0.9" [dev-dependencies.rspec] version = "=1.0.0-beta.3" [features] no-color = [] colored-1.6.1/CHANGELOG.md010064400007650000024000000024731332070543000132010ustar0000000000000000 # 1.6.1 (July 9, 2018) - TECH: update lazy\_static - CHORE: fix typos in README and documentation # 1.6.0 (October 31, 2017) - FEAT: introduced bright colors. `"hello".bright_blue().on_bright_red();` - FEAT: introduced strikethrough styling. `"hello".strikethrough();` # 1.5.3 (September 28, 2017) - FEAT: derive Copy and Clone for `Color` - FEAT: derive Clone for `ColoredString` # 1.5.2 (July 6, 2017) - FIX: method `Colorize::reversed` has been added. `Colorize::reverse` was a typo, that we will keep for compatibility # 1.5.1 (May 9, 2017) - Update lazy\_static to 0.2. # 1.5.0 (May 1, 2017) - FEAT: support for `"hello".color("blue")` (dynamic colors) # 1.3.2 (Nov 26, 2016) - FIX: usage of nested ColoredString again, no more style broken mid-line # 1.3.1 (Oct 14, 2016) - FIX: usage of ColoredString in a nested way broke the styling mid-line # 1.3.0 (Jul 31, 2016) - Provide various options for disabling the coloring in an API-compatible way # 1.2.0 (Mar 30, 2016) - Support the different formatting options, like padding and alignment # 1.1.0 (Mar 15, 2016) - Respect the CLICOLOR/CLICOLOR\_FORCE behavior. See [this specs](http://bixense.com/clicolors/) # 1.0.1 (Mar 14, 2016) - Add a CHANGLOG - Fix crate dependencies: move `ansi_term` in dev\_dependencies # 1.0.0 (Mar 13, 2016) - Initial release colored-1.6.1/examples/control.rs010064400007650000024000000007471332070115100152320ustar0000000000000000extern crate colored; use colored::*; fn main() { // this will be yellow if your environment allow it println!("{}", "some warning".yellow()); // now , this will be always yellow colored::control::set_override(true); println!("{}", "some warning".yellow()); // now, this will be never yellow colored::control::set_override(false); println!("{}", "some warning".yellow()); // let the environment decide again colored::control::unset_override(); } colored-1.6.1/examples/dynamic_colors.rs010064400007650000024000000005371332070115100165540ustar0000000000000000extern crate colored; use colored::*; fn main() { // the easy way "blue string yo".color("blue"); // this will default to white "white string".color("zorglub"); // the safer way via a Result let color_res = "zorglub".parse(); // <- this returns a Result "red string".color(color_res.unwrap_or(Color::Red)); } colored-1.6.1/examples/most_simple.rs010064400007650000024000000011051332070342600161010ustar0000000000000000extern crate colored; use colored::*; fn main() { // TADAA ! println!( "{} {} {}!", "it".green(), "works".blue().bold(), "great".bold().yellow() ); println!("{}", String::from("this also works!").green().bold()); let mut s = String::new(); s.push_str(&"why not ".red().to_string()); s.push_str(&"push things ".blue().to_string()); s.push_str(&"a little further ?".green().to_string()); println!("{}", s); let s = format!("{} {} {}", "this".red(), "is".blue(), "easier".green()); println!("{}", s); } colored-1.6.1/examples/nested_colors.rs010064400007650000024000000006601332070115100164070ustar0000000000000000extern crate colored; use colored::*; /* * This example use colored strings in a nested way (at line 14). It shows that colored is able to * keep the correct color on the “!lalalala” part. */ fn main() { let world = "world".bold(); let hello_world = format!("Hello, {}!", world); println!("{}", hello_world); let hello_world = format!("Hello, {}!lalalala", world).red(); println!("{}", hello_world); } colored-1.6.1/LICENSE010064400007650000024000000405261332070115100123720ustar0000000000000000Mozilla Public License Version 2.0 ================================== 1. Definitions -------------- 1.1. "Contributor" means each individual or legal entity that creates, contributes to the creation of, or owns Covered Software. 1.2. "Contributor Version" means the combination of the Contributions of others (if any) used by a Contributor and that particular Contributor's Contribution. 1.3. "Contribution" means Covered Software of a particular Contributor. 1.4. "Covered Software" means Source Code Form to which the initial Contributor has attached the notice in Exhibit A, the Executable Form of such Source Code Form, and Modifications of such Source Code Form, in each case including portions thereof. 1.5. "Incompatible With Secondary Licenses" means (a) that the initial Contributor has attached the notice described in Exhibit B to the Covered Software; or (b) that the Covered Software was made available under the terms of version 1.1 or earlier of the License, but not also under the terms of a Secondary License. 1.6. "Executable Form" means any form of the work other than Source Code Form. 1.7. "Larger Work" means a work that combines Covered Software with other material, in a separate file or files, that is not Covered Software. 1.8. "License" means this document. 1.9. "Licensable" means having the right to grant, to the maximum extent possible, whether at the time of the initial grant or subsequently, any and all of the rights conveyed by this License. 1.10. "Modifications" means any of the following: (a) any file in Source Code Form that results from an addition to, deletion from, or modification of the contents of Covered Software; or (b) any new file in Source Code Form that contains any Covered Software. 1.11. "Patent Claims" of a Contributor means any patent claim(s), including without limitation, method, process, and apparatus claims, in any patent Licensable by such Contributor that would be infringed, but for the grant of the License, by the making, using, selling, offering for sale, having made, import, or transfer of either its Contributions or its Contributor Version. 1.12. "Secondary License" means either the GNU General Public License, Version 2.0, the GNU Lesser General Public License, Version 2.1, the GNU Affero General Public License, Version 3.0, or any later versions of those licenses. 1.13. "Source Code Form" means the form of the work preferred for making modifications. 1.14. "You" (or "Your") means an individual or a legal entity exercising rights under this License. For legal entities, "You" includes any entity that controls, is controlled by, or is under common control with You. For purposes of this definition, "control" means (a) the power, direct or indirect, to cause the direction or management of such entity, whether by contract or otherwise, or (b) ownership of more than fifty percent (50%) of the outstanding shares or beneficial ownership of such entity. 2. License Grants and Conditions -------------------------------- 2.1. Grants Each Contributor hereby grants You a world-wide, royalty-free, non-exclusive license: (a) under intellectual property rights (other than patent or trademark) Licensable by such Contributor to use, reproduce, make available, modify, display, perform, distribute, and otherwise exploit its Contributions, either on an unmodified basis, with Modifications, or as part of a Larger Work; and (b) under Patent Claims of such Contributor to make, use, sell, offer for sale, have made, import, and otherwise transfer either its Contributions or its Contributor Version. 2.2. Effective Date The licenses granted in Section 2.1 with respect to any Contribution become effective for each Contribution on the date the Contributor first distributes such Contribution. 2.3. Limitations on Grant Scope The licenses granted in this Section 2 are the only rights granted under this License. No additional rights or licenses will be implied from the distribution or licensing of Covered Software under this License. Notwithstanding Section 2.1(b) above, no patent license is granted by a Contributor: (a) for any code that a Contributor has removed from Covered Software; or (b) for infringements caused by: (i) Your and any other third party's modifications of Covered Software, or (ii) the combination of its Contributions with other software (except as part of its Contributor Version); or (c) under Patent Claims infringed by Covered Software in the absence of its Contributions. This License does not grant any rights in the trademarks, service marks, or logos of any Contributor (except as may be necessary to comply with the notice requirements in Section 3.4). 2.4. Subsequent Licenses No Contributor makes additional grants as a result of Your choice to distribute the Covered Software under a subsequent version of this License (see Section 10.2) or under the terms of a Secondary License (if permitted under the terms of Section 3.3). 2.5. Representation Each Contributor represents that the Contributor believes its Contributions are its original creation(s) or it has sufficient rights to grant the rights to its Contributions conveyed by this License. 2.6. Fair Use This License is not intended to limit any rights You have under applicable copyright doctrines of fair use, fair dealing, or other equivalents. 2.7. Conditions Sections 3.1, 3.2, 3.3, and 3.4 are conditions of the licenses granted in Section 2.1. 3. Responsibilities ------------------- 3.1. Distribution of Source Form All distribution of Covered Software in Source Code Form, including any Modifications that You create or to which You contribute, must be under the terms of this License. You must inform recipients that the Source Code Form of the Covered Software is governed by the terms of this License, and how they can obtain a copy of this License. You may not attempt to alter or restrict the recipients' rights in the Source Code Form. 3.2. Distribution of Executable Form If You distribute Covered Software in Executable Form then: (a) such Covered Software must also be made available in Source Code Form, as described in Section 3.1, and You must inform recipients of the Executable Form how they can obtain a copy of such Source Code Form by reasonable means in a timely manner, at a charge no more than the cost of distribution to the recipient; and (b) You may distribute such Executable Form under the terms of this License, or sublicense it under different terms, provided that the license for the Executable Form does not attempt to limit or alter the recipients' rights in the Source Code Form under this License. 3.3. Distribution of a Larger Work You may create and distribute a Larger Work under terms of Your choice, provided that You also comply with the requirements of this License for the Covered Software. If the Larger Work is a combination of Covered Software with a work governed by one or more Secondary Licenses, and the Covered Software is not Incompatible With Secondary Licenses, this License permits You to additionally distribute such Covered Software under the terms of such Secondary License(s), so that the recipient of the Larger Work may, at their option, further distribute the Covered Software under the terms of either this License or such Secondary License(s). 3.4. Notices You may not remove or alter the substance of any license notices (including copyright notices, patent notices, disclaimers of warranty, or limitations of liability) contained within the Source Code Form of the Covered Software, except that You may alter any license notices to the extent required to remedy known factual inaccuracies. 3.5. Application of Additional Terms You may choose to offer, and to charge a fee for, warranty, support, indemnity or liability obligations to one or more recipients of Covered Software. However, You may do so only on Your own behalf, and not on behalf of any Contributor. You must make it absolutely clear that any such warranty, support, indemnity, or liability obligation is offered by You alone, and You hereby agree to indemnify every Contributor for any liability incurred by such Contributor as a result of warranty, support, indemnity or liability terms You offer. You may include additional disclaimers of warranty and limitations of liability specific to any jurisdiction. 4. Inability to Comply Due to Statute or Regulation --------------------------------------------------- If it is impossible for You to comply with any of the terms of this License with respect to some or all of the Covered Software due to statute, judicial order, or regulation then You must: (a) comply with the terms of this License to the maximum extent possible; and (b) describe the limitations and the code they affect. Such description must be placed in a text file included with all distributions of the Covered Software under this License. Except to the extent prohibited by statute or regulation, such description must be sufficiently detailed for a recipient of ordinary skill to be able to understand it. 5. Termination -------------- 5.1. The rights granted under this License will terminate automatically if You fail to comply with any of its terms. However, if You become compliant, then the rights granted under this License from a particular Contributor are reinstated (a) provisionally, unless and until such Contributor explicitly and finally terminates Your grants, and (b) on an ongoing basis, if such Contributor fails to notify You of the non-compliance by some reasonable means prior to 60 days after You have come back into compliance. Moreover, Your grants from a particular Contributor are reinstated on an ongoing basis if such Contributor notifies You of the non-compliance by some reasonable means, this is the first time You have received notice of non-compliance with this License from such Contributor, and You become compliant prior to 30 days after Your receipt of the notice. 5.2. If You initiate litigation against any entity by asserting a patent infringement claim (excluding declaratory judgment actions, counter-claims, and cross-claims) alleging that a Contributor Version directly or indirectly infringes any patent, then the rights granted to You by any and all Contributors for the Covered Software under Section 2.1 of this License shall terminate. 5.3. In the event of termination under Sections 5.1 or 5.2 above, all end user license agreements (excluding distributors and resellers) which have been validly granted by You or Your distributors under this License prior to termination shall survive termination. ************************************************************************ * * * 6. Disclaimer of Warranty * * ------------------------- * * * * Covered Software is provided under this License on an "as is" * * basis, without warranty of any kind, either expressed, implied, or * * statutory, including, without limitation, warranties that the * * Covered Software is free of defects, merchantable, fit for a * * particular purpose or non-infringing. The entire risk as to the * * quality and performance of the Covered Software is with You. * * Should any Covered Software prove defective in any respect, You * * (not any Contributor) assume the cost of any necessary servicing, * * repair, or correction. This disclaimer of warranty constitutes an * * essential part of this License. No use of any Covered Software is * * authorized under this License except under this disclaimer. * * * ************************************************************************ ************************************************************************ * * * 7. Limitation of Liability * * -------------------------- * * * * Under no circumstances and under no legal theory, whether tort * * (including negligence), contract, or otherwise, shall any * * Contributor, or anyone who distributes Covered Software as * * permitted above, be liable to You for any direct, indirect, * * special, incidental, or consequential damages of any character * * including, without limitation, damages for lost profits, loss of * * goodwill, work stoppage, computer failure or malfunction, or any * * and all other commercial damages or losses, even if such party * * shall have been informed of the possibility of such damages. This * * limitation of liability shall not apply to liability for death or * * personal injury resulting from such party's negligence to the * * extent applicable law prohibits such limitation. Some * * jurisdictions do not allow the exclusion or limitation of * * incidental or consequential damages, so this exclusion and * * limitation may not apply to You. * * * ************************************************************************ 8. Litigation ------------- Any litigation relating to this License may be brought only in the courts of a jurisdiction where the defendant maintains its principal place of business and such litigation shall be governed by laws of that jurisdiction, without reference to its conflict-of-law provisions. Nothing in this Section shall prevent a party's ability to bring cross-claims or counter-claims. 9. Miscellaneous ---------------- This License represents the complete agreement concerning the subject matter hereof. If any provision of this License is held to be unenforceable, such provision shall be reformed only to the extent necessary to make it enforceable. Any law or regulation which provides that the language of a contract shall be construed against the drafter shall not be used to construe this License against a Contributor. 10. Versions of the License --------------------------- 10.1. New Versions Mozilla Foundation is the license steward. Except as provided in Section 10.3, no one other than the license steward has the right to modify or publish new versions of this License. Each version will be given a distinguishing version number. 10.2. Effect of New Versions You may distribute the Covered Software under the terms of the version of the License under which You originally received the Covered Software, or under the terms of any subsequent version published by the license steward. 10.3. Modified Versions If you create software not governed by this License, and you want to create a new license for such software, you may create and use a modified version of this License if you rename the license and remove any references to the name of the license steward (except to note that such modified license differs from this License). 10.4. Distributing Source Code Form that is Incompatible With Secondary Licenses If You choose to distribute Source Code Form that is Incompatible With Secondary Licenses under the terms of this version of the License, the notice described in Exhibit B of this License must be attached. Exhibit A - Source Code Form License Notice ------------------------------------------- This Source Code Form is subject to the terms of the Mozilla Public License, v. 2.0. If a copy of the MPL was not distributed with this file, You can obtain one at http://mozilla.org/MPL/2.0/. If it is not possible or desirable to put the notice in a particular file, then You may include the notice in a location (such as a LICENSE file in a relevant directory) where a recipient would be likely to look for such a notice. You may add additional accurate notices of copyright ownership. Exhibit B - "Incompatible With Secondary Licenses" Notice --------------------------------------------------------- This Source Code Form is "Incompatible With Secondary Licenses", as defined by the Mozilla Public License, v. 2.0. colored-1.6.1/README.md010064400007650000024000000110761332070115100126420ustar0000000000000000# Colored [![Build Status](https://travis-ci.org/mackwic/colored.svg?branch=master)](https://travis-ci.org/mackwic/colored) [![Crates.io](https://img.shields.io/crates/v/colored.svg?maxAge=2592000)](https://crates.io/crates/colored) [![Crates.io](https://img.shields.io/crates/l/colored.svg?maxAge=2592000)](https://github.com/mackwic/colored/blob/master/LICENSE) Coloring terminal so simple, you already know how to do it! ```rust "this is blue".blue(); "this is red".red(); "this is red on blue".red().on_blue(); "this is also red on blue".on_blue().red(); "bright colors are welcome as well".on_bright_blue().bright_red(); "you can also make bold comments".bold(); println!("{} {} {}", "or use".cyan(), "any".italic().yellow(), "string type".cyan()); "or change advice. This is red".yellow().blue().red(); "or clear things up. This is default color and style".red().bold().clear(); "purple and magenta are the same".purple().magenta(); "and so are normal and clear".normal().clear(); "you can specify color by string".color("blue").on_color("red"); String::from("this also works!").green().bold(); format!("{:30}", "format works as expected. This will be padded".blue()); format!("{:.3}", "and this will be green but truncated to 3 chars".green()); ``` ## How to use Add this in your `Cargo.toml`: ```toml [dependencies] colored = "1.6" ``` and add this to your `lib.rs` or `main.rs`: ```rust extern crate colored; use colored::*; // test the example with `cargo run --example most_simple` fn main() { // TADAA! println!("{} {} !", "it".green(), "works".blue().bold()); } ``` ## Features - Safe rust, easy to use, minimal dependencies, complete test suite - Respect the `CLICOLOR`/`CLICOLOR_FORCE` behavior (see [the specs](http://bixense.com/clicolors/)) #### Colors: - black - red - green - yellow - blue - magenta (or purple) - cyan - white Bright colors: prepend the color by `bright_`. So easy. Background colors: prepend the color by `on_`. Simple as that. Bright Background colors: prepend the color by `on_bright_`. Not hard at all. #### Styles: - bold - underline - italic - dimmed - reversed - blink - hidden - strikethrough You can clear color _and_ style anytime by using `normal()` or `clear()` #### Advanced Control: ##### Dynamic color from str As `Color` implements `FromStr`, `From<&str>`, and `From`, you can easily cast a string into a color like that: ```rust // the easy way "blue string yo".color("blue"); // this will default to white "white string".color("zorglub"); // the safer way via a Result let color_res = "zorglub".parse(); // <- this returns a Result "red string".color(color_res.unwrap_or(Color::Red)); ``` ##### Colorization control If you want to disable any coloring at compile time, you can simply do so by using the `no-color` feature. For example, you can do this in your `Cargo.toml` to disable color in tests: ```toml [features] # this effectively enable the feature `no-color` of colored when testing with # `cargo test --feature test` test = ["colored/no-color"] ``` You can use have even finer control by using the `colored::control::set_override` method. ## Todo - **Windows console support**: this works only with ANSI terminals. I plan to support the windows console also. - **More tests ?**: We always welcome more tests! Please contribute! ## Credits This library wouldn't have been the same without the marvelous ruby gem [colored](https://github.com/defunkt/colored). Thanks for the [ansi\_term crate](https://github.com/ogham/rust-ansi-term) for providing a reference implementation, which greatly helped making this crate output correct strings. ## License [Mozilla Public License 2.0](https://www.mozilla.org/en-US/MPL/2.0/). See the [LICENSE](https://github.com/mackwic/colored/blob/master/LICENSE) file at the root of the repository. In non legal terms it means that: - if you fix a bug, you MUST give me the code of the fix (it's only fair) - if you change/extend the API, you MUST give me the code you changed in the files under MPL2. - you CAN'T sue me for anything about this code - apart from that, you can do almost whatever you want. See the LICENSE file for details. ## Contributors - Thomas Wickham: [@mackwic](https://github.com/mackwic) - Corey "See More" Richardson: [@cmr](https://github.com/cmr) - Iban Eguia: [@Razican](https://github.com/Razican) - Alexis "Horgix" Chotard: [@horgix](https://github.com/horgix) - Keith Yeung: [@KiChjang](https://github.com/KiChjang) - Kyle Galloway: [@kylegalloway](https://github.com/kylegalloway) colored-1.6.1/src/color.rs010064400007650000024000000141351332070342600136440ustar0000000000000000use std::convert::From; use std::str::FromStr; /// The 8 standard colors. #[derive(Clone, Copy, Debug, PartialEq, Eq)] pub enum Color { Black, Red, Green, Yellow, Blue, Magenta, Cyan, White, BrightBlack, BrightRed, BrightGreen, BrightYellow, BrightBlue, BrightMagenta, BrightCyan, BrightWhite, } impl Color { pub fn to_fg_str(&self) -> &str { match *self { Color::Black => "30", Color::Red => "31", Color::Green => "32", Color::Yellow => "33", Color::Blue => "34", Color::Magenta => "35", Color::Cyan => "36", Color::White => "37", Color::BrightBlack => "90", Color::BrightRed => "91", Color::BrightGreen => "92", Color::BrightYellow => "93", Color::BrightBlue => "94", Color::BrightMagenta => "95", Color::BrightCyan => "96", Color::BrightWhite => "97", } } pub fn to_bg_str(&self) -> &str { match *self { Color::Black => "40", Color::Red => "41", Color::Green => "42", Color::Yellow => "43", Color::Blue => "44", Color::Magenta => "45", Color::Cyan => "46", Color::White => "47", Color::BrightBlack => "100", Color::BrightRed => "101", Color::BrightGreen => "102", Color::BrightYellow => "103", Color::BrightBlue => "104", Color::BrightMagenta => "105", Color::BrightCyan => "106", Color::BrightWhite => "107", } } } impl<'a> From<&'a str> for Color { fn from(src: &str) -> Self { src.parse().unwrap_or(Color::White) } } impl From for Color { fn from(src: String) -> Self { src.parse().unwrap_or(Color::White) } } impl FromStr for Color { type Err = (); fn from_str(src: &str) -> Result { let src = src.to_lowercase(); match src.as_ref() { "black" => Ok(Color::Black), "red" => Ok(Color::Red), "green" => Ok(Color::Green), "yellow" => Ok(Color::Yellow), "blue" => Ok(Color::Blue), "magenta" => Ok(Color::Magenta), "cyan" => Ok(Color::Cyan), "white" => Ok(Color::White), "bright black" => Ok(Color::BrightBlack), "bright red" => Ok(Color::BrightRed), "bright green" => Ok(Color::BrightGreen), "bright yellow" => Ok(Color::BrightYellow), "bright blue" => Ok(Color::BrightBlue), "bright magenta" => Ok(Color::BrightMagenta), "bright cyan" => Ok(Color::BrightCyan), "bright white" => Ok(Color::BrightWhite), _ => Err(()), } } } #[cfg(test)] mod tests { pub use super::*; mod from_str { pub use super::*; macro_rules! make_test { ( $( $name:ident: $src:expr => $dst:expr),* ) => { $( #[test] fn $name() { let color : Color = $src.into(); assert_eq!($dst, color) } )* } } make_test!( black: "black" => Color::Black, red: "red" => Color::Red, green: "green" => Color::Green, yellow: "yellow" => Color::Yellow, blue: "blue" => Color::Blue, magenta: "magenta" => Color::Magenta, cyan: "cyan" => Color::Cyan, white: "white" => Color::White, brightblack: "bright black" => Color::BrightBlack, brightred: "bright red" => Color::BrightRed, brightgreen: "bright green" => Color::BrightGreen, brightyellow: "bright yellow" => Color::BrightYellow, brightblue: "bright blue" => Color::BrightBlue, brightmagenta: "bright magenta" => Color::BrightMagenta, brightcyan: "bright cyan" => Color::BrightCyan, brightwhite: "bright white" => Color::BrightWhite, invalid: "invalid" => Color::White, capitalized: "BLUE" => Color::Blue, mixed_case: "bLuE" => Color::Blue ); } mod from_string { pub use super::*; macro_rules! make_test { ( $( $name:ident: $src:expr => $dst:expr),* ) => { $( #[test] fn $name() { let src = String::from($src); let color : Color = src.into(); assert_eq!($dst, color) } )* } } make_test!( black: "black" => Color::Black, red: "red" => Color::Red, green: "green" => Color::Green, yellow: "yellow" => Color::Yellow, blue: "blue" => Color::Blue, magenta: "magenta" => Color::Magenta, cyan: "cyan" => Color::Cyan, white: "white" => Color::White, brightblack: "bright black" => Color::BrightBlack, brightred: "bright red" => Color::BrightRed, brightgreen: "bright green" => Color::BrightGreen, brightyellow: "bright yellow" => Color::BrightYellow, brightblue: "bright blue" => Color::BrightBlue, brightmagenta: "bright magenta" => Color::BrightMagenta, brightcyan: "bright cyan" => Color::BrightCyan, brightwhite: "bright white" => Color::BrightWhite, invalid: "invalid" => Color::White, capitalized: "BLUE" => Color::Blue, mixed_case: "bLuE" => Color::Blue ); } mod fromstr { pub use super::*; #[test] fn parse() { let color: Result = "blue".parse(); assert_eq!(Ok(Color::Blue), color) } #[test] fn error() { let color: Result = "bloublou".parse(); assert_eq!(Err(()), color) } } } colored-1.6.1/src/control.rs010064400007650000024000000217561332070342600142150ustar0000000000000000//! A couple of functions to enable and disable coloring. use std::default::Default; use std::env; use std::sync::atomic::{AtomicBool, Ordering}; pub struct ShouldColorize { clicolor: Option, clicolor_force: Option, // XXX we can't use Option because we can't use &mut references to ShouldColorize has_manual_override: AtomicBool, manual_override: AtomicBool, } /// Use this to force colored to ignore the environment and always/never colorize /// See example/control.rs pub fn set_override(override_colorize: bool) { SHOULD_COLORIZE.set_override(override_colorize) } /// Remove the manual override and let the environment decide if it's ok to colorize /// See example/control.rs pub fn unset_override() { SHOULD_COLORIZE.unset_override() } lazy_static! { pub static ref SHOULD_COLORIZE: ShouldColorize = ShouldColorize::from_env(); } impl Default for ShouldColorize { fn default() -> ShouldColorize { ShouldColorize { clicolor: None, clicolor_force: None, has_manual_override: AtomicBool::new(false), manual_override: AtomicBool::new(false), } } } impl ShouldColorize { pub fn from_env() -> Self { use std::io; ShouldColorize { clicolor: ShouldColorize::normalize_env(env::var("CLICOLOR")), clicolor_force: ShouldColorize::normalize_env(env::var("CLICOLOR_FORCE")), ..ShouldColorize::default() } } pub fn should_colorize(&self) -> bool { if self.has_manual_override.load(Ordering::Relaxed) { return self.manual_override.load(Ordering::Relaxed); } if let Some(forced_value) = self.clicolor_force { return forced_value; } if let Some(value) = self.clicolor { return value; } true } pub fn set_override(&self, override_colorize: bool) { self.has_manual_override.store(true, Ordering::Relaxed); self.manual_override .store(override_colorize, Ordering::Relaxed); } pub fn unset_override(&self) { self.has_manual_override.store(false, Ordering::Relaxed); } /* private */ fn normalize_env(env_res: Result) -> Option { match env_res { Ok(string) => Some(string != "0"), Err(_) => None, } } } #[cfg(test)] mod specs { use super::*; use rspec; use rspec::context::*; use std::env; #[test] fn clicolor_behavior() { use std::io; let stdout = &mut io::stdout(); let mut formatter = rspec::formatter::Simple::new(stdout); let mut runner = describe("ShouldColorize", |ctx| { ctx.describe("::normalize_env", |ctx| { ctx.it("should return None if error", || { assert_eq!( None, ShouldColorize::normalize_env(Err(env::VarError::NotPresent)) ); assert_eq!( None, ShouldColorize::normalize_env(Err(env::VarError::NotUnicode("".into()))) ) }); ctx.it("should return Some(true) if != 0", || { Some(true) == ShouldColorize::normalize_env(Ok(String::from("1"))) }); ctx.it("should return Some(false) if == 0", || { Some(false) == ShouldColorize::normalize_env(Ok(String::from("0"))) }); }); ctx.describe("constructors", |ctx| { ctx.it("should have a default constructor", || { ShouldColorize::default(); }); ctx.it("should have an environment constructor", || { ShouldColorize::from_env(); }); }); ctx.describe("when only changing clicolors", |ctx| { ctx.it("clicolor == false means no colors", || { let colorize_control = ShouldColorize { clicolor: Some(false), ..ShouldColorize::default() }; false == colorize_control.should_colorize() }); ctx.it("clicolor == true means colors !", || { let colorize_control = ShouldColorize { clicolor: Some(true), ..ShouldColorize::default() }; true == colorize_control.should_colorize() }); ctx.it("unset clicolors implies true", || { true == ShouldColorize::default().should_colorize() }); }); ctx.describe("when using clicolor_force", |ctx| { ctx.it( "clicolor_force should force to true no matter clicolor", || { let colorize_control = ShouldColorize { clicolor: Some(false), clicolor_force: Some(true), ..ShouldColorize::default() }; true == colorize_control.should_colorize() }, ); ctx.it( "clicolor_force should force to false no matter clicolor", || { let colorize_control = ShouldColorize { clicolor: Some(true), clicolor_force: Some(false), ..ShouldColorize::default() }; false == colorize_control.should_colorize() }, ); }); ctx.describe("using a manual override", |ctx| { ctx.it("shoud colorize if manual_override is true, but clicolor is false and clicolor_force also false", || { let colorize_control = ShouldColorize { clicolor: Some(false), clicolor_force: None, has_manual_override: AtomicBool::new(true), manual_override: AtomicBool::new(true), .. ShouldColorize::default() }; true == colorize_control.should_colorize() }); ctx.it("should not colorize if manual_override is false, but clicolor is true or clicolor_force is true", || { let colorize_control = ShouldColorize { clicolor: Some(true), clicolor_force: Some(true), has_manual_override: AtomicBool::new(true), manual_override: AtomicBool::new(false), .. ShouldColorize::default() }; false == colorize_control.should_colorize() }) }); ctx.describe("::set_override", |ctx| { ctx.it("should exists", || { let colorize_control = ShouldColorize::default(); colorize_control.set_override(true); }); ctx.it("set the manual_override property", || { let colorize_control = ShouldColorize::default(); colorize_control.set_override(true); { assert_eq!( true, colorize_control.has_manual_override.load(Ordering::Relaxed) ); let val = colorize_control.manual_override.load(Ordering::Relaxed); assert_eq!(true, val); } colorize_control.set_override(false); { assert_eq!( true, colorize_control.has_manual_override.load(Ordering::Relaxed) ); let val = colorize_control.manual_override.load(Ordering::Relaxed); assert_eq!(false, val); } }); }); ctx.describe("::unset_override", |ctx| { ctx.it("should exists", || { let colorize_control = ShouldColorize::default(); colorize_control.unset_override(); }); ctx.it("unset the manual_override property", || { let colorize_control = ShouldColorize::default(); colorize_control.set_override(true); colorize_control.unset_override(); assert_eq!( false, colorize_control.has_manual_override.load(Ordering::Relaxed) ); }); }); }); runner.add_event_handler(&mut formatter); runner.run().unwrap(); } } colored-1.6.1/src/formatters.rs010064400007650000024000000004551332070115100147050ustar0000000000000000 use color::Color; use style::Style; pub trait ColoringFormatter { fn format(out: String, fg: Color, bg: Color, style: Style) -> String; } pub struct NoColor; impl ColoringFormatter for NoColor { fn format(out: String, _fg: Color, _bg: Color, _style: Style) -> String { out } } colored-1.6.1/src/lib.rs010064400007650000024000000523211332070342600132730ustar0000000000000000#![allow(unused_imports, dead_code, unused_parens)] //!Coloring terminal so simple, you already know how to do it ! //! //! use colored::Colorize; //! //! "this is blue".blue(); //! "this is red".red(); //! "this is red on blue".red().on_blue(); //! "this is also red on blue".on_blue().red(); //! "you can also make bold comments".bold(); //! println!("{} {} {}", "or use".cyan(), "any".italic().yellow(), "string type".cyan()); //! "or change advice. This is red".yellow().blue().red(); //! "or clear things up. This is default color and style".red().bold().clear(); //! "purple and magenta are the same".purple().magenta(); //! "bright colors are also allowed".bright_blue().on_bright_white(); //! "you can specify color by string".color("blue").on_color("red"); //! "and so are normal and clear".normal().clear(); //! String::from("this also works!").green().bold(); //! format!("{:30}", "format works as expected. This will be padded".blue()); //! format!("{:.3}", "and this will be green but truncated to 3 chars".green()); //! //! //! See [the `Colorize` trait](./trait.Colorize.html) for all the methods. //! #[macro_use] extern crate lazy_static; #[cfg(test)] extern crate rspec; mod color; pub mod control; mod style; pub use color::*; use std::convert::From; use std::fmt; use std::ops::Deref; use std::string::String; /// A string that may have color and/or style applied to it. #[derive(Clone, Debug, PartialEq, Eq)] pub struct ColoredString { input: String, fgcolor: Option, bgcolor: Option, style: style::Style, } /// The trait that enables something to be given color. /// /// You can use `colored` effectively simply by importing this trait /// and then using its methods on `String` and `&str`. pub trait Colorize { // Font Colors fn black(self) -> ColoredString; fn red(self) -> ColoredString; fn green(self) -> ColoredString; fn yellow(self) -> ColoredString; fn blue(self) -> ColoredString; fn magenta(self) -> ColoredString; fn purple(self) -> ColoredString; fn cyan(self) -> ColoredString; fn white(self) -> ColoredString; fn bright_black(self) -> ColoredString; fn bright_red(self) -> ColoredString; fn bright_green(self) -> ColoredString; fn bright_yellow(self) -> ColoredString; fn bright_blue(self) -> ColoredString; fn bright_magenta(self) -> ColoredString; fn bright_purple(self) -> ColoredString; fn bright_cyan(self) -> ColoredString; fn bright_white(self) -> ColoredString; fn color>(self, color: S) -> ColoredString; // Background Colors fn on_black(self) -> ColoredString; fn on_red(self) -> ColoredString; fn on_green(self) -> ColoredString; fn on_yellow(self) -> ColoredString; fn on_blue(self) -> ColoredString; fn on_magenta(self) -> ColoredString; fn on_purple(self) -> ColoredString; fn on_cyan(self) -> ColoredString; fn on_white(self) -> ColoredString; fn on_bright_black(self) -> ColoredString; fn on_bright_red(self) -> ColoredString; fn on_bright_green(self) -> ColoredString; fn on_bright_yellow(self) -> ColoredString; fn on_bright_blue(self) -> ColoredString; fn on_bright_magenta(self) -> ColoredString; fn on_bright_purple(self) -> ColoredString; fn on_bright_cyan(self) -> ColoredString; fn on_bright_white(self) -> ColoredString; fn on_color>(self, color: S) -> ColoredString; // Styles fn clear(self) -> ColoredString; fn normal(self) -> ColoredString; fn bold(self) -> ColoredString; fn dimmed(self) -> ColoredString; fn italic(self) -> ColoredString; fn underline(self) -> ColoredString; fn blink(self) -> ColoredString; /// Historical name of `Colorize::reversed`. May be removed in a future version. Please use /// `Colorize::reversed` instead fn reverse(self) -> ColoredString; /// This should be preferred to `Colorize::reverse`. fn reversed(self) -> ColoredString; fn hidden(self) -> ColoredString; fn strikethrough(self) -> ColoredString; } impl ColoredString { pub fn is_plain(&self) -> bool { (self.bgcolor.is_none() && self.fgcolor.is_none() && self.style == style::CLEAR) } #[cfg(not(feature = "no-color"))] fn has_colors(&self) -> bool { use control; control::SHOULD_COLORIZE.should_colorize() } #[cfg(feature = "no-color")] fn has_colors(&self) -> bool { false } fn compute_style(&self) -> String { if !self.has_colors() || self.is_plain() { return String::new(); } let mut res = String::from("\x1B["); let mut has_wrote = if self.style != style::CLEAR { res.push_str(&self.style.to_str()); true } else { false }; if let Some(ref bgcolor) = self.bgcolor { if has_wrote { res.push(';'); } res.push_str(bgcolor.to_bg_str()); has_wrote = true; } if let Some(ref fgcolor) = self.fgcolor { if has_wrote { res.push(';'); } res.push_str(fgcolor.to_fg_str()); } res.push('m'); res } fn escape_inner_reset_sequences(&self) -> String { if !self.has_colors() || self.is_plain() { return self.input.clone(); } // TODO: BoyScoutRule let reset = "\x1B[0m"; let style = self.compute_style(); let matches: Vec = self.input .match_indices(reset) .map(|(idx, _)| idx) .collect(); let mut idx_in_matches = 0; let mut input = self.input.clone(); input.reserve(matches.len() * style.len()); for offset in matches { // shift the offset to the end of the reset sequence and take in account // the number of matches we have escaped (which shift the index to insert) let mut offset = offset + reset.len() + idx_in_matches * style.len(); for cchar in style.chars() { input.insert(offset, cchar); offset += 1; } idx_in_matches += 1; } input } } impl Default for ColoredString { fn default() -> Self { ColoredString { input: String::default(), fgcolor: None, bgcolor: None, style: style::CLEAR, } } } impl Deref for ColoredString { type Target = str; fn deref(&self) -> &str { &self.input } } impl<'a> From<&'a str> for ColoredString { fn from(s: &'a str) -> Self { ColoredString { input: String::from(s), ..ColoredString::default() } } } macro_rules! def_color { ($side:ident: $name: ident => $color: path) => { fn $name(self) -> ColoredString { ColoredString { $side: Some($color), .. self } } }; } macro_rules! def_style { ($name: ident, $value: path) => { fn $name(self) -> ColoredString { ColoredString { style: style::Style::from_both(self.style, $value), .. self } } }; } impl Colorize for ColoredString { def_color!(fgcolor: black => Color::Black); fn red(self) -> ColoredString { self.color(Color::Red) } def_color!(fgcolor: green => Color::Green); def_color!(fgcolor: yellow => Color::Yellow); def_color!(fgcolor: blue => Color::Blue); def_color!(fgcolor: magenta => Color::Magenta); def_color!(fgcolor: purple => Color::Magenta); def_color!(fgcolor: cyan => Color::Cyan); def_color!(fgcolor: white => Color::White); def_color!(fgcolor: bright_black => Color::BrightBlack); fn bright_red(self) -> ColoredString { self.color(Color::BrightRed) } def_color!(fgcolor: bright_green => Color::BrightGreen); def_color!(fgcolor: bright_yellow => Color::BrightYellow); def_color!(fgcolor: bright_blue => Color::BrightBlue); def_color!(fgcolor: bright_magenta => Color::BrightMagenta); def_color!(fgcolor: bright_purple => Color::BrightMagenta); def_color!(fgcolor: bright_cyan => Color::BrightCyan); def_color!(fgcolor: bright_white => Color::BrightWhite); fn color>(self, color: S) -> ColoredString { ColoredString { fgcolor: Some(color.into()), ..self } } def_color!(bgcolor: on_black => Color::Black); fn on_red(self) -> ColoredString { ColoredString { bgcolor: Some(Color::Red), ..self } } def_color!(bgcolor: on_green => Color::Green); def_color!(bgcolor: on_yellow => Color::Yellow); def_color!(bgcolor: on_blue => Color::Blue); def_color!(bgcolor: on_magenta => Color::Magenta); def_color!(bgcolor: on_purple => Color::Magenta); def_color!(bgcolor: on_cyan => Color::Cyan); def_color!(bgcolor: on_white => Color::White); def_color!(bgcolor: on_bright_black => Color::BrightBlack); fn on_bright_red(self) -> ColoredString { ColoredString { bgcolor: Some(Color::BrightRed), ..self } } def_color!(bgcolor: on_bright_green => Color::BrightGreen); def_color!(bgcolor: on_bright_yellow => Color::BrightYellow); def_color!(bgcolor: on_bright_blue => Color::BrightBlue); def_color!(bgcolor: on_bright_magenta => Color::BrightMagenta); def_color!(bgcolor: on_bright_purple => Color::BrightMagenta); def_color!(bgcolor: on_bright_cyan => Color::BrightCyan); def_color!(bgcolor: on_bright_white => Color::BrightWhite); fn on_color>(self, color: S) -> ColoredString { ColoredString { bgcolor: Some(color.into()), ..self } } fn clear(self) -> ColoredString { ColoredString { input: self.input, ..ColoredString::default() } } fn normal(self) -> ColoredString { self.clear() } def_style!(bold, style::Styles::Bold); def_style!(dimmed, style::Styles::Dimmed); def_style!(italic, style::Styles::Italic); def_style!(underline, style::Styles::Underline); def_style!(blink, style::Styles::Blink); def_style!(reverse, style::Styles::Reversed); def_style!(reversed, style::Styles::Reversed); def_style!(hidden, style::Styles::Hidden); def_style!(strikethrough, style::Styles::Strikethrough); } macro_rules! def_str_color { ($side:ident: $name: ident => $color: path) => { fn $name(self) -> ColoredString { ColoredString { input: String::from(self), $side: Some($color), .. ColoredString::default() } } } } macro_rules! def_str_style { ($name:ident, $style:path) => { fn $name(self) -> ColoredString { ColoredString { input: String::from(self), style: style::Style::new($style), .. ColoredString::default() } } } } impl<'a> Colorize for &'a str { def_str_color!(fgcolor: black => Color::Black); fn red(self) -> ColoredString { ColoredString { input: String::from(self), fgcolor: Some(Color::Red), ..ColoredString::default() } } def_str_color!(fgcolor: green => Color::Green); def_str_color!(fgcolor: yellow => Color::Yellow); def_str_color!(fgcolor: blue => Color::Blue); def_str_color!(fgcolor: magenta => Color::Magenta); def_str_color!(fgcolor: purple => Color::Magenta); def_str_color!(fgcolor: cyan => Color::Cyan); def_str_color!(fgcolor: white => Color::White); def_str_color!(fgcolor: bright_black => Color::BrightBlack); fn bright_red(self) -> ColoredString { ColoredString { input: String::from(self), fgcolor: Some(Color::BrightRed), ..ColoredString::default() } } def_str_color!(fgcolor: bright_green => Color::BrightGreen); def_str_color!(fgcolor: bright_yellow => Color::BrightYellow); def_str_color!(fgcolor: bright_blue => Color::BrightBlue); def_str_color!(fgcolor: bright_magenta => Color::BrightMagenta); def_str_color!(fgcolor: bright_purple => Color::BrightMagenta); def_str_color!(fgcolor: bright_cyan => Color::BrightCyan); def_str_color!(fgcolor: bright_white => Color::BrightWhite); fn color>(self, color: S) -> ColoredString { ColoredString { fgcolor: Some(color.into()), input: String::from(self), ..ColoredString::default() } } def_str_color!(bgcolor: on_black => Color::Black); fn on_red(self) -> ColoredString { ColoredString { input: String::from(self), bgcolor: Some(Color::Red), ..ColoredString::default() } } def_str_color!(bgcolor: on_green => Color::Green); def_str_color!(bgcolor: on_yellow => Color::Yellow); def_str_color!(bgcolor: on_blue => Color::Blue); def_str_color!(bgcolor: on_magenta => Color::Magenta); def_str_color!(bgcolor: on_purple => Color::Magenta); def_str_color!(bgcolor: on_cyan => Color::Cyan); def_str_color!(bgcolor: on_white => Color::White); def_str_color!(bgcolor: on_bright_black => Color::BrightBlack); fn on_bright_red(self) -> ColoredString { ColoredString { input: String::from(self), bgcolor: Some(Color::BrightRed), ..ColoredString::default() } } def_str_color!(bgcolor: on_bright_green => Color::BrightGreen); def_str_color!(bgcolor: on_bright_yellow => Color::BrightYellow); def_str_color!(bgcolor: on_bright_blue => Color::BrightBlue); def_str_color!(bgcolor: on_bright_magenta => Color::BrightMagenta); def_str_color!(bgcolor: on_bright_purple => Color::BrightMagenta); def_str_color!(bgcolor: on_bright_cyan => Color::BrightCyan); def_str_color!(bgcolor: on_bright_white => Color::BrightWhite); fn on_color>(self, color: S) -> ColoredString { ColoredString { bgcolor: Some(color.into()), input: String::from(self), ..ColoredString::default() } } fn clear(self) -> ColoredString { ColoredString { input: String::from(self), style: style::CLEAR, ..ColoredString::default() } } fn normal(self) -> ColoredString { self.clear() } def_str_style!(bold, style::Styles::Bold); def_str_style!(dimmed, style::Styles::Dimmed); def_str_style!(italic, style::Styles::Italic); def_str_style!(underline, style::Styles::Underline); def_str_style!(blink, style::Styles::Blink); def_str_style!(reverse, style::Styles::Reversed); def_str_style!(reversed, style::Styles::Reversed); def_str_style!(hidden, style::Styles::Hidden); def_str_style!(strikethrough, style::Styles::Strikethrough); } impl fmt::Display for ColoredString { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { if !self.has_colors() || self.is_plain() { return (::fmt(&self.input, f)); } // XXX: see tests. Useful when nesting colored strings let escaped_input = self.escape_inner_reset_sequences(); try!(f.write_str(&self.compute_style())); try!(::fmt(&escaped_input, f)); try!(f.write_str("\x1B[0m")); Ok(()) } } #[cfg(test)] mod tests { use super::*; #[test] fn formatting() { // respect the formatting. Escape sequence add some padding so >= 40 assert!(format!("{:40}", "".blue()).len() >= 40); // both should be truncated to 1 char before coloring assert_eq!( format!("{:1.1}", "toto".blue()).len(), format!("{:1.1}", "1".blue()).len() ) } #[test] fn it_works() { let toto = "toto"; println!("{}", toto.red()); println!("{}", String::from(toto).red()); println!("{}", toto.blue()); println!("blue style ****"); println!("{}", toto.bold()); println!("{}", "yeah ! Red bold !".red().bold()); println!("{}", "yeah ! Yellow bold !".bold().yellow()); println!("{}", toto.bold().blue()); println!("{}", toto.blue().bold()); println!("{}", toto.blue().bold().underline()); println!("{}", toto.blue().italic()); println!("******"); println!("test clearing"); println!("{}", "red cleared".red().clear()); println!("{}", "bold cyan cleared".bold().cyan().clear()); println!("******"); println!("Bg tests"); println!("{}", toto.green().on_blue()); println!("{}", toto.on_magenta().yellow()); println!("{}", toto.purple().on_yellow()); println!("{}", toto.magenta().on_white()); println!("{}", toto.cyan().on_green()); println!("{}", toto.black().on_white()); println!("******"); println!("{}", toto.green()); println!("{}", toto.yellow()); println!("{}", toto.purple()); println!("{}", toto.magenta()); println!("{}", toto.cyan()); println!("{}", toto.white()); println!("{}", toto.white().red().blue().green()); // uncomment to see term output // assert!(false) } #[test] fn compute_style_empty_string() { assert_eq!("", "".clear().compute_style()); } #[test] fn compute_style_simple_fg_blue() { let blue = "\x1B[34m"; assert_eq!(blue, "".blue().compute_style()); } #[test] fn compute_style_simple_bg_blue() { let on_blue = "\x1B[44m"; assert_eq!(on_blue, "".on_blue().compute_style()); } #[test] fn compute_style_blue_on_blue() { let blue_on_blue = "\x1B[44;34m"; assert_eq!(blue_on_blue, "".blue().on_blue().compute_style()); } #[test] fn compute_style_simple_fg_bright_blue() { let blue = "\x1B[94m"; assert_eq!(blue, "".bright_blue().compute_style()); } #[test] fn compute_style_simple_bg_bright_blue() { let on_blue = "\x1B[104m"; assert_eq!(on_blue, "".on_bright_blue().compute_style()); } #[test] fn compute_style_bright_blue_on_bright_blue() { let blue_on_blue = "\x1B[104;94m"; assert_eq!( blue_on_blue, "".bright_blue().on_bright_blue().compute_style() ); } #[test] fn compute_style_simple_bold() { let bold = "\x1B[1m"; assert_eq!(bold, "".bold().compute_style()); } #[test] fn compute_style_blue_bold() { let blue_bold = "\x1B[1;34m"; assert_eq!(blue_bold, "".blue().bold().compute_style()); } #[test] fn compute_style_blue_bold_on_blue() { let blue_bold_on_blue = "\x1B[1;44;34m"; assert_eq!( blue_bold_on_blue, "".blue().bold().on_blue().compute_style() ); } #[test] fn escape_reset_sequence_spec_should_do_nothing_on_empty_strings() { let style = ColoredString::default(); let expected = String::new(); let output = style.escape_inner_reset_sequences(); assert_eq!(expected, output); } #[test] fn escape_reset_sequence_spec_should_do_nothing_on_string_with_no_reset() { let style = ColoredString { input: String::from("hello world !"), ..ColoredString::default() }; let expected = String::from("hello world !"); let output = style.escape_inner_reset_sequences(); assert_eq!(expected, output); } #[test] fn escape_reset_sequence_spec_should_replace_inner_reset_sequence_with_current_style() { let input = format!("start {} end", String::from("hello world !").red()); let style = input.blue(); let output = style.escape_inner_reset_sequences(); let blue = "\x1B[34m"; let red = "\x1B[31m"; let reset = "\x1B[0m"; let expected = format!("start {}hello world !{}{} end", red, reset, blue); assert_eq!(expected, output); } #[test] fn escape_reset_sequence_spec_should_replace_multiple_inner_reset_sequences_with_current_style() { let italic_str = String::from("yo").italic(); let input = format!( "start 1:{} 2:{} 3:{} end", italic_str, italic_str, italic_str ); let style = input.blue(); let output = style.escape_inner_reset_sequences(); let blue = "\x1B[34m"; let italic = "\x1B[3m"; let reset = "\x1B[0m"; let expected = format!( "start 1:{}yo{}{} 2:{}yo{}{} 3:{}yo{}{} end", italic, reset, blue, italic, reset, blue, italic, reset, blue ); println!("first: {}\nsecond: {}", expected, output); assert_eq!(expected, output); } #[test] fn color_fn() { assert_eq!("blue".blue(), "blue".color("blue")) } #[test] fn on_color_fn() { assert_eq!("blue".on_blue(), "blue".on_color("blue")) } #[test] fn bright_color_fn() { assert_eq!("blue".bright_blue(), "blue".color("bright blue")) } #[test] fn on_bright_color_fn() { assert_eq!("blue".on_bright_blue(), "blue".on_color("bright blue")) } } colored-1.6.1/src/style.rs010064400007650000024000000166171332070342600136750ustar0000000000000000const CLEARV: u8 = 0b0000_0000; const BOLD: u8 = 0b0000_0001; const UNDERLINE: u8 = 0b0000_0010; const REVERSED: u8 = 0b0000_0100; const ITALIC: u8 = 0b0000_1000; const BLINK: u8 = 0b0001_0000; const HIDDEN: u8 = 0b0010_0000; const DIMMED: u8 = 0b0100_0000; const STRIKETHROUGH: u8 = 0b1000_0000; static STYLES: [(u8, Styles); 8] = [ (BOLD, Styles::Bold), (DIMMED, Styles::Dimmed), (UNDERLINE, Styles::Underline), (REVERSED, Styles::Reversed), (ITALIC, Styles::Italic), (BLINK, Styles::Blink), (HIDDEN, Styles::Hidden), (STRIKETHROUGH, Styles::Strikethrough), ]; pub static CLEAR: Style = Style(CLEARV); #[derive(Clone, Copy, PartialEq, Eq, Debug)] pub struct Style(u8); #[derive(Clone, Copy, PartialEq, Eq, Debug)] pub enum Styles { Clear, Bold, Dimmed, Underline, Reversed, Italic, Blink, Hidden, Strikethrough, } impl Styles { fn to_str<'a>(self) -> &'a str { match self { Styles::Clear => "", // unreachable, but we don't want to panic Styles::Bold => "1", Styles::Dimmed => "2", Styles::Italic => "3", Styles::Underline => "4", Styles::Blink => "5", Styles::Reversed => "7", Styles::Hidden => "8", Styles::Strikethrough => "9", } } fn to_u8(self) -> u8 { match self { Styles::Clear => CLEARV, Styles::Bold => BOLD, Styles::Dimmed => DIMMED, Styles::Italic => ITALIC, Styles::Underline => UNDERLINE, Styles::Blink => BLINK, Styles::Reversed => REVERSED, Styles::Hidden => HIDDEN, Styles::Strikethrough => STRIKETHROUGH, } } fn from_u8(u: u8) -> Option> { if u == CLEARV { return None; } let res: Vec = STYLES .into_iter() .filter(|&&(ref mask, _)| (0 != (u & mask))) .map(|&(_, value)| value) .collect(); if res.is_empty() { None } else { Some(res) } } } impl Style { pub fn to_str(&self) -> String { let styles = match Styles::from_u8(self.0) { None => return String::new(), Some(s) => s, }; let mut res = String::new(); let mut first = true; for style in styles.iter().map(|s| s.to_str()) { if first { res.push_str(style); first = false; continue; } else { res.push(';'); res.push_str(style) } } res } pub fn new(from: Styles) -> Style { Style(from.to_u8()) } pub fn from_both(one: Style, two: Styles) -> Style { Style(one.0 | two.to_u8()) } } #[cfg(test)] mod tests { mod u8_to_styles_invalid_is_none { use super::super::CLEARV; use super::super::{Style, Styles}; #[test] fn empty_is_none() { assert_eq!(None, Styles::from_u8(CLEARV)) } } mod u8_to_styles_isomorphism { use super::super::Styles; use super::super::{ BLINK, BOLD, DIMMED, HIDDEN, ITALIC, REVERSED, STRIKETHROUGH, UNDERLINE, }; macro_rules! value_isomorph { ($name:ident, $value:expr) => { #[test] fn $name() { let u = Styles::from_u8($value); assert!( u.is_some(), "{}: Styles::from_u8 -> None", stringify!($value) ); let u = u.unwrap(); assert!( u.len() == 1, "{}: Styles::from_u8 found {} styles (expected 1)", stringify!($value), u.len() ); assert!( u[0].to_u8() == $value, "{}: to_u8() doesn't match its const value", stringify!($value) ); } }; } value_isomorph!(bold, BOLD); value_isomorph!(underline, UNDERLINE); value_isomorph!(reversed, REVERSED); value_isomorph!(italic, ITALIC); value_isomorph!(blink, BLINK); value_isomorph!(hidden, HIDDEN); value_isomorph!(dimmed, DIMMED); value_isomorph!(strikethrough, STRIKETHROUGH); } mod styles_combine_complex { use super::super::Styles::*; use super::super::{Style, Styles}; use super::super::{ BLINK, BOLD, DIMMED, HIDDEN, ITALIC, REVERSED, STRIKETHROUGH, UNDERLINE, }; fn style_from_multiples(styles: &[Styles]) -> Style { let mut res = Style::new(styles[0]); for s in &styles[1..] { res = Style::from_both(res, *s) } res } macro_rules! test_aggreg { ($styles:expr, $expect:expr) => {{ let v = style_from_multiples($styles); let r = Styles::from_u8(v.0).expect("should find styles"); assert_eq!(&$expect as &[Styles], &r[..]) }}; } #[test] fn aggreg1() { let styles: &[Styles] = &[Bold, Bold, Bold]; test_aggreg!(styles, [Bold]) } #[test] fn aggreg2() { let styles: &[Styles] = &[Italic, Italic, Bold, Bold]; test_aggreg!(styles, [Bold, Italic]) } #[test] fn aggreg3() { let styles: &[Styles] = &[Bold, Italic, Bold]; test_aggreg!(styles, [Bold, Italic]) } macro_rules! test_combine { ($styles:expr) => {{ let v = style_from_multiples($styles); let r = Styles::from_u8(v.0).expect("should find styles"); assert_eq!($styles, &r[..]) }}; } #[test] fn two1() { let s: &[Styles] = &[Bold, Underline]; test_combine!(s) } #[test] fn two2() { let s: &[Styles] = &[Underline, Italic]; test_combine!(s) } #[test] fn two3() { let s: &[Styles] = &[Bold, Italic]; test_combine!(s) } #[test] fn three1() { let s: &[Styles] = &[Bold, Underline, Italic]; test_combine!(s) } #[test] fn three2() { let s: &[Styles] = &[Dimmed, Underline, Italic]; test_combine!(s) } #[test] fn four() { let s: &[Styles] = &[Dimmed, Underline, Italic, Hidden]; test_combine!(s) } #[test] fn five() { let s: &[Styles] = &[Dimmed, Underline, Italic, Blink, Hidden]; test_combine!(s) } #[test] fn six() { let s: &[Styles] = &[Bold, Dimmed, Underline, Italic, Blink, Hidden]; test_combine!(s) } #[test] fn all() { let s: &[Styles] = &[ Bold, Dimmed, Underline, Reversed, Italic, Blink, Hidden, Strikethrough, ]; test_combine!(s) } } } colored-1.6.1/tests/ansi_term_compat.rs010064400007650000024000000067301332070342600164270ustar0000000000000000#![allow(unused_imports)] extern crate ansi_term; extern crate colored; use ansi_term::*; use colored::*; macro_rules! test_simple_color { ($string:expr, $colored_name:ident, $ansi_term_name:ident) => { #[test] fn $colored_name() { let s = format!("{} {}", $string, stringify!($colored_name)); assert_eq!( s.$colored_name().to_string(), Colour::$ansi_term_name.paint(s).to_string() ) } }; } mod compat_colors { use super::ansi_term::*; use super::colored::*; test_simple_color!("test string", black, Black); test_simple_color!("test string", red, Red); test_simple_color!("test string", green, Green); test_simple_color!("test string", yellow, Yellow); test_simple_color!("test string", blue, Blue); test_simple_color!("test string", magenta, Purple); test_simple_color!("test string", cyan, Cyan); test_simple_color!("test string", white, White); } macro_rules! test_simple_style { ($string:expr, $style:ident) => { #[test] fn $style() { let s = format!("{} {}", $string, stringify!($style)); assert_eq!( s.$style().to_string(), ansi_term::Style::new().$style().paint(s).to_string() ) } }; } mod compat_styles { use super::ansi_term; use super::ansi_term::*; use super::colored; use super::colored::*; test_simple_style!("test string", bold); test_simple_style!("test string", dimmed); test_simple_style!("test string", italic); test_simple_style!("test string", underline); test_simple_style!("test string", blink); test_simple_style!("test string", reverse); test_simple_style!("test string", hidden); } macro_rules! test_simple_bgcolor { ($string:expr, $colored_name:ident, $ansi_term_name:ident) => { #[test] fn $colored_name() { let s = format!("{} {}", $string, stringify!($colored_name)); assert_eq!( s.$colored_name().to_string(), ansi_term::Style::default() .on(ansi_term::Colour::$ansi_term_name) .paint(s) .to_string() ) } }; } mod compat_bgcolors { use super::ansi_term; use super::ansi_term::*; use super::colored; use super::colored::*; test_simple_bgcolor!("test string", on_black, Black); test_simple_bgcolor!("test string", on_red, Red); test_simple_bgcolor!("test string", on_green, Green); test_simple_bgcolor!("test string", on_yellow, Yellow); test_simple_bgcolor!("test string", on_blue, Blue); test_simple_bgcolor!("test string", on_magenta, Purple); test_simple_bgcolor!("test string", on_cyan, Cyan); test_simple_bgcolor!("test string", on_white, White); } mod compat_complex { use super::ansi_term; use super::ansi_term::*; use super::colored; use super::colored::*; #[test] fn complex1() { let s = "test string"; let ansi = Colour::Red.on(Colour::Black).bold().italic().paint(s); assert_eq!( ansi.to_string(), s.red().bold().italic().on_black().to_string() ); } #[test] fn complex2() { let s = "test string"; let ansi = Colour::Green.on(Colour::Yellow).underline().paint(s); assert_eq!( ansi.to_string(), s.green().on_yellow().underline().to_string() ); } }