colored-2.2.0/.cargo_vcs_info.json0000644000000001360000000000100124640ustar { "git": { "sha1": "ef1484c713e1340d842cc7b76f79dc976afe891f" }, "path_in_vcs": "" }colored-2.2.0/.devcontainer/devcontainer.json000064400000000000000000000004321046102023000173660ustar 00000000000000{ "name": "Rust", "image": "mcr.microsoft.com/vscode/devcontainers/rust:1", "customizations": { "vscode": { "extensions": ["rust-lang.rust-analyzer"] } }, "postCreateCommand": "cargo install cargo-insta", "remoteUser": "vscode" } colored-2.2.0/.git-blame-ignore-revs000064400000000000000000000001011046102023000153440ustar 00000000000000# pedantic clippy fixes 58a06a44c7640a83a65df6c5afae5ed8f0014fd0 colored-2.2.0/.gitattributes000064400000000000000000000000361046102023000141460ustar 00000000000000*.snap linguist-language=Text colored-2.2.0/.github/dependabot.yml000064400000000000000000000003551046102023000154470ustar 00000000000000# https://docs.github.com/en/code-security/dependabot/dependabot-version-updates/configuration-options-for-the-dependabot.yml-file version: 2 updates: - package-ecosystem: cargo directory: "/" schedule: interval: monthly colored-2.2.0/.github/workflows/publish.yml000064400000000000000000000033711046102023000170460ustar 00000000000000name: Publish on: push: branches: [master] permissions: contents: write jobs: publish: name: Publish runs-on: ubuntu-latest steps: - name: Checkout repository uses: actions/checkout@v3 - name: Get local crate version id: local-version run: cargo metadata --no-deps --format-version=1 | jq -r '.packages[0].version' | echo "VERSION=$(cat)" >> "${GITHUB_OUTPUT}" - name: Get crates.io crate version id: remote-version run: curl 'https://index.crates.io/co/lo/colored' | jq -r '.vers' | tail -n 1 | echo "VERSION=$(cat)" >> "${GITHUB_OUTPUT}" - name: Check if crates.io version is older than local version id: needs-update run: | if ! printf '%s\n' "${{ steps.local-version.outputs.VERSION }}" "${{ steps.remote-version.outputs.VERSION }}" | sort -V | tail -n 1 | grep -Fw "${{ steps.remote-version.outputs.VERSION }}"; then echo "UPDATE=true" >> "${GITHUB_OUTPUT}" else echo "UPDATE=false" >> "${GITHUB_OUTPUT}" fi - name: Install parse-changelog if: steps.needs-update.outputs.UPDATE == 'true' uses: taiki-e/install-action@parse-changelog - name: Create GitHub release if: steps.needs-update.outputs.UPDATE == 'true' run: gh release create "v${{ steps.local-version.outputs.VERSION }}" -t "v${{ steps.local-version.outputs.VERSION }}" -n "$(parse-changelog CHANGELOG.md "${{ steps.local-version.outputs.VERSION }}")" env: GITHUB_TOKEN: "${{ secrets.GITHUB_TOKEN }}" - name: Publish to crates.io if: steps.needs-update.outputs.UPDATE == 'true' run: cargo publish env: CARGO_REGISTRY_TOKEN: "${{ secrets.CARGO_REGISTRY_TOKEN }}" colored-2.2.0/.github/workflows/test.yml000064400000000000000000000033011046102023000163500ustar 00000000000000name: Run tests on: pull_request env: CLICOLOR_FORCE: 1 COLORTERM: "truecolor" jobs: cargo-fmt: name: cargo-fmt@stable runs-on: ubuntu-latest steps: - name: Checkout repository uses: actions/checkout@v3 - name: Install Rust stable uses: dtolnay/rust-toolchain@master with: toolchain: stable components: rustfmt - name: Run formatting checks run: cargo fmt --check cargo-clippy: name: "${{ matrix.os }}:cargo-clippy@stable" runs-on: "${{ matrix.os }}-latest" strategy: matrix: os: ["ubuntu", "windows", "macos"] steps: - name: Checkout repository uses: actions/checkout@v3 - name: Install Rust stable uses: dtolnay/rust-toolchain@master with: toolchain: stable components: clippy - name: Run clippy checks run: cargo clippy --all-features -- -D warnings cargo-test: name: "${{ matrix.os }}:cargo-test@${{ matrix.version }}" runs-on: "${{ matrix.os }}-latest" strategy: matrix: os: ["ubuntu", "windows", "macos"] version: ["stable", "beta", "1.70"] steps: - name: Checkout repository uses: actions/checkout@v3 - name: Install Rust ${{ matrix.version }} uses: dtolnay/rust-toolchain@master with: toolchain: ${{ matrix.version }} - name: Run tests run: cargo test check-semver: name: Check semver compatibility if: github.base_ref == 'master' runs-on: ubuntu-latest steps: - name: Checkout repository uses: actions/checkout@v3 - name: Check semver uses: obi1kenobi/cargo-semver-checks-action@v2 colored-2.2.0/.gitignore000064400000000000000000000000271046102023000132430ustar 00000000000000target Cargo.lock *.bk colored-2.2.0/CHANGELOG.md000064400000000000000000000114411046102023000130660ustar 00000000000000# Unreleased - Updated top-level docs to include a note about `ColoredString`\'s role in the `Colorize` pipeline as well as link to it to suggest learning more about how to manipulate existing `ColoredString`\'s. - Changes to `ColoredString`: - Expose fields. - **[DEPRECATION]:** Deprecated methods `fgcolor`, `bgcolor`, and `style` due to their obsolescence in the face of the exposing of their represented fields. - Add methods for clearing specific elements of `fgcolor`, `bgcolor`, and `style`. - Change Default implementation to be via derive as Style now implements Default (see changes to Style below). - Add implementation of `DerefMut`. - Updated docs to reflect the above changes as well as generally greatly expand them. - Changes to `Style`: - Implemented `Default` for `Style` (returns `CLEAR`). This exposes a method by which users can create plain `Style`\'s from scratch. - Implemented `From` for `Style`. This lets users easily create `Style`\'s from specific styles. - Exposed previously private method `add`. - Created method `remove` which essentially does the opposite. - Added builder-style methods in the vein of `Colorize` to add stylings (e.g. `bold`, `underline`, `italic`, `strikethrough`). - Implemented bitwise operators `BitAnd`, `BitOr`, `BitXor`, and `Not` as well as their representative assignment operators. You can also use a `Styles` as an operand for these. - Implemented `FromIterator` for Style. - Changes to `Styles`: - Implemented bitwise operators `BitAnd`, `BitOr`, `BitXor`, and `Not` which all combine `Styles`\'s and output `Style`\'s. These can also take a `Style` as an operand. - Added additional testing for all of the above changes. - Added methods `with_style` and `with_color_and_style` to `Colorize`. # 2.1.0 * Impl From for ColoredString by @mahor1221 in https://github.com/colored-rs/colored/pull/126 * Allow conversion from ColoredString to Error by @spenserblack in https://github.com/colored-rs/colored/pull/86 * Suggestion for minor documentation clarification by @jonasbn in https://github.com/colored-rs/colored/pull/98 * Remove unnecessary is_terminal dependency by @Oakchris1955 in https://github.com/colored-rs/colored/pull/149 - Document crate MSRV of `1.70`. # 2.0.4 - Switch from `winapi` to `windows-sys`. # 2.0.3 - Document crate MSRV of `1.63`. # 2.0.2 - Fix typo in `src/control.rs`. - Replace `atty` dependency with `is-terminal`. # 2.0.1 (July 3, 2023) - Add edition for future compatibility. - Implement custom colors that can be stored in a variable. # 2.0.0 (July 14, 2020) - Add support for true colours. - Alter `Color` interface to return `Cow<'static, str>` # 1.9.3 (February 24, 2020) - Fix compilation regression for 1.34.0. Thanks @jlevon for reporting. # 1.9.2 (January 11, 2020) - Exposed `ColoredString` data through methods for purposes of interrogating the applied colours. - Increased documentation. # 1.9.1 (December 31, 2019) - Remove deprecated `try!` macro in codebase - Reduce allocations in `ColoredString` impl (PR#65) - Added `"purple"` as match in `impl FromStr for Color` (PR#71) # 1.9.0 (November 11, 2019) - **[POSSIBLE_BREAKING CHANGE]:** Replace `winconsole` with `winapi`: - Changes `set_virtual_terminal` function signature. - Update dependencies - Add Dockerfile - Respect tty discovery for CLICOLOR # 1.8.0 (April 30, 2019) - FEAT: support Windows 10 colors # 1.7.0 (January, 2019) - TECH: update lazy\_static - FEAT: introduce respect for the `NO_COLOR` environment variable # 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-2.2.0/Cargo.lock0000644000000475660000000000100104610ustar # This file is automatically @generated by Cargo. # It is not intended for manual editing. version = 3 [[package]] name = "ansi_term" version = "0.12.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d52a9bb7ec0cf484c551830a7ce27bd20d67eac647e1befb56b0be4ee39a55d2" dependencies = [ "winapi", ] [[package]] name = "base-x" version = "0.2.11" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "4cbbc9d0964165b47557570cce6c952866c2678457aca742aafc9fb771d30270" [[package]] name = "bumpalo" version = "3.16.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "79296716171880943b8470b5f8d03aa55eb2e645a4874bdbb28adb49162e012c" [[package]] name = "cfg-if" version = "1.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" [[package]] name = "colored" version = "2.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "cbf2150cce219b664a8a70df7a1f933836724b503f8a413af9365b4dcc4d90b8" dependencies = [ "lazy_static", "windows-sys 0.48.0", ] [[package]] name = "colored" version = "2.2.0" dependencies = [ "ansi_term", "insta", "lazy_static", "rspec", "windows-sys 0.59.0", ] [[package]] name = "console" version = "0.15.8" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0e1f83fc076bd6dd27517eacdf25fef6c4dfe5f1d7448bafaaf3a26f13b5e4eb" dependencies = [ "encode_unicode", "lazy_static", "libc", "windows-sys 0.52.0", ] [[package]] name = "const_fn" version = "0.4.10" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "373e9fafaa20882876db20562275ff58d50e0caa2590077fe7ce7bef90211d0d" [[package]] name = "crossbeam-deque" version = "0.8.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "613f8cc01fe9cf1a3eb3d7f488fd2fa8388403e97039e2f73692932e291a770d" dependencies = [ "crossbeam-epoch", "crossbeam-utils", ] [[package]] name = "crossbeam-epoch" version = "0.9.18" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "5b82ac4a3c2ca9c3460964f020e1402edd5753411d7737aa39c3714ad1b5420e" dependencies = [ "crossbeam-utils", ] [[package]] name = "crossbeam-utils" version = "0.8.20" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "22ec99545bb0ed0ea7bb9b8e1e9122ea386ff8a48c0922e43f36d45ab09e0e80" [[package]] name = "darling" version = "0.10.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0d706e75d87e35569db781a9b5e2416cff1236a47ed380831f959382ccd5f858" dependencies = [ "darling_core", "darling_macro", ] [[package]] name = "darling_core" version = "0.10.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f0c960ae2da4de88a91b2d920c2a7233b400bc33cb28453a2987822d8392519b" dependencies = [ "fnv", "ident_case", "proc-macro2", "quote", "strsim", "syn 1.0.109", ] [[package]] name = "darling_macro" version = "0.10.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d9b5a2f4ac4969822c62224815d069952656cadc7084fdca9751e6d959189b72" dependencies = [ "darling_core", "quote", "syn 1.0.109", ] [[package]] name = "derive-new" version = "0.5.9" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3418329ca0ad70234b9735dc4ceed10af4df60eff9c8e7b06cb5e520d92c3535" dependencies = [ "proc-macro2", "quote", "syn 1.0.109", ] [[package]] name = "derive_builder" version = "0.9.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a2658621297f2cf68762a6f7dc0bb7e1ff2cfd6583daef8ee0fed6f7ec468ec0" dependencies = [ "darling", "derive_builder_core", "proc-macro2", "quote", "syn 1.0.109", ] [[package]] name = "derive_builder_core" version = "0.9.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "2791ea3e372c8495c0bc2033991d76b512cd799d07491fbd6890124db9458bef" dependencies = [ "darling", "proc-macro2", "quote", "syn 1.0.109", ] [[package]] name = "discard" version = "1.0.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "212d0f5754cb6769937f4501cc0e67f4f4483c8d2c3e1e922ee9edbe4ab4c7c0" [[package]] name = "either" version = "1.13.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "60b1af1c220855b6ceac025d3f6ecdd2b7c4894bfe9cd9bda4fbb4bc7c0d4cf0" [[package]] name = "encode_unicode" version = "0.3.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a357d28ed41a50f9c765dbfe56cbc04a64e53e5fc58ba79fbc34c10ef3df831f" [[package]] name = "fnv" version = "1.0.7" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3f9eec918d3f24069decb9af1554cad7c880e2da24a9afd88aca000531ab82c1" [[package]] name = "ident_case" version = "1.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b9e0384b61958566e926dc50660321d12159025e767c18e043daf26b70104c39" [[package]] name = "insta" version = "1.41.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7e9ffc4d4892617c50a928c52b2961cb5174b6fc6ebf252b2fac9d21955c48b8" dependencies = [ "console", "lazy_static", "linked-hash-map", "similar", ] [[package]] name = "itoa" version = "1.0.14" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d75a2a4b1b190afb6f5425f10f6a8f959d2ea0b9c2b1d79553551850539e4674" [[package]] name = "lazy_static" version = "1.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "bbd2bcb4c963f2ddae06a2efc7e9f3591312473c50c6685e1f298068316e66fe" [[package]] name = "libc" version = "0.2.168" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "5aaeb2981e0606ca11d79718f8bb01164f1d6ed75080182d3abf017e6d244b6d" [[package]] name = "linked-hash-map" version = "0.5.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0717cef1bc8b636c6e1c1bbdefc09e6322da8a9321966e8928ef80d20f7f770f" [[package]] name = "log" version = "0.4.22" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a7a70ba024b9dc04c27ea2f0c0548feb474ec5c54bba33a7f72f873a39d07b24" [[package]] name = "memchr" version = "2.7.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "78ca9ab1a0babb1e7d5695e3530886289c18cf2f87ec19a575a0abdce112e3a3" [[package]] name = "once_cell" version = "1.20.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1261fe7e33c73b354eab43b1273a57c8f967d0391e80353e51f764ac02cf6775" [[package]] name = "proc-macro-hack" version = "0.5.20+deprecated" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "dc375e1527247fe1a97d8b7156678dfe7c1af2fc075c9a4db3690ecd2a148068" [[package]] name = "proc-macro2" version = "1.0.92" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "37d3544b3f2748c54e147655edb5025752e2303145b5aefb3c3ea2c78b973bb0" dependencies = [ "unicode-ident", ] [[package]] name = "quote" version = "1.0.37" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b5b9d34b8991d19d98081b46eacdd8eb58c6f2b201139f7c5f643cc155a633af" dependencies = [ "proc-macro2", ] [[package]] name = "rayon" version = "1.10.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b418a60154510ca1a002a752ca9714984e21e4241e804d32555251faf8b78ffa" dependencies = [ "either", "rayon-core", ] [[package]] name = "rayon-core" version = "1.12.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1465873a3dfdaa8ae7cb14b4383657caab0b3e8a0aa9ae8e04b044854c8dfce2" dependencies = [ "crossbeam-deque", "crossbeam-utils", ] [[package]] name = "rspec" version = "1.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "89389e7c690310e855df3d9b507985ca0d323e2e766b2fedf369b02671e70e0a" dependencies = [ "colored 2.1.0", "derive-new", "derive_builder", "rayon", "time", ] [[package]] name = "rustc_version" version = "0.2.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "138e3e0acb6c9fb258b19b67cb8abd63c00679d2851805ea151465464fe9030a" dependencies = [ "semver", ] [[package]] name = "ryu" version = "1.0.18" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f3cb5ba0dc43242ce17de99c180e96db90b235b8a9fdc9543c96d2209116bd9f" [[package]] name = "semver" version = "0.9.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1d7eb9ef2c18661902cc47e535f9bc51b78acd254da71d375c2f6720d9a40403" dependencies = [ "semver-parser", ] [[package]] name = "semver-parser" version = "0.7.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "388a1df253eca08550bef6c72392cfe7c30914bf41df5269b68cbd6ff8f570a3" [[package]] name = "serde" version = "1.0.216" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0b9781016e935a97e8beecf0c933758c97a5520d32930e460142b4cd80c6338e" dependencies = [ "serde_derive", ] [[package]] name = "serde_derive" version = "1.0.216" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "46f859dbbf73865c6627ed570e78961cd3ac92407a2d117204c49232485da55e" dependencies = [ "proc-macro2", "quote", "syn 2.0.90", ] [[package]] name = "serde_json" version = "1.0.133" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c7fceb2473b9166b2294ef05efcb65a3db80803f0b03ef86a5fc88a2b85ee377" dependencies = [ "itoa", "memchr", "ryu", "serde", ] [[package]] name = "sha1" version = "0.6.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c1da05c97445caa12d05e848c4a4fcbbea29e748ac28f7e80e9b010392063770" dependencies = [ "sha1_smol", ] [[package]] name = "sha1_smol" version = "1.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "bbfa15b3dddfee50a0fff136974b3e1bde555604ba463834a7eb7deb6417705d" [[package]] name = "similar" version = "2.6.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1de1d4f81173b03af4c0cbed3c898f6bff5b870e4a7f5d6f4057d62a7a4b686e" [[package]] name = "standback" version = "0.2.17" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e113fb6f3de07a243d434a56ec6f186dfd51cb08448239fe7bcae73f87ff28ff" dependencies = [ "version_check", ] [[package]] name = "stdweb" version = "0.4.20" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d022496b16281348b52d0e30ae99e01a73d737b2f45d38fed4edf79f9325a1d5" dependencies = [ "discard", "rustc_version", "stdweb-derive", "stdweb-internal-macros", "stdweb-internal-runtime", "wasm-bindgen", ] [[package]] name = "stdweb-derive" version = "0.5.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c87a60a40fccc84bef0652345bbbbbe20a605bf5d0ce81719fc476f5c03b50ef" dependencies = [ "proc-macro2", "quote", "serde", "serde_derive", "syn 1.0.109", ] [[package]] name = "stdweb-internal-macros" version = "0.2.9" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "58fa5ff6ad0d98d1ffa8cb115892b6e69d67799f6763e162a1c9db421dc22e11" dependencies = [ "base-x", "proc-macro2", "quote", "serde", "serde_derive", "serde_json", "sha1", "syn 1.0.109", ] [[package]] name = "stdweb-internal-runtime" version = "0.1.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "213701ba3370744dcd1a12960caa4843b3d68b4d1c0a5d575e0d65b2ee9d16c0" [[package]] name = "strsim" version = "0.9.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6446ced80d6c486436db5c078dde11a9f73d42b57fb273121e160b84f63d894c" [[package]] name = "syn" version = "1.0.109" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "72b64191b275b66ffe2469e8af2c1cfe3bafa67b529ead792a6d0160888b4237" dependencies = [ "proc-macro2", "quote", "unicode-ident", ] [[package]] name = "syn" version = "2.0.90" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "919d3b74a5dd0ccd15aeb8f93e7006bd9e14c295087c9896a110f490752bcf31" dependencies = [ "proc-macro2", "quote", "unicode-ident", ] [[package]] name = "time" version = "0.2.27" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "4752a97f8eebd6854ff91f1c1824cd6160626ac4bd44287f7f4ea2035a02a242" dependencies = [ "const_fn", "libc", "standback", "stdweb", "time-macros", "version_check", "winapi", ] [[package]] name = "time-macros" version = "0.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "957e9c6e26f12cb6d0dd7fc776bb67a706312e7299aed74c8dd5b17ebb27e2f1" dependencies = [ "proc-macro-hack", "time-macros-impl", ] [[package]] name = "time-macros-impl" version = "0.1.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "fd3c141a1b43194f3f56a1411225df8646c55781d5f26db825b3d98507eb482f" dependencies = [ "proc-macro-hack", "proc-macro2", "quote", "standback", "syn 1.0.109", ] [[package]] name = "unicode-ident" version = "1.0.14" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "adb9e6ca4f869e1180728b7950e35922a7fc6397f7b641499e8f3ef06e50dc83" [[package]] name = "version_check" version = "0.9.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0b928f33d975fc6ad9f86c8f283853ad26bdd5b10b7f1542aa2fa15e2289105a" [[package]] name = "wasm-bindgen" version = "0.2.99" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a474f6281d1d70c17ae7aa6a613c87fce69a127e2624002df63dcb39d6cf6396" dependencies = [ "cfg-if", "once_cell", "wasm-bindgen-macro", ] [[package]] name = "wasm-bindgen-backend" version = "0.2.99" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "5f89bb38646b4f81674e8f5c3fb81b562be1fd936d84320f3264486418519c79" dependencies = [ "bumpalo", "log", "proc-macro2", "quote", "syn 2.0.90", "wasm-bindgen-shared", ] [[package]] name = "wasm-bindgen-macro" version = "0.2.99" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "2cc6181fd9a7492eef6fef1f33961e3695e4579b9872a6f7c83aee556666d4fe" dependencies = [ "quote", "wasm-bindgen-macro-support", ] [[package]] name = "wasm-bindgen-macro-support" version = "0.2.99" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "30d7a95b763d3c45903ed6c81f156801839e5ee968bb07e534c44df0fcd330c2" dependencies = [ "proc-macro2", "quote", "syn 2.0.90", "wasm-bindgen-backend", "wasm-bindgen-shared", ] [[package]] name = "wasm-bindgen-shared" version = "0.2.99" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "943aab3fdaaa029a6e0271b35ea10b72b943135afe9bffca82384098ad0e06a6" [[package]] name = "winapi" version = "0.3.9" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "5c839a674fcd7a98952e593242ea400abe93992746761e38641405d28b00f419" 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 = "windows-sys" version = "0.48.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "677d2418bec65e3338edb076e806bc1ec15693c5d0104683f2efe857f61056a9" dependencies = [ "windows-targets 0.48.5", ] [[package]] name = "windows-sys" version = "0.52.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "282be5f36a8ce781fad8c8ae18fa3f9beff57ec1b52cb3de0789201425d9a33d" dependencies = [ "windows-targets 0.52.6", ] [[package]] name = "windows-sys" version = "0.59.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1e38bc4d79ed67fd075bcc251a1c39b32a1776bbe92e5bef1f0bf1f8c531853b" dependencies = [ "windows-targets 0.52.6", ] [[package]] name = "windows-targets" version = "0.48.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9a2fa6e2155d7247be68c096456083145c183cbbbc2764150dda45a87197940c" dependencies = [ "windows_aarch64_gnullvm 0.48.5", "windows_aarch64_msvc 0.48.5", "windows_i686_gnu 0.48.5", "windows_i686_msvc 0.48.5", "windows_x86_64_gnu 0.48.5", "windows_x86_64_gnullvm 0.48.5", "windows_x86_64_msvc 0.48.5", ] [[package]] name = "windows-targets" version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9b724f72796e036ab90c1021d4780d4d3d648aca59e491e6b98e725b84e99973" dependencies = [ "windows_aarch64_gnullvm 0.52.6", "windows_aarch64_msvc 0.52.6", "windows_i686_gnu 0.52.6", "windows_i686_gnullvm", "windows_i686_msvc 0.52.6", "windows_x86_64_gnu 0.52.6", "windows_x86_64_gnullvm 0.52.6", "windows_x86_64_msvc 0.52.6", ] [[package]] name = "windows_aarch64_gnullvm" version = "0.48.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "2b38e32f0abccf9987a4e3079dfb67dcd799fb61361e53e2882c3cbaf0d905d8" [[package]] name = "windows_aarch64_gnullvm" version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "32a4622180e7a0ec044bb555404c800bc9fd9ec262ec147edd5989ccd0c02cd3" [[package]] name = "windows_aarch64_msvc" version = "0.48.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "dc35310971f3b2dbbf3f0690a219f40e2d9afcf64f9ab7cc1be722937c26b4bc" [[package]] name = "windows_aarch64_msvc" version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "09ec2a7bb152e2252b53fa7803150007879548bc709c039df7627cabbd05d469" [[package]] name = "windows_i686_gnu" version = "0.48.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a75915e7def60c94dcef72200b9a8e58e5091744960da64ec734a6c6e9b3743e" [[package]] name = "windows_i686_gnu" version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8e9b5ad5ab802e97eb8e295ac6720e509ee4c243f69d781394014ebfe8bbfa0b" [[package]] name = "windows_i686_gnullvm" version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0eee52d38c090b3caa76c563b86c3a4bd71ef1a819287c19d586d7334ae8ed66" [[package]] name = "windows_i686_msvc" version = "0.48.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8f55c233f70c4b27f66c523580f78f1004e8b5a8b659e05a4eb49d4166cca406" [[package]] name = "windows_i686_msvc" version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "240948bc05c5e7c6dabba28bf89d89ffce3e303022809e73deaefe4f6ec56c66" [[package]] name = "windows_x86_64_gnu" version = "0.48.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "53d40abd2583d23e4718fddf1ebec84dbff8381c07cae67ff7768bbf19c6718e" [[package]] name = "windows_x86_64_gnu" version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "147a5c80aabfbf0c7d901cb5895d1de30ef2907eb21fbbab29ca94c5b08b1a78" [[package]] name = "windows_x86_64_gnullvm" version = "0.48.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0b7b52767868a23d5bab768e390dc5f5c55825b6d30b86c844ff2dc7414044cc" [[package]] name = "windows_x86_64_gnullvm" version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "24d5b23dc417412679681396f2b49f3de8c1473deb516bd34410872eff51ed0d" [[package]] name = "windows_x86_64_msvc" version = "0.48.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ed94fce61571a4006852b7389a063ab983c02eb1bb37b47f8272ce92d06d9538" [[package]] name = "windows_x86_64_msvc" version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "589f6da84c646204747d1270a2a5661ea66ed1cced2631d546fdfb155959f9ec" colored-2.2.0/Cargo.toml0000644000000035020000000000100104620ustar # 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 are reading this file be aware that the original Cargo.toml # will likely look very different (and much more reasonable). # See Cargo.toml.orig for the original contents. [package] edition = "2021" rust-version = "1.70" name = "colored" version = "2.2.0" authors = ["Thomas Wickham "] build = false autolib = false autobins = false autoexamples = false autotests = false autobenches = false 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" [lib] name = "colored" path = "src/lib.rs" [[example]] name = "as_error" path = "examples/as_error.rs" [[example]] name = "control" path = "examples/control.rs" [[example]] name = "custom_colors" path = "examples/custom_colors.rs" [[example]] name = "dynamic_colors" path = "examples/dynamic_colors.rs" [[example]] name = "most_simple" path = "examples/most_simple.rs" [[example]] name = "nested_colors" path = "examples/nested_colors.rs" [[test]] name = "ansi_term_compat" path = "tests/ansi_term_compat.rs" [dependencies.lazy_static] version = "1" [dev-dependencies.ansi_term] version = "0.12" [dev-dependencies.insta] version = "1" [dev-dependencies.rspec] version = "1" [features] no-color = [] [target."cfg(windows)".dependencies.windows-sys] version = ">=0.48,<=0.59" features = [ "Win32_Foundation", "Win32_System_Console", ] colored-2.2.0/Cargo.toml.orig000064400000000000000000000013241046102023000141430ustar 00000000000000[package] name = "colored" description = "The most simple way to add colors in your terminal" version = "2.2.0" edition = "2021" 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"] rust-version = "1.70" [features] # with this feature, no color will ever be written no-color = [] [dependencies] lazy_static = "1" [target.'cfg(windows)'.dependencies.windows-sys] version = ">=0.48,<=0.59" features = [ "Win32_Foundation", "Win32_System_Console", ] [dev-dependencies] ansi_term = "0.12" insta = "1" rspec = "1" colored-2.2.0/Dockerfile000064400000000000000000000001531046102023000132450ustar 00000000000000FROM rust:latest ENV SRC_DIR /src RUN mkdir $SRC_DIR WORKDIR $SRC_DIR VOLUME $SRC_DIR CMD ["/bin/bash"] colored-2.2.0/LICENSE000064400000000000000000000405261046102023000122700ustar 00000000000000Mozilla 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-2.2.0/README.md000064400000000000000000000132761046102023000125440ustar 00000000000000# 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(); "you can use truecolor values too!".truecolor(0, 255, 136); "background truecolor also works :)".on_truecolor(135, 28, 167); "truecolor from tuple".custom_color((0, 255, 136)); "background truecolor from tuple".on_custom_color((0, 255, 136)); "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 = "2" ``` and add this to your `lib.rs` or `main.rs`: ```rust extern crate colored; // not needed in Rust 2018+ use colored::Colorize; // 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/)) - Respect the `NO_COLOR` behavior (see [the specs](https://no-color.org/)) - Do note that `CLICOLOR_FORCE` overrules `NO_COLOR`, which overrules `CLICOLOR` - Works on Linux, MacOS, and Windows (Powershell) #### 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. #### Truecolors Colored has support for truecolors where you can specify any arbitrary rgb value. This feature will only work correctly in terminals which support true colors (i.e. most modern terminals). You can check if your terminal supports true color by checking the value of the environment variable `$COLORTERM` on your terminal. A value of `truecolor` or `24bit` indicates that it will work. #### 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 : Result = "zorglub".parse(); "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 dumb_terminal` dumb_terminal = ["colored/no-color"] ``` You can use have even finer control by using the `colored::control::set_override` method. ## Todo - **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. ## Minimum Supported Rust Version (MSRV) The current MSRV is `1.70`, which is checked and enforced automatically via CI. This version may change in the future in minor version bumps, so if you require a specific Rust version you should use a restricted version requirement such as `~X.Y`. ## 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) - Hunter Wittenborn [@hwittenborn](https://github.com/hwittenborn) - 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) - Luke Hsiao: [@lukehsiao](https://github.com/lukehsiao) - kurtlawrence: [@kurtlawrence](https://github.com/kurtlawrence) colored-2.2.0/examples/as_error.rs000064400000000000000000000002121046102023000152470ustar 00000000000000extern crate colored; use colored::Colorize; use std::error::Error; fn main() -> Result<(), Box> { Err("ERROR".red())? } colored-2.2.0/examples/control.rs000064400000000000000000000031661046102023000151260ustar 00000000000000#![allow(unused_must_use)] extern crate colored; use colored::*; #[cfg(not(windows))] fn main() { both(); } #[cfg(windows)] fn main() { both(); // additional control setting using windows set_virtual_terminal colored::control::set_virtual_terminal(true); println!("{}", "stdout: Virtual Terminal is in use".bright_green()); colored::control::set_virtual_terminal(false); println!( "{}", "stderr: Virtual Terminal is NOT in use, escape chars should be visible".bright_red() ); colored::control::set_virtual_terminal(true); println!( "{}", "stdout: Virtual Terminal is in use AGAIN and should be green!".bright_green() ); colored::control::set_virtual_terminal(true); // again with stderr eprintln!("{}", "stderr: Virtual Terminal is in use".bright_green()); colored::control::set_virtual_terminal(false); eprintln!( "{}", "stderr: Virtual Terminal is NOT in use, escape chars should be visible".bright_red() ); colored::control::set_virtual_terminal(true); eprintln!( "{}", "stderr: Virtual Terminal is in use AGAIN and should be green!".bright_green() ); } fn both() { // 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-2.2.0/examples/custom_colors.rs000064400000000000000000000004301046102023000163300ustar 00000000000000use colored::*; fn main() { let my_color = CustomColor::new(0, 120, 120); println!("{}", "Greetings from Ukraine".custom_color(my_color)); println!("{}", "Slava Ukraini!".on_custom_color(my_color)); println!("{}", "Hello World!".on_custom_color((0, 120, 120))); } colored-2.2.0/examples/dynamic_colors.rs000064400000000000000000000005371046102023000164520ustar 00000000000000extern 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-2.2.0/examples/most_simple.rs000064400000000000000000000011051046102023000157700ustar 00000000000000extern 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-2.2.0/examples/nested_colors.rs000064400000000000000000000006601046102023000163050ustar 00000000000000extern 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-2.2.0/src/color.rs000064400000000000000000000306221046102023000135320ustar 00000000000000use std::{borrow::Cow, env, str::FromStr}; /// The 8 standard colors. #[derive(Clone, Copy, Debug, PartialEq, Eq)] #[allow(missing_docs)] pub enum Color { Black, Red, Green, Yellow, Blue, Magenta, Cyan, White, BrightBlack, BrightRed, BrightGreen, BrightYellow, BrightBlue, BrightMagenta, BrightCyan, BrightWhite, TrueColor { r: u8, g: u8, b: u8 }, } fn truecolor_support() -> bool { let truecolor = env::var("COLORTERM"); if let Ok(truecolor) = truecolor { truecolor == "truecolor" || truecolor == "24bit" } else { false } } #[allow(missing_docs)] impl Color { pub fn to_fg_str(&self) -> Cow<'static, str> { match *self { Color::Black => "30".into(), Color::Red => "31".into(), Color::Green => "32".into(), Color::Yellow => "33".into(), Color::Blue => "34".into(), Color::Magenta => "35".into(), Color::Cyan => "36".into(), Color::White => "37".into(), Color::BrightBlack => "90".into(), Color::BrightRed => "91".into(), Color::BrightGreen => "92".into(), Color::BrightYellow => "93".into(), Color::BrightBlue => "94".into(), Color::BrightMagenta => "95".into(), Color::BrightCyan => "96".into(), Color::BrightWhite => "97".into(), Color::TrueColor { .. } if !truecolor_support() => { self.closest_color_euclidean().to_fg_str() } Color::TrueColor { r, g, b } => format!("38;2;{};{};{}", r, g, b).into(), } } pub fn to_bg_str(&self) -> Cow<'static, str> { match *self { Color::Black => "40".into(), Color::Red => "41".into(), Color::Green => "42".into(), Color::Yellow => "43".into(), Color::Blue => "44".into(), Color::Magenta => "45".into(), Color::Cyan => "46".into(), Color::White => "47".into(), Color::BrightBlack => "100".into(), Color::BrightRed => "101".into(), Color::BrightGreen => "102".into(), Color::BrightYellow => "103".into(), Color::BrightBlue => "104".into(), Color::BrightMagenta => "105".into(), Color::BrightCyan => "106".into(), Color::BrightWhite => "107".into(), Color::TrueColor { .. } if !truecolor_support() => { self.closest_color_euclidean().to_bg_str() } Color::TrueColor { r, g, b } => format!("48;2;{};{};{}", r, g, b).into(), } } /// Gets the closest plain color to the TrueColor fn closest_color_euclidean(self) -> Self { use std::cmp; use Color::*; match self { TrueColor { r: r1, g: g1, b: b1, } => { let colors = vec![ Black, Red, Green, Yellow, Blue, Magenta, Cyan, White, BrightBlack, BrightRed, BrightGreen, BrightYellow, BrightBlue, BrightMagenta, BrightCyan, BrightWhite, ] .into_iter() .map(|c| (c, c.into_truecolor())); let distances = colors.map(|(c_original, c)| { if let TrueColor { r, g, b } = c { let rd = cmp::max(r, r1) - cmp::min(r, r1); let gd = cmp::max(g, g1) - cmp::min(g, g1); let bd = cmp::max(b, b1) - cmp::min(b, b1); let rd: u32 = rd.into(); let gd: u32 = gd.into(); let bd: u32 = bd.into(); let distance = rd.pow(2) + gd.pow(2) + bd.pow(2); (c_original, distance) } else { unimplemented!("{:?} not a TrueColor", c) } }); distances.min_by(|(_, d1), (_, d2)| d1.cmp(d2)).unwrap().0 } c => c, } } fn into_truecolor(self) -> Self { use Color::*; match self { Black => TrueColor { r: 0, g: 0, b: 0 }, Red => TrueColor { r: 205, g: 0, b: 0 }, Green => TrueColor { r: 0, g: 205, b: 0 }, Yellow => TrueColor { r: 205, g: 205, b: 0, }, Blue => TrueColor { r: 0, g: 0, b: 238 }, Magenta => TrueColor { r: 205, g: 0, b: 205, }, Cyan => TrueColor { r: 0, g: 205, b: 205, }, White => TrueColor { r: 229, g: 229, b: 229, }, BrightBlack => TrueColor { r: 127, g: 127, b: 127, }, BrightRed => TrueColor { r: 255, g: 0, b: 0 }, BrightGreen => TrueColor { r: 0, g: 255, b: 0 }, BrightYellow => TrueColor { r: 255, g: 255, b: 0, }, BrightBlue => TrueColor { r: 92, g: 92, b: 255, }, BrightMagenta => TrueColor { r: 255, g: 0, b: 255, }, BrightCyan => TrueColor { r: 0, g: 255, b: 255, }, BrightWhite => TrueColor { r: 255, g: 255, b: 255, }, TrueColor { r, g, b } => TrueColor { r, g, b }, } } } impl From<&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), "purple" => 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, purple: "purple" => 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); } } mod closest_euclidean { use super::*; macro_rules! make_euclidean_distance_test { ( $test:ident : ( $r:literal, $g: literal, $b:literal ), $expected:expr ) => { #[test] fn $test() { let true_color = Color::TrueColor { r: $r, g: $g, b: $b, }; let actual = true_color.closest_color_euclidean(); assert_eq!(actual, $expected); } }; } make_euclidean_distance_test! { exact_black: (0, 0, 0), Color::Black } make_euclidean_distance_test! { exact_red: (205, 0, 0), Color::Red } make_euclidean_distance_test! { exact_green: (0, 205, 0), Color::Green } make_euclidean_distance_test! { exact_yellow: (205, 205, 0), Color::Yellow } make_euclidean_distance_test! { exact_blue: (0, 0, 238), Color::Blue } make_euclidean_distance_test! { exact_magenta: (205, 0, 205), Color::Magenta } make_euclidean_distance_test! { exact_cyan: (0, 205, 205), Color::Cyan } make_euclidean_distance_test! { exact_white: (229, 229, 229), Color::White } make_euclidean_distance_test! { almost_black: (10, 15, 10), Color::Black } make_euclidean_distance_test! { almost_red: (215, 10, 10), Color::Red } make_euclidean_distance_test! { almost_green: (10, 195, 10), Color::Green } make_euclidean_distance_test! { almost_yellow: (195, 215, 10), Color::Yellow } make_euclidean_distance_test! { almost_blue: (0, 0, 200), Color::Blue } make_euclidean_distance_test! { almost_magenta: (215, 0, 195), Color::Magenta } make_euclidean_distance_test! { almost_cyan: (10, 215, 215), Color::Cyan } make_euclidean_distance_test! { almost_white: (209, 209, 229), Color::White } } } colored-2.2.0/src/control.rs000064400000000000000000000342631046102023000141010ustar 00000000000000//! A couple of functions to enable and disable coloring. use std::default::Default; use std::env; use std::io::{self, IsTerminal}; use std::sync::atomic::{AtomicBool, Ordering}; /// Sets a flag to the console to use a virtual terminal environment. /// /// This is primarily used for Windows 10 environments which will not correctly colorize /// the outputs based on ANSI escape codes. /// /// The returned `Result` is _always_ `Ok(())`, the return type was kept to ensure backwards /// compatibility. /// /// # Notes /// > Only available to `Windows` build targets. /// /// # Example /// ```rust /// use colored::*; /// control::set_virtual_terminal(false).unwrap(); /// println!("{}", "bright cyan".bright_cyan()); // will print 'bright cyan' on windows 10 /// /// control::set_virtual_terminal(true).unwrap(); /// println!("{}", "bright cyan".bright_cyan()); // will print correctly /// ``` #[allow(clippy::result_unit_err)] #[cfg(windows)] pub fn set_virtual_terminal(use_virtual: bool) -> Result<(), ()> { use windows_sys::Win32::System::Console::{ GetConsoleMode, GetStdHandle, SetConsoleMode, ENABLE_VIRTUAL_TERMINAL_PROCESSING, STD_OUTPUT_HANDLE, }; unsafe { let handle = GetStdHandle(STD_OUTPUT_HANDLE); let mut original_mode = 0; GetConsoleMode(handle, &mut original_mode); let enabled = original_mode & ENABLE_VIRTUAL_TERMINAL_PROCESSING == ENABLE_VIRTUAL_TERMINAL_PROCESSING; match (use_virtual, enabled) { // not enabled, should be enabled (true, false) => { SetConsoleMode(handle, ENABLE_VIRTUAL_TERMINAL_PROCESSING | original_mode) } // already enabled, should be disabled (false, true) => { SetConsoleMode(handle, ENABLE_VIRTUAL_TERMINAL_PROCESSING ^ original_mode) } _ => 0, }; } Ok(()) } /// A flag for whether coloring should occur. pub struct ShouldColorize { clicolor: bool, 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! { /// The persistent [`ShouldColorize`]. pub static ref SHOULD_COLORIZE: ShouldColorize = ShouldColorize::from_env(); } impl Default for ShouldColorize { fn default() -> ShouldColorize { ShouldColorize { clicolor: true, clicolor_force: None, has_manual_override: AtomicBool::new(false), manual_override: AtomicBool::new(false), } } } impl ShouldColorize { /// Reads environment variables and checks if output is a tty to determine /// whether colorization should be used or not. /// `CLICOLOR_FORCE` takes highest priority, followed by `NO_COLOR`, /// followed by `CLICOLOR` combined with tty check. pub fn from_env() -> Self { ShouldColorize { clicolor: ShouldColorize::normalize_env(env::var("CLICOLOR")).unwrap_or(true) && io::stdout().is_terminal(), clicolor_force: ShouldColorize::resolve_clicolor_force( env::var("NO_COLOR"), env::var("CLICOLOR_FORCE"), ), ..ShouldColorize::default() } } /// Returns if the current coloring is expected. 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; } self.clicolor } /// Use this to force colored to ignore the environment and always/never colorize pub fn set_override(&self, override_colorize: bool) { self.has_manual_override.store(true, Ordering::Relaxed); self.manual_override .store(override_colorize, Ordering::Relaxed); } /// Remove the manual override and let the environment decide if it's ok to colorize 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, } } fn resolve_clicolor_force( no_color: Result, clicolor_force: Result, ) -> Option { if ShouldColorize::normalize_env(clicolor_force) == Some(true) { Some(true) } else if ShouldColorize::normalize_env(no_color).is_some() { Some(false) } else { None } } } #[cfg(test)] mod specs { use super::*; use rspec; use std::env; #[test] fn clicolor_behavior() { rspec::run(&rspec::describe("ShouldColorize", (), |ctx| { ctx.specify("::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.specify("::resolve_clicolor_force", |ctx| { ctx.it( "should return None if NO_COLOR is not set and CLICOLOR_FORCE is not set or set to 0", |_| { assert_eq!( None, ShouldColorize::resolve_clicolor_force( Err(env::VarError::NotPresent), Err(env::VarError::NotPresent) ) ); assert_eq!( None, ShouldColorize::resolve_clicolor_force( Err(env::VarError::NotPresent), Ok(String::from("0")), ) ); }, ); ctx.it( "should return Some(false) if NO_COLOR is set and CLICOLOR_FORCE is not enabled", |_| { assert_eq!( Some(false), ShouldColorize::resolve_clicolor_force( Ok(String::from("0")), Err(env::VarError::NotPresent) ) ); assert_eq!( Some(false), ShouldColorize::resolve_clicolor_force( Ok(String::from("1")), Err(env::VarError::NotPresent) ) ); assert_eq!( Some(false), ShouldColorize::resolve_clicolor_force( Ok(String::from("1")), Ok(String::from("0")), ) ); }, ); ctx.it( "should prioritize CLICOLOR_FORCE over NO_COLOR if CLICOLOR_FORCE is set to non-zero value", |_| { assert_eq!( Some(true), ShouldColorize::resolve_clicolor_force( Ok(String::from("1")), Ok(String::from("1")), ) ); assert_eq!( Some(false), ShouldColorize::resolve_clicolor_force( Ok(String::from("1")), Ok(String::from("0")), ) ); assert_eq!( Some(true), ShouldColorize::resolve_clicolor_force( Err(env::VarError::NotPresent), Ok(String::from("1")), ) ); }, ); }); ctx.specify("constructors", |ctx| { ctx.it("should have a default constructor", |_| { ShouldColorize::default(); }); ctx.it("should have an environment constructor", |_| { ShouldColorize::from_env(); }); }); ctx.specify("when only changing clicolors", |ctx| { ctx.it("clicolor == false means no colors", |_| { let colorize_control = ShouldColorize { clicolor: false, ..ShouldColorize::default() }; !colorize_control.should_colorize() }); ctx.it("clicolor == true means colors !", |_| { let colorize_control = ShouldColorize { clicolor: true, ..ShouldColorize::default() }; colorize_control.should_colorize() }); ctx.it("unset clicolors implies true", |_| { ShouldColorize::default().should_colorize() }); }); ctx.specify("when using clicolor_force", |ctx| { ctx.it( "clicolor_force should force to true no matter clicolor", |_| { let colorize_control = ShouldColorize { clicolor: false, clicolor_force: Some(true), ..ShouldColorize::default() }; colorize_control.should_colorize() }, ); ctx.it( "clicolor_force should force to false no matter clicolor", |_| { let colorize_control = ShouldColorize { clicolor: true, clicolor_force: Some(false), ..ShouldColorize::default() }; !colorize_control.should_colorize() }, ); }); ctx.specify("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: false, clicolor_force: None, has_manual_override: AtomicBool::new(true), manual_override: AtomicBool::new(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: true, clicolor_force: Some(true), has_manual_override: AtomicBool::new(true), manual_override: AtomicBool::new(false), }; !colorize_control.should_colorize() }); }); ctx.specify("::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!(colorize_control.has_manual_override.load(Ordering::Relaxed)); let val = colorize_control.manual_override.load(Ordering::Relaxed); assert!(val); } colorize_control.set_override(false); { assert!(colorize_control.has_manual_override.load(Ordering::Relaxed)); let val = colorize_control.manual_override.load(Ordering::Relaxed); assert!(!val); } }); }); ctx.specify("::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!(!colorize_control.has_manual_override.load(Ordering::Relaxed)); }); }); })); } } colored-2.2.0/src/customcolors.rs000064400000000000000000000020031046102023000151400ustar 00000000000000/// Custom color structure, it will generate a true color in the result #[derive(Debug, Copy, Clone, PartialEq, Eq)] pub struct CustomColor { /// Red pub r: u8, /// Green pub g: u8, /// Blue pub b: u8, } /// This only makes custom color creation easier. impl CustomColor { /// Create a new custom color pub fn new(r: u8, g: u8, b: u8) -> Self { Self { r, g, b } } } impl From<(u8, u8, u8)> for CustomColor { fn from((r, g, b): (u8, u8, u8)) -> Self { Self::new(r, g, b) } } #[cfg(test)] mod tests { use crate::*; #[cfg_attr(feature = "no-color", ignore)] #[test] fn main() { let my_color = CustomColor::new(0, 120, 120); insta::assert_snapshot!("Greetings from Ukraine".custom_color(my_color)); } #[test] fn from_tuple() { let tuple = (1u8, 255u8, 0u8); let cc = CustomColor::from(tuple); assert_eq!(cc.r, tuple.0); assert_eq!(cc.g, tuple.1); assert_eq!(cc.b, tuple.2); } } colored-2.2.0/src/error.rs000064400000000000000000000010231046102023000135360ustar 00000000000000use super::ColoredString; use std::{error::Error, fmt}; pub struct ColoredStringError(pub ColoredString); impl ColoredStringError { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { write!(f, "{}", self.0) } } impl fmt::Display for ColoredStringError { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { self.fmt(f) } } impl fmt::Debug for ColoredStringError { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { self.fmt(f) } } impl Error for ColoredStringError {} colored-2.2.0/src/formatters.rs000064400000000000000000000004551046102023000146030ustar 00000000000000 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-2.2.0/src/lib.rs000064400000000000000000000667141046102023000131750ustar 00000000000000//!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 use truecolor values too!".truecolor(0, 255, 136); //! "background truecolor also works :)".on_truecolor(135, 28, 167); //! "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. //! //! Note: The methods of [`Colorize`], when used on [`str`]'s, return //! [`ColoredString`]'s. See [`ColoredString`] to learn more about them and //! what you can do with them beyond continue to use [`Colorize`] to further //! modify them. #![warn(missing_docs)] #[macro_use] extern crate lazy_static; #[cfg(test)] extern crate rspec; mod color; pub mod control; mod error; mod style; pub use self::customcolors::CustomColor; /// Custom colors support. pub mod customcolors; pub use color::*; use std::{ borrow::Cow, error::Error, fmt, ops::{Deref, DerefMut}, }; pub use style::{Style, Styles}; /// A string that may have color and/or style applied to it. /// /// Commonly created via calling the methods of [`Colorize`] on a &str. /// All methods of [`Colorize`] either create a new `ColoredString` from /// the type called on or modify a callee `ColoredString`. See /// [`Colorize`] for more. /// /// The primary usage of `ColoredString`'s is as a way to take text, /// apply colors and miscillaneous styling to it (such as bold or /// underline), and then use it to create formatted strings that print /// to the console with the special styling applied. /// /// ## Usage /// /// As stated, `ColoredString`'s, once created, can be printed to the /// console with their colors and style or turned into a string /// containing special console codes that has the same effect. /// This is made easy via `ColoredString`'s implementations of /// [`Display`](std::fmt::Display) and [`ToString`] for those purposes /// respectively. /// /// Printing a `ColoredString` with its style is as easy as: /// /// ``` /// # use colored::*; /// let cstring: ColoredString = "Bold and Red!".bold().red(); /// println!("{}", cstring); /// ``` /// /// ## Manipulating the coloring/style of a `ColoredString` /// /// Getting or changing the foreground color, background color, and or /// style of a `ColoredString` is as easy as manually reading / modifying /// the fields of `ColoredString`. /// /// ``` /// # use colored::*; /// let mut red_text = "Red".red(); /// // Changing color using re-assignment and [`Colorize`]: /// red_text = red_text.blue(); /// // Manipulating fields of `ColoredString` in-place: /// red_text.fgcolor = Some(Color::Blue); /// /// let styled_text1 = "Bold".bold(); /// let styled_text2 = "Italic".italic(); /// let mut styled_text3 = ColoredString::from("Bold and Italic"); /// styled_text3.style = styled_text1.style | styled_text2.style; /// ``` /// /// ## Modifying the text of a `ColoredString` /// /// Modifying the text is as easy as modifying the `input` field of /// `ColoredString`... /// /// ``` /// # use colored::*; /// let mut colored_text = "Magenta".magenta(); /// colored_text = colored_text.blue(); /// colored_text.input = "Blue".to_string(); /// // Note: The above is inefficient and `colored_text.input.replace_range(.., "Blue")` would /// // be more proper. This is just for example. /// /// assert_eq!(&*colored_text, "Blue"); /// ``` /// /// Notice how this process preserves the coloring and style. #[derive(Clone, Debug, Default, PartialEq, Eq)] #[non_exhaustive] pub struct ColoredString { /// The plain text that will have color and style applied to it. pub input: String, /// The color of the text as it will be printed. pub fgcolor: Option, /// The background color (if any). None means that the text will be printed /// without a special background. pub bgcolor: Option, /// Any special styling to be applied to the text (see Styles for a list of /// available options). pub 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`. #[allow(missing_docs)] pub trait Colorize { // Font Colors fn black(self) -> ColoredString where Self: Sized, { self.color(Color::Black) } fn red(self) -> ColoredString where Self: Sized, { self.color(Color::Red) } fn green(self) -> ColoredString where Self: Sized, { self.color(Color::Green) } fn yellow(self) -> ColoredString where Self: Sized, { self.color(Color::Yellow) } fn blue(self) -> ColoredString where Self: Sized, { self.color(Color::Blue) } fn magenta(self) -> ColoredString where Self: Sized, { self.color(Color::Magenta) } fn purple(self) -> ColoredString where Self: Sized, { self.color(Color::Magenta) } fn cyan(self) -> ColoredString where Self: Sized, { self.color(Color::Cyan) } fn white(self) -> ColoredString where Self: Sized, { self.color(Color::White) } fn bright_black(self) -> ColoredString where Self: Sized, { self.color(Color::BrightBlack) } fn bright_red(self) -> ColoredString where Self: Sized, { self.color(Color::BrightRed) } fn bright_green(self) -> ColoredString where Self: Sized, { self.color(Color::BrightGreen) } fn bright_yellow(self) -> ColoredString where Self: Sized, { self.color(Color::BrightYellow) } fn bright_blue(self) -> ColoredString where Self: Sized, { self.color(Color::BrightBlue) } fn bright_magenta(self) -> ColoredString where Self: Sized, { self.color(Color::BrightMagenta) } fn bright_purple(self) -> ColoredString where Self: Sized, { self.color(Color::BrightMagenta) } fn bright_cyan(self) -> ColoredString where Self: Sized, { self.color(Color::BrightCyan) } fn bright_white(self) -> ColoredString where Self: Sized, { self.color(Color::BrightWhite) } fn truecolor(self, r: u8, g: u8, b: u8) -> ColoredString where Self: Sized, { self.color(Color::TrueColor { r, g, b }) } fn custom_color(self, color: T) -> ColoredString where Self: Sized, T: Into, { let color = color.into(); self.color(Color::TrueColor { r: color.r, g: color.g, b: color.b, }) } fn color>(self, color: S) -> ColoredString; // Background Colors fn on_black(self) -> ColoredString where Self: Sized, { self.on_color(Color::Black) } fn on_red(self) -> ColoredString where Self: Sized, { self.on_color(Color::Red) } fn on_green(self) -> ColoredString where Self: Sized, { self.on_color(Color::Green) } fn on_yellow(self) -> ColoredString where Self: Sized, { self.on_color(Color::Yellow) } fn on_blue(self) -> ColoredString where Self: Sized, { self.on_color(Color::Blue) } fn on_magenta(self) -> ColoredString where Self: Sized, { self.on_color(Color::Magenta) } fn on_purple(self) -> ColoredString where Self: Sized, { self.on_color(Color::Magenta) } fn on_cyan(self) -> ColoredString where Self: Sized, { self.on_color(Color::Cyan) } fn on_white(self) -> ColoredString where Self: Sized, { self.on_color(Color::White) } fn on_bright_black(self) -> ColoredString where Self: Sized, { self.on_color(Color::BrightBlack) } fn on_bright_red(self) -> ColoredString where Self: Sized, { self.on_color(Color::BrightRed) } fn on_bright_green(self) -> ColoredString where Self: Sized, { self.on_color(Color::BrightGreen) } fn on_bright_yellow(self) -> ColoredString where Self: Sized, { self.on_color(Color::BrightYellow) } fn on_bright_blue(self) -> ColoredString where Self: Sized, { self.on_color(Color::BrightBlue) } fn on_bright_magenta(self) -> ColoredString where Self: Sized, { self.on_color(Color::BrightMagenta) } fn on_bright_purple(self) -> ColoredString where Self: Sized, { self.on_color(Color::BrightMagenta) } fn on_bright_cyan(self) -> ColoredString where Self: Sized, { self.on_color(Color::BrightCyan) } fn on_bright_white(self) -> ColoredString where Self: Sized, { self.on_color(Color::BrightWhite) } fn on_truecolor(self, r: u8, g: u8, b: u8) -> ColoredString where Self: Sized, { self.on_color(Color::TrueColor { r, g, b }) } fn on_custom_color(self, color: T) -> ColoredString where Self: Sized, T: Into, { let color = color.into(); self.on_color(Color::TrueColor { r: color.r, g: color.g, b: color.b, }) } 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; #[deprecated(since = "1.5.2", note = "Users should use reversed instead")] fn reverse(self) -> ColoredString; fn reversed(self) -> ColoredString; fn hidden(self) -> ColoredString; fn strikethrough(self) -> ColoredString; } impl ColoredString { /// Get the current background color applied. /// /// ```rust /// # use colored::*; /// let cstr = "".blue(); /// assert_eq!(cstr.fgcolor(), Some(Color::Blue)); /// let cstr = cstr.clear(); /// assert_eq!(cstr.fgcolor(), None); /// ``` #[deprecated(note = "Deprecated due to the exposing of the fgcolor struct field.")] pub fn fgcolor(&self) -> Option { self.fgcolor.as_ref().copied() } /// Get the current background color applied. /// /// ```rust /// # use colored::*; /// let cstr = "".on_blue(); /// assert_eq!(cstr.bgcolor(), Some(Color::Blue)); /// let cstr = cstr.clear(); /// assert_eq!(cstr.bgcolor(), None); /// ``` #[deprecated(note = "Deprecated due to the exposing of the bgcolor struct field.")] pub fn bgcolor(&self) -> Option { self.bgcolor.as_ref().copied() } /// Get the current [`Style`] which can be check if it contains a [`Styles`]. /// /// ```rust /// # use colored::*; /// let colored = "".bold().italic(); /// assert_eq!(colored.style().contains(Styles::Bold), true); /// assert_eq!(colored.style().contains(Styles::Italic), true); /// assert_eq!(colored.style().contains(Styles::Dimmed), false); /// ``` #[deprecated(note = "Deprecated due to the exposing of the style struct field.")] pub fn style(&self) -> style::Style { self.style } /// Clears foreground coloring on this `ColoredString`, meaning that it /// will be printed with the default terminal text color. pub fn clear_fgcolor(&mut self) { self.fgcolor = None; } /// Gets rid of this `ColoredString`'s background. pub fn clear_bgcolor(&mut self) { self.bgcolor = None; } /// Clears any special styling and sets it back to the default (plain, /// maybe colored, text). pub fn clear_style(&mut self) { self.style = Style::default(); } /// Checks if the colored string has no color or styling. /// /// ```rust /// # use colored::*; /// let cstr = "".red(); /// assert_eq!(cstr.is_plain(), false); /// let cstr = cstr.clear(); /// assert_eq!(cstr.is_plain(), true); /// ``` 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() -> bool { control::SHOULD_COLORIZE.should_colorize() } #[cfg(feature = "no-color")] fn has_colors() -> bool { false } fn compute_style(&self) -> String { if !ColoredString::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) -> Cow { if !ColoredString::has_colors() || self.is_plain() { return self.input.as_str().into(); } // TODO: BoyScoutRule let reset = "\x1B[0m"; let style = self.compute_style(); let matches: Vec = self .input .match_indices(reset) .map(|(idx, _)| idx) .collect(); if matches.is_empty() { return self.input.as_str().into(); } let mut input = self.input.clone(); input.reserve(matches.len() * style.len()); for (idx_in_matches, offset) in matches.into_iter().enumerate() { // 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; } } input.into() } } impl Deref for ColoredString { type Target = str; fn deref(&self) -> &Self::Target { &self.input } } impl DerefMut for ColoredString { fn deref_mut(&mut self) -> &mut ::Target { &mut self.input } } impl From for ColoredString { fn from(s: String) -> Self { ColoredString { input: s, ..ColoredString::default() } } } impl<'a> From<&'a str> for ColoredString { fn from(s: &'a str) -> Self { ColoredString { input: String::from(s), ..ColoredString::default() } } } impl Colorize for ColoredString { fn color>(mut self, color: S) -> ColoredString { self.fgcolor = Some(color.into()); self } fn on_color>(mut self, color: S) -> ColoredString { self.bgcolor = Some(color.into()); self } fn clear(self) -> ColoredString { ColoredString { input: self.input, ..ColoredString::default() } } fn normal(self) -> ColoredString { self.clear() } fn bold(mut self) -> ColoredString { self.style.add(style::Styles::Bold); self } fn dimmed(mut self) -> ColoredString { self.style.add(style::Styles::Dimmed); self } fn italic(mut self) -> ColoredString { self.style.add(style::Styles::Italic); self } fn underline(mut self) -> ColoredString { self.style.add(style::Styles::Underline); self } fn blink(mut self) -> ColoredString { self.style.add(style::Styles::Blink); self } fn reverse(self) -> ColoredString { self.reversed() } fn reversed(mut self) -> ColoredString { self.style.add(style::Styles::Reversed); self } fn hidden(mut self) -> ColoredString { self.style.add(style::Styles::Hidden); self } fn strikethrough(mut self) -> ColoredString { self.style.add(style::Styles::Strikethrough); self } } impl Colorize for &str { fn color>(self, color: S) -> ColoredString { ColoredString { fgcolor: Some(color.into()), input: String::from(self), ..ColoredString::default() } } 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() } fn bold(self) -> ColoredString { ColoredString::from(self).bold() } fn dimmed(self) -> ColoredString { ColoredString::from(self).dimmed() } fn italic(self) -> ColoredString { ColoredString::from(self).italic() } fn underline(self) -> ColoredString { ColoredString::from(self).underline() } fn blink(self) -> ColoredString { ColoredString::from(self).blink() } fn reverse(self) -> ColoredString { self.reversed() } fn reversed(self) -> ColoredString { ColoredString::from(self).reversed() } fn hidden(self) -> ColoredString { ColoredString::from(self).hidden() } fn strikethrough(self) -> ColoredString { ColoredString::from(self).strikethrough() } } impl fmt::Display for ColoredString { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { if !ColoredString::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(); f.write_str(&self.compute_style())?; escaped_input.fmt(f)?; f.write_str("\x1B[0m")?; Ok(()) } } impl From for Box { fn from(cs: ColoredString) -> Box { Box::from(error::ColoredStringError(cs)) } } #[cfg(test)] mod tests { use super::*; use std::{error::Error, fmt::Write}; #[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() -> Result<(), Box> { let mut buf = String::new(); let toto = "toto"; writeln!(&mut buf, "{}", toto.red())?; writeln!(&mut buf, "{}", String::from(toto).red())?; writeln!(&mut buf, "{}", toto.blue())?; writeln!(&mut buf, "blue style ****")?; writeln!(&mut buf, "{}", toto.bold())?; writeln!(&mut buf, "{}", "yeah ! Red bold !".red().bold())?; writeln!(&mut buf, "{}", "yeah ! Yellow bold !".bold().yellow())?; writeln!(&mut buf, "{}", toto.bold().blue())?; writeln!(&mut buf, "{}", toto.blue().bold())?; writeln!(&mut buf, "{}", toto.blue().bold().underline())?; writeln!(&mut buf, "{}", toto.blue().italic())?; writeln!(&mut buf, "******")?; writeln!(&mut buf, "test clearing")?; writeln!(&mut buf, "{}", "red cleared".red().clear())?; writeln!(&mut buf, "{}", "bold cyan cleared".bold().cyan().clear())?; writeln!(&mut buf, "******")?; writeln!(&mut buf, "Bg tests")?; writeln!(&mut buf, "{}", toto.green().on_blue())?; writeln!(&mut buf, "{}", toto.on_magenta().yellow())?; writeln!(&mut buf, "{}", toto.purple().on_yellow())?; writeln!(&mut buf, "{}", toto.magenta().on_white())?; writeln!(&mut buf, "{}", toto.cyan().on_green())?; writeln!(&mut buf, "{}", toto.black().on_white())?; writeln!(&mut buf, "******")?; writeln!(&mut buf, "{}", toto.green())?; writeln!(&mut buf, "{}", toto.yellow())?; writeln!(&mut buf, "{}", toto.purple())?; writeln!(&mut buf, "{}", toto.magenta())?; writeln!(&mut buf, "{}", toto.cyan())?; writeln!(&mut buf, "{}", toto.white())?; writeln!(&mut buf, "{}", toto.white().red().blue().green())?; writeln!(&mut buf, "{}", toto.truecolor(255, 0, 0))?; writeln!(&mut buf, "{}", toto.truecolor(255, 255, 0))?; writeln!(&mut buf, "{}", toto.on_truecolor(0, 80, 80))?; writeln!(&mut buf, "{}", toto.custom_color((255, 255, 0)))?; writeln!(&mut buf, "{}", toto.on_custom_color((0, 80, 80)))?; #[cfg(feature = "no-color")] insta::assert_snapshot!("it_works_no_color", buf); #[cfg(not(feature = "no-color"))] insta::assert_snapshot!("it_works", buf); Ok(()) } #[test] fn compute_style_empty_string() { assert_eq!("", "".clear().compute_style()); } #[cfg_attr(feature = "no-color", ignore)] #[test] fn compute_style_simple_fg_blue() { let blue = "\x1B[34m"; assert_eq!(blue, "".blue().compute_style()); } #[cfg_attr(feature = "no-color", ignore)] #[test] fn compute_style_simple_bg_blue() { let on_blue = "\x1B[44m"; assert_eq!(on_blue, "".on_blue().compute_style()); } #[cfg_attr(feature = "no-color", ignore)] #[test] fn compute_style_blue_on_blue() { let blue_on_blue = "\x1B[44;34m"; assert_eq!(blue_on_blue, "".blue().on_blue().compute_style()); } #[cfg_attr(feature = "no-color", ignore)] #[test] fn compute_style_simple_fg_bright_blue() { let blue = "\x1B[94m"; assert_eq!(blue, "".bright_blue().compute_style()); } #[cfg_attr(feature = "no-color", ignore)] #[test] fn compute_style_simple_bg_bright_blue() { let on_blue = "\x1B[104m"; assert_eq!(on_blue, "".on_bright_blue().compute_style()); } #[cfg_attr(feature = "no-color", ignore)] #[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() ); } #[cfg_attr(feature = "no-color", ignore)] #[test] fn compute_style_simple_bold() { let bold = "\x1B[1m"; assert_eq!(bold, "".bold().compute_style()); } #[cfg_attr(feature = "no-color", ignore)] #[test] fn compute_style_blue_bold() { let blue_bold = "\x1B[1;34m"; assert_eq!(blue_bold, "".blue().bold().compute_style()); } #[cfg_attr(feature = "no-color", ignore)] #[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); } #[cfg_attr(feature = "no-color", ignore)] #[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); } #[cfg_attr(feature = "no-color", ignore)] #[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")); } #[test] fn exposing_tests() { #![allow(deprecated)] let cstring = "".red(); assert_eq!(cstring.fgcolor(), Some(Color::Red)); assert_eq!(cstring.bgcolor(), None); let cstring = cstring.clear(); assert_eq!(cstring.fgcolor(), None); assert_eq!(cstring.bgcolor(), None); let cstring = cstring.blue().on_bright_yellow(); assert_eq!(cstring.fgcolor(), Some(Color::Blue)); assert_eq!(cstring.bgcolor(), Some(Color::BrightYellow)); let cstring = cstring.bold().italic(); assert_eq!(cstring.fgcolor(), Some(Color::Blue)); assert_eq!(cstring.bgcolor(), Some(Color::BrightYellow)); assert!(cstring.style().contains(Styles::Bold)); assert!(cstring.style().contains(Styles::Italic)); assert!(!cstring.style().contains(Styles::Dimmed)); } } colored-2.2.0/src/snapshots/colored__customcolors__tests__main.snap000064400000000000000000000002201046102023000240700ustar 00000000000000--- source: src/customcolors.rs expression: "\"Greetings from Ukraine\".custom_color(my_color)" --- Greetings from Ukraine colored-2.2.0/src/snapshots/colored__tests__it_works.snap000064400000000000000000000012001046102023000220310ustar 00000000000000--- source: src/lib.rs expression: buf --- toto toto toto blue style **** toto yeah ! Red bold ! yeah ! Yellow bold ! toto toto toto toto ****** test clearing red cleared bold cyan cleared ****** Bg tests toto toto toto toto toto toto ****** toto toto toto toto toto toto toto toto toto toto toto toto colored-2.2.0/src/snapshots/colored__tests__it_works_no_color.snap000064400000000000000000000004571046102023000237400ustar 00000000000000--- source: src/lib.rs expression: buf --- toto toto toto blue style **** toto yeah ! Red bold ! yeah ! Yellow bold ! toto toto toto toto ****** test clearing red cleared bold cyan cleared ****** Bg tests toto toto toto toto toto toto ****** toto toto toto toto toto toto toto toto toto toto toto toto colored-2.2.0/src/style.rs000064400000000000000000000565461046102023000135710ustar 00000000000000use core::ops::{BitAnd, BitAndAssign, BitOr, BitOrAssign, BitXor, BitXorAssign, Not}; macro_rules! auto_impl_ref_binop_trait { (impl $trait_name:ident, $method:ident for $t:ty, $u:ty) => { impl $trait_name<&$u> for $t { type Output = <$t as $trait_name<$t>>::Output; #[inline] fn $method(self, rhs: &$u) -> Self::Output { $trait_name::$method(self, *rhs) } } impl $trait_name<$u> for &$t { type Output = <$t as $trait_name<$t>>::Output; #[inline] fn $method(self, rhs: $u) -> Self::Output { $trait_name::$method(*self, rhs) } } impl $trait_name<&$u> for &$t { type Output = <$t as $trait_name<$t>>::Output; #[inline] fn $method(self, rhs: &$u) -> Self::Output { $trait_name::$method(*self, *rhs) } } }; } macro_rules! impl_assign_op_trait { ( $trait:ident, $method:ident for $t:ty, $u:ty, using $used_trait:ident::$used_method:ident ) => { impl $trait<$u> for $t { #[inline] fn $method(&mut self, other: $u) { *self = $used_trait::$used_method(&*self, other); } } impl $trait<&$u> for $t { #[inline] fn $method(&mut self, other: &$u) { *self = $used_trait::$used_method(&*self, other); } } }; } const 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); /// A combinatorial style such as bold, italics, dimmed, etc. /// /// ## Creation /// /// `Style::default()` returns a `Style` with no style switches /// activated and is the default method of creating a plain `Style`. /// /// ## `Style` from a set of `Styles`s / `Styles` iterator /// /// `Style` implements `FromIter` which means that it is /// possible to do the following: /// /// ```rust /// # use colored::*; /// let style = Style::from_iter([Styles::Bold, Styles::Italic, Styles::Strikethrough]); /// for styles in [Styles::Bold, Styles::Italic, Styles::Strikethrough] { /// assert!(style.contains(styles)); /// } /// ``` /// /// As you can see, this is a good thing to keep in mind, although for /// most cases, where you're not setting styles dynamically and are /// simply creating a pre-defined set of styles, using [`Default`] and /// then using the builder-style methods is likely prettier. /// /// ```rust /// # use colored::*; /// let many_styles = Style::default() /// .bold() /// .underline() /// .italic() /// .blink(); /// ``` /// /// ## Implementation of logical bitwise operators /// /// `Style` implements bitwise logical operations that operate on /// the held style switches collectively. By far the most common /// and useful is the bitwise 'or' operator `|` which combines two /// styles, merging their combined styles into one. Example: /// /// ```rust /// # use colored::*; /// let only_bold = Style::from(Styles::Bold); /// // This line is actually an example of `Styles`'s bitwise logic impls but still. /// let underline_and_italic = Styles::Underline | Styles::Italic; /// let all_three = only_bold | underline_and_italic; /// /// assert!(all_three.contains(Styles::Bold) /// && all_three.contains(Styles::Underline) /// && all_three.contains(Styles::Italic)); /// ``` /// /// This functionality also allows for easily turning off styles /// of one `Styles` using another by combining the `&` and `!` /// operators. /// /// ```rust /// # use colored::*; /// let mut very_loud_style = Style::default() /// .bold() /// .underline() /// .italic() /// .strikethrough() /// .hidden(); /// /// // Oops! Some of those should not be in there! /// // This Style now has all styles _except_ the two we don't want /// // (hidden and strikethough). /// let remove_mask = /// !Style::from_iter([Styles::Hidden, Styles::Strikethrough]); /// very_loud_style &= remove_mask; /// /// // `very_loud_style` no longer contains the undesired style /// // switches... /// assert!(!very_loud_style.contains(Styles::Hidden) /// && !very_loud_style.contains(Styles::Strikethrough)); /// // ...but it retains everything else! /// assert!(very_loud_style.contains(Styles::Bold)); /// ``` #[derive(Clone, Copy, PartialEq, Eq, Debug)] pub struct Style(u8); /// Enum containing all of the available style settings that can be /// applied to a [`Styles`] and by extension, a colrized type. /// /// ## Implementation of bitwise logical operators /// /// The implementations of [`BitAnd`], [`BitOr`], [`BitXor`], and /// [`Not`] are really extensions of [`Style`]'s implementations of /// the same. [`BitOr`] is great for starting chains of `Styles`'s /// for creating [`Style`]'s. /// /// ``` /// # use colored::*; /// let my_styles = /// // BitOr for Styles (Styles | Styles) = Style /// Styles::Bold | Styles::Underline /// // BitOr for Style (Style | Styles) = Style /// | Styles::Italic; /// /// for s in [Styles::Bold, Styles::Underline, Styles::Italic] { /// assert!(my_styles.contains(s)); /// } /// ``` /// /// [`Not`] has far fewer use cases but can still find use in /// turning a `Styles` into a [`Style`] with all styles activated /// except that `Styles`. /// /// ``` /// # use colored::*; /// let everything_but_bold = !Styles::Bold; /// /// assert!(everything_but_bold.contains(Styles::Underline)); /// assert!(everything_but_bold.contains(Styles::Strikethrough)); /// assert!(!everything_but_bold.contains(Styles::Bold)); /// ``` #[derive(Clone, Copy, PartialEq, Eq, Debug)] #[allow(missing_docs)] 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 .iter() .filter(|&(mask, _)| (0 != (u & mask))) .map(|&(_, value)| value) .collect(); if res.is_empty() { None } else { Some(res) } } } impl BitAnd for Styles { type Output = Style; fn bitand(self, rhs: Styles) -> Self::Output { Style(self.to_u8() & rhs.to_u8()) } } auto_impl_ref_binop_trait!(impl BitAnd, bitand for Styles, Styles); impl BitAnd