Skip to content

Commit

Permalink
🔥 Remove public xparsecolor from colorsaurus
Browse files Browse the repository at this point in the history
  • Loading branch information
bash committed Jan 3, 2025
1 parent b49e903 commit 2c60028
Show file tree
Hide file tree
Showing 7 changed files with 35 additions and 307 deletions.
1 change: 1 addition & 0 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

15 changes: 6 additions & 9 deletions crates/terminal-colorsaurus/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -11,27 +11,24 @@ edition = "2021"
rust-version = "1.70.0" # Search for `FIXME(msrv)` when bumping.
exclude = [".github", ".gitignore", "*.sh", "benchmark/**/*", "doc/issues.md", "deny.toml"]

[features]
default = ["query"]
query = ["dep:memchr", "dep:mio", "dep:terminal-trx", "dep:libc", "dep:windows-sys"]

[dependencies]
rgb = { version = "0.8.37", optional = true }
anstyle = { version = "1.0.7", optional = true }
cfg-if = "1.0.0"
xterm-color = { path = "../xterm-color", version = "1.0" }

[target.'cfg(any(unix, windows))'.dependencies]
memchr = { version = "2.7.1", optional = true }
terminal-trx = { version = "0.2.3", optional = true }
memchr = "2.7.1"
terminal-trx = "0.2.3"

[target.'cfg(unix)'.dependencies]
mio = { version = "1", features = ["os-ext"], default-features = false, optional = true }
mio = { version = "1", features = ["os-ext"], default-features = false }

[target.'cfg(target_os = "macos")'.dependencies]
libc = { version = "0.2.151", optional = true }
libc = "0.2.151"

[target.'cfg(windows)'.dependencies]
windows-sys = { version = "0.59.0", features = ["Win32_System_Threading"], optional = true } # Keep this in sync with terminal-trx's version to avoid duplicate deps.
windows-sys = { version = "0.59.0", features = ["Win32_System_Threading"] } # Keep this in sync with terminal-trx's version to avoid duplicate deps.

[lints]
workspace = true
Expand Down
35 changes: 6 additions & 29 deletions crates/terminal-colorsaurus/src/color.rs
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ impl Color {
/// let is_dark = color.perceived_lightness() <= 50;
/// ```
pub fn perceived_lightness(&self) -> u8 {
luminance_to_perceived_lightness(luminance(self))
(self.perceived_lightness_f32() * 100.) as u8
}

/// Converts the color to 8 bit precision per channel by scaling each channel.
Expand All @@ -41,6 +41,11 @@ impl Color {
scale_to_u8(self.b),
)
}

pub(crate) fn perceived_lightness_f32(&self) -> f32 {
let color = xterm_color::Color::rgb(self.r, self.g, self.b);
color.perceived_lightness()
}
}

fn scale_to_u8(channel: u16) -> u8 {
Expand Down Expand Up @@ -85,34 +90,6 @@ impl From<Color> for anstyle::RgbColor {
}
}

// Implementation of determining the perceived lightness
// follows this excellent answer: https://stackoverflow.com/a/56678483

fn srgb_to_lin(channel: f64) -> f64 {
if channel < 0.04045 {
channel / 12.92
} else {
((channel + 0.055) / 1.055).powf(2.4)
}
}

// Luminance (Y)
fn luminance(color: &Color) -> f64 {
let r = f64::from(color.r) / f64::from(u16::MAX);
let g = f64::from(color.g) / f64::from(u16::MAX);
let b = f64::from(color.b) / f64::from(u16::MAX);
0.2126 * srgb_to_lin(r) + 0.7152 * srgb_to_lin(g) + 0.0722 * srgb_to_lin(b)
}

// Perceptual lightness (L*)
fn luminance_to_perceived_lightness(luminance: f64) -> u8 {
if luminance < 216. / 24389. {
(luminance * (24389. / 27.)) as u8
} else {
(luminance.powf(1. / 3.) * 116. - 16.) as u8
}
}

#[cfg(test)]
mod tests {
use super::*;
Expand Down
15 changes: 9 additions & 6 deletions crates/terminal-colorsaurus/src/color_scheme_tests.rs
Original file line number Diff line number Diff line change
Expand Up @@ -54,9 +54,9 @@ mod dark {
#[test]
fn fg_and_bg_both_dark() {
for (foreground, background) in [(DARK_GRAY, DARKER_GRAY), (DARKER_GRAY, BLACK)] {
assert!(foreground.perceived_lightness() < PERCEPTUAL_MIDDLE_GRAY);
assert!(background.perceived_lightness() < PERCEPTUAL_MIDDLE_GRAY);
assert!(foreground.perceived_lightness() != background.perceived_lightness());
assert!(foreground.perceived_lightness_f32() < 0.5);
assert!(background.perceived_lightness_f32() < 0.5);
assert!(foreground.perceived_lightness_f32() != background.perceived_lightness_f32());

let palette = ColorPalette {
foreground,
Expand Down Expand Up @@ -93,9 +93,12 @@ mod light {
#[test]
fn fg_and_bg_both_light() {
for (foreground, background) in [(LIGHT_GRAY, LIGHTER_GRAY), (LIGHTER_GRAY, WHITE)] {
assert!(foreground.perceived_lightness() > PERCEPTUAL_MIDDLE_GRAY);
assert!(background.perceived_lightness() > PERCEPTUAL_MIDDLE_GRAY);
assert!(foreground.perceived_lightness() != background.perceived_lightness());
assert!(foreground.perceived_lightness_f32() > 0.5);
assert!(background.perceived_lightness_f32() > 0.5);
assert!(
(foreground.perceived_lightness_f32() - background.perceived_lightness_f32()).abs()
>= f32::EPSILON
);

let palette = ColorPalette {
foreground,
Expand Down
34 changes: 3 additions & 31 deletions crates/terminal-colorsaurus/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -45,22 +45,6 @@ mod color;
mod error;
mod fmt;

/// Low-level utilities for parsing responses to `OSC 10` / `OSC 11` queries.
///
/// **Hint:** If you are only using this module, then you should probably disable
/// the default features to avoid unnecessary dependencies:
///
/// ```toml
/// [dependencies]
/// terminal-colorsaurus = { version = "...", default-features = false }
/// ```
pub mod parse {
pub use crate::xparsecolor::xparsecolor;
}

mod xparsecolor;

#[cfg(feature = "query")]
cfg_if! {
if #[cfg(all(any(unix, windows), not(terminal_colorsaurus_test_unsupported)))] {
mod io;
Expand Down Expand Up @@ -101,7 +85,6 @@ pub use color::*;

/// The color palette i.e. foreground and background colors of the terminal.
/// Retrieved by calling [`color_palette`].
#[cfg(feature = "query")]
#[derive(Debug, Clone, PartialEq, Eq)]
#[non_exhaustive]
pub struct ColorPalette {
Expand All @@ -115,7 +98,6 @@ pub struct ColorPalette {
///
/// The easiest way to retrieve the color scheme
/// is by calling [`color_scheme`].
#[cfg(feature = "query")]
#[derive(Debug, Clone, Copy, PartialEq, Eq, Default)]
#[allow(clippy::exhaustive_enums)]
#[doc(alias = "Theme")]
Expand All @@ -127,18 +109,14 @@ pub enum ColorScheme {
Light,
}

#[cfg(feature = "query")]
const PERCEPTUAL_MIDDLE_GRAY: u8 = 50;

#[cfg(feature = "query")]
impl ColorPalette {
/// Determines if the terminal uses a dark or light background.
pub fn color_scheme(&self) -> ColorScheme {
let fg = self.foreground.perceived_lightness();
let bg = self.background.perceived_lightness();
let fg = self.foreground.perceived_lightness_f32();
let bg = self.background.perceived_lightness_f32();
if bg < fg {
ColorScheme::Dark
} else if bg > fg || bg > PERCEPTUAL_MIDDLE_GRAY {
} else if bg > fg || bg > 0.5 {
ColorScheme::Light
} else {
ColorScheme::Dark
Expand All @@ -152,7 +130,6 @@ pub use error::Error;

/// Options to be used with [`foreground_color`] and [`background_color`].
/// You should almost always use the unchanged [`QueryOptions::default`] value.
#[cfg(feature = "query")]
#[derive(Debug, Clone, PartialEq, Eq)]
#[non_exhaustive]
pub struct QueryOptions {
Expand All @@ -168,7 +145,6 @@ pub struct QueryOptions {
pub timeout: std::time::Duration,
}

#[cfg(feature = "query")]
impl Default for QueryOptions {
fn default() -> Self {
Self {
Expand All @@ -178,23 +154,20 @@ impl Default for QueryOptions {
}

/// Detects if the terminal is dark or light.
#[cfg(feature = "query")]
#[doc = include_str!("../doc/caveats.md")]
#[doc(alias = "theme")]
pub fn color_scheme(options: QueryOptions) -> Result<ColorScheme> {
color_palette(options).map(|p| p.color_scheme())
}

/// Queries the terminal for it's color scheme (foreground and background color).
#[cfg(feature = "query")]
#[doc = include_str!("../doc/caveats.md")]
pub fn color_palette(options: QueryOptions) -> Result<ColorPalette> {
imp::color_palette(options)
}

/// Queries the terminal for it's foreground color. \
/// If you also need the foreground color it is more efficient to use [`color_palette`] instead.
#[cfg(feature = "query")]
#[doc = include_str!("../doc/caveats.md")]
#[doc(alias = "fg")]
pub fn foreground_color(options: QueryOptions) -> Result<Color> {
Expand All @@ -203,7 +176,6 @@ pub fn foreground_color(options: QueryOptions) -> Result<Color> {

/// Queries the terminal for it's background color. \
/// If you also need the foreground color it is more efficient to use [`color_palette`] instead.
#[cfg(feature = "query")]
#[doc = include_str!("../doc/caveats.md")]
#[doc(alias = "bg")]
pub fn background_color(options: QueryOptions) -> Result<Color> {
Expand Down
Loading

0 comments on commit 2c60028

Please sign in to comment.