Skip to content

Commit

Permalink
Merge branch 'master' into chore/156/snapshot-tests
Browse files Browse the repository at this point in the history
  • Loading branch information
kurtlawrence authored Dec 12, 2023
2 parents 913e70c + c3dcd33 commit 6b3e65e
Show file tree
Hide file tree
Showing 6 changed files with 801 additions and 58 deletions.
2 changes: 2 additions & 0 deletions .github/workflows/test.yml
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,8 @@ jobs:
name: Check semver compatibility
runs-on: ubuntu-latest
steps:
- name: Checkout repository
uses: actions/checkout@v3
- name: Check semver
uses: obi1kenobi/cargo-semver-checks-action@v2

22 changes: 21 additions & 1 deletion CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,26 @@
# Unreleased
- Document crate MSRV of `1.70`.
- Handle errors in `set_virtual_terminal`.

- 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<Styles>` 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<Styles>` 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.0.4
- Switch from `winapi` to `windows-sys`.
Expand Down
101 changes: 77 additions & 24 deletions src/color.rs
Original file line number Diff line number Diff line change
Expand Up @@ -52,7 +52,9 @@ impl Color {
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 { .. } if !truecolor_support() => {
self.closest_color_euclidean().to_fg_str()
}
Color::TrueColor { r, g, b } => format!("38;2;{};{};{}", r, g, b).into(),
}
}
Expand All @@ -75,18 +77,24 @@ impl Color {
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 { .. } 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 Color::*;
use std::cmp;
use Color::*;

match *self {
TrueColor { r: r1, g: g1, b: b1 } => {
TrueColor {
r: r1,
g: g1,
b: b1,
} => {
let colors = vec![
Black,
Red,
Expand All @@ -104,7 +112,9 @@ impl Color {
BrightMagenta,
BrightCyan,
BrightWhite,
].into_iter().map(|c| (c, c.into_truecolor()));
]
.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);
Expand All @@ -123,28 +133,67 @@ impl Color {
}
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 },
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 },
}
}
Expand Down Expand Up @@ -300,11 +349,15 @@ mod tests {
( $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 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 }
Expand Down
15 changes: 4 additions & 11 deletions src/control.rs
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,9 @@ use std::sync::atomic::{AtomicBool, Ordering};
/// 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.
///
Expand All @@ -25,25 +28,15 @@ use std::sync::atomic::{AtomicBool, Ordering};
#[allow(clippy::result_unit_err)]
#[cfg(windows)]
pub fn set_virtual_terminal(use_virtual: bool) -> Result<(), ()> {
use windows_sys::Win32::Foundation::INVALID_HANDLE_VALUE;
use windows_sys::Win32::System::Console::{
GetConsoleMode, GetStdHandle, SetConsoleMode, ENABLE_VIRTUAL_TERMINAL_PROCESSING,
STD_OUTPUT_HANDLE,
};

unsafe {
let handle = GetStdHandle(STD_OUTPUT_HANDLE);
if handle == INVALID_HANDLE_VALUE {
return Err(());
}

let mut original_mode = 0;
// Return value of 0 means that the function failed:
// https://learn.microsoft.com/en-us/windows/console/getconsolemode#return-value
if GetConsoleMode(handle, &mut original_mode) == 0 {
// TODO: It would be prudent to get the error using `GetLastError` here.
return Err(());
}
GetConsoleMode(handle, &mut original_mode);

let enabled = original_mode & ENABLE_VIRTUAL_TERMINAL_PROCESSING
== ENABLE_VIRTUAL_TERMINAL_PROCESSING;
Expand Down
Loading

0 comments on commit 6b3e65e

Please sign in to comment.