bezel-theme 0.2.24

Design tokens for gpui — an environment-driven theme with designed light and dark palettes
Documentation
use gpui::Hsla;

use crate::color;

/// Paint-only syntax colors. The hues follow the Git history graph's lane
/// palette (indigo, pink, emerald, amber, red, neutral), while light-mode
/// variants are darkened enough to remain readable as text on white.
#[derive(Debug, Clone)]
pub struct SyntaxPalette {
    pub comment: Hsla,
    pub keyword: Hsla,
    pub string: Hsla,
    pub string_special: Hsla,
    pub escape: Hsla,
    pub number: Hsla,
    pub boolean: Hsla,
    pub type_name: Hsla,
    pub type_builtin: Hsla,
    pub constructor: Hsla,
    pub function: Hsla,
    pub function_builtin: Hsla,
    pub macro_name: Hsla,
    pub property: Hsla,
    pub constant: Hsla,
    pub variable: Hsla,
    pub variable_special: Hsla,
    pub parameter: Hsla,
    pub operator: Hsla,
    pub punctuation: Hsla,
    pub tag: Hsla,
    pub attribute: Hsla,
    pub label: Hsla,
    pub invalid: Hsla,
}

/// The token category a highlighter paints with, mirroring [`SyntaxPalette`]
/// field-for-field so classification can name a kind without knowing its color.
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum HighlightKind {
    Comment,
    Keyword,
    String,
    StringSpecial,
    Escape,
    Number,
    Boolean,
    TypeName,
    TypeBuiltin,
    Constructor,
    Function,
    FunctionBuiltin,
    MacroName,
    Property,
    Constant,
    Variable,
    VariableSpecial,
    Parameter,
    Operator,
    Punctuation,
    Tag,
    Attribute,
    Label,
    Invalid,
}

impl HighlightKind {
    pub const ALL: [Self; 24] = [
        Self::Comment,
        Self::Keyword,
        Self::String,
        Self::StringSpecial,
        Self::Escape,
        Self::Number,
        Self::Boolean,
        Self::TypeName,
        Self::TypeBuiltin,
        Self::Constructor,
        Self::Function,
        Self::FunctionBuiltin,
        Self::MacroName,
        Self::Property,
        Self::Constant,
        Self::Variable,
        Self::VariableSpecial,
        Self::Parameter,
        Self::Operator,
        Self::Punctuation,
        Self::Tag,
        Self::Attribute,
        Self::Label,
        Self::Invalid,
    ];

    /// The kind as a kebab-case word: `string-special`. Stable — a stylesheet
    /// names kinds by it.
    pub fn name(self) -> &'static str {
        match self {
            Self::Comment => "comment",
            Self::Keyword => "keyword",
            Self::String => "string",
            Self::StringSpecial => "string-special",
            Self::Escape => "escape",
            Self::Number => "number",
            Self::Boolean => "boolean",
            Self::TypeName => "type",
            Self::TypeBuiltin => "type-builtin",
            Self::Constructor => "constructor",
            Self::Function => "function",
            Self::FunctionBuiltin => "function-builtin",
            Self::MacroName => "macro",
            Self::Property => "property",
            Self::Constant => "constant",
            Self::Variable => "variable",
            Self::VariableSpecial => "variable-special",
            Self::Parameter => "parameter",
            Self::Operator => "operator",
            Self::Punctuation => "punctuation",
            Self::Tag => "tag",
            Self::Attribute => "attribute",
            Self::Label => "label",
            Self::Invalid => "invalid",
        }
    }
}

impl SyntaxPalette {
    /// The palette color for a token kind.
    pub fn color(&self, kind: HighlightKind) -> Hsla {
        match kind {
            HighlightKind::Comment => self.comment,
            HighlightKind::Keyword => self.keyword,
            HighlightKind::String => self.string,
            HighlightKind::StringSpecial => self.string_special,
            HighlightKind::Escape => self.escape,
            HighlightKind::Number => self.number,
            HighlightKind::Boolean => self.boolean,
            HighlightKind::TypeName => self.type_name,
            HighlightKind::TypeBuiltin => self.type_builtin,
            HighlightKind::Constructor => self.constructor,
            HighlightKind::Function => self.function,
            HighlightKind::FunctionBuiltin => self.function_builtin,
            HighlightKind::MacroName => self.macro_name,
            HighlightKind::Property => self.property,
            HighlightKind::Constant => self.constant,
            HighlightKind::Variable => self.variable,
            HighlightKind::VariableSpecial => self.variable_special,
            HighlightKind::Parameter => self.parameter,
            HighlightKind::Operator => self.operator,
            HighlightKind::Punctuation => self.punctuation,
            HighlightKind::Tag => self.tag,
            HighlightKind::Attribute => self.attribute,
            HighlightKind::Label => self.label,
            HighlightKind::Invalid => self.invalid,
        }
    }

    pub(crate) fn dark(text: Hsla, comment: Hsla, danger: Hsla) -> Self {
        // Same sources and 72% saturation treatment as history::graph_color.
        let indigo = git_graph_tone(color::oklch(0.673, 0.182, 276.935));
        let pink = git_graph_tone(color::oklch(0.718, 0.202, 349.761));
        let emerald = git_graph_tone(color::oklch(0.765, 0.177, 163.223));
        let amber = git_graph_tone(color::oklch(0.828, 0.189, 84.429));
        let red = git_graph_tone(danger);
        Self {
            comment,
            keyword: indigo,
            string: emerald,
            string_special: pink,
            escape: pink,
            number: amber,
            boolean: amber,
            type_name: amber,
            type_builtin: emerald,
            constructor: amber,
            function: indigo,
            function_builtin: pink,
            macro_name: pink,
            property: amber,
            constant: emerald,
            variable: text,
            variable_special: pink,
            parameter: text,
            operator: text,
            punctuation: text,
            tag: pink,
            attribute: amber,
            label: amber,
            invalid: red,
        }
    }

    pub(crate) fn light(text: Hsla, comment: Hsla, danger: Hsla) -> Self {
        // Match the light graph's hue families at text-safe lightness.
        let indigo = git_graph_tone(color::oklch(0.47, 0.20, 276.966));
        let pink = git_graph_tone(color::oklch(0.47, 0.17, 0.584));
        let emerald = git_graph_tone(color::oklch(0.46, 0.11, 163.225));
        let amber = git_graph_tone(color::oklch(0.47, 0.12, 48.998));
        let red = git_graph_tone(danger);
        Self {
            comment,
            keyword: indigo,
            string: emerald,
            string_special: pink,
            escape: pink,
            number: amber,
            boolean: amber,
            type_name: amber,
            type_builtin: emerald,
            constructor: amber,
            function: indigo,
            function_builtin: pink,
            macro_name: pink,
            property: amber,
            constant: emerald,
            variable: text,
            variable_special: pink,
            parameter: text,
            operator: text,
            punctuation: text,
            tag: pink,
            attribute: amber,
            label: amber,
            invalid: red,
        }
    }
}

/// Git history intentionally softens lane saturation so the graph remains
/// colorful without competing with content. Syntax uses the same treatment.
fn git_graph_tone(mut color: Hsla) -> Hsla {
    color.s *= 0.72;
    color
}