blob: 43736aae84d2226aab2af262a5b851e10c0833b9 [file] [log] [blame] [edit]
// Code based on [https://github.com/defuz/sublimate/blob/master/src/core/syntax/scope.rs](https://github.com/defuz/sublimate/blob/master/src/core/syntax/scope.rs)
// released under the MIT license by @defuz
use bitflags::bitflags;
use serde_derive::{Deserialize, Serialize};
/// Foreground and background colors, with font style
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Serialize, Deserialize)]
pub struct Style {
/// Foreground color
pub foreground: Color,
/// Background color
pub background: Color,
/// Style of the font
pub font_style: FontStyle,
}
/// A change to a [`Style`] applied incrementally by a theme rule
///
/// Fields left empty (as `None`) will not modify the corresponding field on a `Style`
///
/// [`Style`]: struct.Style.html
#[derive(Debug, Default, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
pub struct StyleModifier {
/// Foreground color
pub foreground: Option<Color>,
/// Background color
pub background: Option<Color>,
/// Style of the font
pub font_style: Option<FontStyle>,
}
/// RGBA color, directly from the theme
///
/// Because these numbers come directly from the theme, you might have to do your own color space
/// conversion if you're outputting a different color space from the theme. This can be a problem
/// because some Sublime themes use sRGB and some don't. This is specified in an attribute syntect
/// doesn't parse yet.
#[derive(Clone, Copy, PartialEq, Eq, Hash, Serialize, Deserialize)]
pub struct Color {
/// Red component
pub r: u8,
/// Green component
pub g: u8,
/// Blue component
pub b: u8,
/// Alpha (transparency) component
pub a: u8,
}
// More compact alternate debug representation by not using a separate line for each color field,
// also adapts the default debug representation to match.
impl std::fmt::Debug for Color {
fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
let Color { r, g, b, a } = self;
if f.alternate() {
// when formatted with "{:#?}"
write!(
f,
"Color {{ r/g/b/a: {: >3}/{: >3}/{: >3}/{: >3} }}",
r, g, b, a
)
} else {
// when formatted with "{:?}"
write!(f, "Color {{ r/g/b/a: {}/{}/{}/{} }}", r, g, b, a)
}
}
}
bitflags! {
/// The color-independent styling of a font - i.e. bold, italicized, and/or underlined
#[derive(Serialize, Deserialize)]
pub struct FontStyle: u8 {
/// Bold font style
const BOLD = 1;
/// Underline font style
const UNDERLINE = 2;
/// Italic font style
const ITALIC = 4;
}
}
impl Color {
/// The color black (`#000000`)
pub const BLACK: Color = Color {
r: 0x00,
g: 0x00,
b: 0x00,
a: 0xFF,
};
/// The color white (`#FFFFFF`)
pub const WHITE: Color = Color {
r: 0xFF,
g: 0xFF,
b: 0xFF,
a: 0xFF,
};
}
impl Style {
/// Applies a change to this style, yielding a new changed style
pub fn apply(&self, modifier: StyleModifier) -> Style {
Style {
foreground: modifier.foreground.unwrap_or(self.foreground),
background: modifier.background.unwrap_or(self.background),
font_style: modifier.font_style.unwrap_or(self.font_style),
}
}
}
impl Default for Style {
fn default() -> Style {
Style {
foreground: Color::BLACK,
background: Color::WHITE,
font_style: FontStyle::empty(),
}
}
}
impl StyleModifier {
/// Applies the other modifier to this one, creating a new modifier.
///
/// Values in `other` are preferred.
pub fn apply(&self, other: StyleModifier) -> StyleModifier {
StyleModifier {
foreground: other.foreground.or(self.foreground),
background: other.background.or(self.background),
font_style: other.font_style.or(self.font_style),
}
}
}
impl Default for FontStyle {
fn default() -> FontStyle {
FontStyle::empty()
}
}