1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295
#![no_std]
//! Internal implementation details of [`stylish-core`](https://docs.rs/stylish-core).
//!
//! Do not depend on this crate directly.
#![warn(missing_copy_implementations)]
#![warn(missing_debug_implementations)]
#![warn(missing_docs)]
#![warn(trivial_casts)]
#![warn(trivial_numeric_casts)]
#![warn(unused_extern_crates)]
#![warn(unused_import_braces)]
#![warn(variant_size_differences)]
#![cfg_attr(docsrs, feature(doc_cfg, doc_auto_cfg))]
#[cfg(feature = "alloc")]
extern crate alloc;
/// A color that can be used with [`Foreground`] to modify [`Style::foreground`]
/// or [`Background`] to modify [`Style::background`].
#[allow(dead_code)]
#[derive(Copy, Clone, Debug, Eq, PartialEq)]
#[non_exhaustive]
pub enum Color {
/// Black
Black,
/// Red
Red,
/// Green
Green,
/// Yellow
Yellow,
/// Blue
Blue,
/// Magenta
Magenta,
/// Cyan
Cyan,
/// White
White,
/// Default color
Default,
}
/// An intensity to render text with, to emphasise or de-emphasise it as needed.
#[derive(Copy, Clone, Debug, Eq, PartialEq)]
#[non_exhaustive]
pub enum Intensity {
/// The normal intensity
Normal,
/// A bolder intensity to emphasise content
Bold,
/// A fainter intensity to de-emphasise content
Faint,
}
/// A style to render text with, setting the foreground and background colors,
/// along with intensity.
#[derive(Copy, Clone, Debug, Default, Eq, PartialEq)]
#[non_exhaustive]
pub struct Style {
/// The text foreground color
pub foreground: Color,
/// The text background color
pub background: Color,
/// The text intensity
pub intensity: Intensity,
}
/// A diff between two styles.
///
/// Most useful for some implementors of `stylish::Write` to detect changes
/// between two parts, or for applying multiple changes to a style at once.
#[derive(Copy, Clone, Debug, Default, Eq, PartialEq)]
#[non_exhaustive]
pub struct StyleDiff {
/// The change in the text foreground color
pub foreground: Option<Color>,
/// The change in the text background color
pub background: Option<Color>,
/// The change in the text intensity
pub intensity: Option<Intensity>,
}
/// A [`Restyle`] implementor for setting [`Style::foreground`].
///
/// ```rust
/// use stylish::{Color, Foreground, Style};
///
/// let mut expected = Style::default();
/// expected.foreground = Color::Magenta;
///
/// assert_eq!(Style::default().with(Foreground(Color::Magenta)), expected);
/// ```
#[derive(Copy, Clone, Debug, Default, Eq, PartialEq)]
pub struct Foreground(pub Color);
/// A [`Restyle`] implementor for setting [`Style::background`].
///
/// ```rust
/// use stylish::{Background, Color, Style};
///
/// let mut expected = Style::default();
/// expected.background = Color::Magenta;
///
/// assert_eq!(Style::default().with(Background(Color::Magenta)), expected);
/// ```
#[derive(Copy, Clone, Debug, Default, Eq, PartialEq)]
pub struct Background(pub Color);
/// A trait for modifications to [`Style`], allowing an ergonomic API with
/// [`Style::with`] and `stylish::Formatter::with`.
///
/// ```rust
/// use stylish::{Color, Foreground, Intensity, Restyle, Style};
///
/// struct OhNo;
///
/// impl Restyle for OhNo {
/// fn apply(&self, style: Style) -> Style {
/// style.with(Foreground(Color::Red)).with(Intensity::Bold)
/// }
/// }
///
/// let mut expected = Style::default();
/// expected.foreground = Color::Red;
/// expected.intensity = Intensity::Bold;
///
/// assert_eq!(Style::default().with(OhNo), expected);
/// ```
pub trait Restyle {
/// Apply the restyling this instance represents to an existing style,
/// returning the updated style.
fn apply(&self, style: Style) -> Style;
}
impl Default for Color {
fn default() -> Self {
Self::Default
}
}
impl Default for Intensity {
fn default() -> Self {
Self::Normal
}
}
impl Style {
/// Apply a modification to this style, returning the result.
///
/// ```rust
/// use stylish::{Intensity, Style};
///
/// let mut expected = Style::default();
/// expected.intensity = Intensity::Faint;
///
/// assert_eq!(Style::default().with(Intensity::Faint), expected);
/// ```
pub fn with(self, adj: impl Restyle) -> Self {
adj.apply(self)
}
/// Find the changes from the `original` style that would result in this
/// style.
///
/// This can be useful for writers like `ansi` that are stateful, finding
/// the minimal state that must be changed between the current output
/// style and the new style.
///
/// ```rust
/// use stylish::{Color, Foreground, Style, StyleDiff};
///
/// let original = Style::default();
/// let updated = original.with(Foreground(Color::Cyan));
///
/// assert!(matches!(
/// updated.diff_from(original),
/// StyleDiff {
/// foreground: Some(Color::Cyan),
/// background: None,
/// intensity: None,
/// ..
/// }
/// ));
/// ```
pub fn diff_from(self, original: Style) -> StyleDiff {
fn diff<T: PartialEq>(original: T, new: T) -> Option<T> {
if original == new {
None
} else {
Some(new)
}
}
StyleDiff {
foreground: diff(original.foreground, self.foreground),
background: diff(original.background, self.background),
intensity: diff(original.intensity, self.intensity),
}
}
}
impl<T: Restyle + ?Sized> Restyle for &T {
fn apply(&self, style: Style) -> Style {
(**self).apply(style)
}
}
#[cfg(feature = "alloc")]
impl<T: Restyle + ?Sized> Restyle for alloc::boxed::Box<T> {
fn apply(&self, style: Style) -> Style {
(**self).apply(style)
}
}
impl<T: Restyle> Restyle for [T] {
fn apply(&self, mut style: Style) -> Style {
for restyle in self {
style = restyle.apply(style);
}
style
}
}
impl<T: Restyle> Restyle for Option<T> {
fn apply(&self, style: Style) -> Style {
self.as_ref().map_or(style, |s| s.apply(style))
}
}
impl Restyle for StyleDiff {
fn apply(&self, style: Style) -> Style {
(
self.foreground.map(Foreground),
self.background.map(Background),
self.intensity,
)
.apply(style)
}
}
impl Restyle for Style {
fn apply(&self, _style: Style) -> Style {
*self
}
}
impl Restyle for Foreground {
fn apply(&self, style: Style) -> Style {
let &Foreground(foreground) = self;
Style {
foreground,
..style
}
}
}
impl Restyle for Background {
fn apply(&self, style: Style) -> Style {
let &Background(background) = self;
Style {
background,
..style
}
}
}
impl Restyle for Intensity {
fn apply(&self, style: Style) -> Style {
Style {
intensity: *self,
..style
}
}
}
impl Restyle for () {
fn apply(&self, style: Style) -> Style {
style
}
}
impl<T: Restyle, U: Restyle> Restyle for (T, U) {
fn apply(&self, style: Style) -> Style {
style.with(&self.0).with(&self.1)
}
}
impl<T: Restyle, U: Restyle, V: Restyle> Restyle for (T, U, V) {
fn apply(&self, style: Style) -> Style {
style.with(&self.0).with(&self.1).with(&self.2)
}
}