1use crate::style::Style;
22use lattice_theme::{BuiltinElementIds, ElementId, ResolvedTheme};
23
24pub fn syntax_element_id(ids: &BuiltinElementIds, style: Style) -> ElementId {
29 use crate::style::Style as S;
30 match style {
31 S::Default => ids.syntax_default,
32 S::Comment => ids.syntax_comment,
33 S::LineComment => ids.syntax_line_comment,
34 S::String => ids.syntax_string,
35 S::Keyword => ids.syntax_keyword,
36 S::Type => ids.syntax_type,
37 S::Number => ids.syntax_number,
38 S::Function => ids.syntax_function,
39 S::Constant => ids.syntax_constant,
40 S::Variable => ids.syntax_variable,
41 S::Operator => ids.syntax_operator,
42 S::Punctuation => ids.syntax_punctuation,
43 S::Attribute => ids.syntax_attribute,
44 S::Heading1 => ids.syntax_heading_1,
45 S::Heading2 => ids.syntax_heading_2,
46 S::Heading3 => ids.syntax_heading_3,
47 S::Heading4 => ids.syntax_heading_4,
48 S::Heading5 => ids.syntax_heading_5,
49 S::Heading6 => ids.syntax_heading_6,
50 S::Bold => ids.syntax_bold,
51 S::Italic => ids.syntax_italic,
52 S::Link => ids.syntax_link,
53 S::Url => ids.syntax_url,
54 S::MarkupRaw => ids.syntax_markup_raw,
55 S::Markup => ids.syntax_markup,
56 S::DiagnosticError => ids.diagnostic_error,
59 S::DiagnosticWarning => ids.diagnostic_warning,
60 S::DiagnosticInfo => ids.diagnostic_info,
61 S::DiagnosticHint => ids.diagnostic_hint,
62 S::DiffAdd => ids.diff_add_text,
63 S::DiffRemove => ids.diff_remove_text,
64 S::MessagesTimestamp => ids.messages_timestamp,
69 S::MessagesTrace => ids.messages_trace,
70 S::MessagesDebug => ids.messages_debug,
71 S::MessagesInfo => ids.messages_info,
72 S::MessagesWarn => ids.messages_warn,
73 S::MessagesError => ids.messages_error,
74 S::MagitSha => ids.magit_sha,
75 S::MagitBranchCurrent => ids.magit_branch_current,
76 S::MagitRefDecoration => ids.magit_ref_decoration,
77 S::MagitRebaseVerb => ids.magit_rebase_verb,
78 S::MagitAuthor => ids.magit_author,
79 S::HelpKey => ids.help_key,
83 S::HelpCommand => ids.help_command,
84 S::HelpAction => ids.help_action,
85 S::HelpLiteral => ids.help_literal,
86 S::InlayHint => ids.inlay_hint,
89 S::Element(id) => id,
93 }
94}
95
96pub fn resolve_syntax_style(
103 resolved: &ResolvedTheme,
104 ids: &BuiltinElementIds,
105 style: Style,
106) -> lattice_theme::Style {
107 resolved.get(syntax_element_id(ids, style))
108}
109
110#[cfg(test)]
111mod tests {
112 #![allow(clippy::unwrap_used)]
113 use super::*;
114 use lattice_theme::{
115 BuiltinElementIds, Color, InMemoryThemeRegistry, ResolvedTheme, ThemeRegistry,
116 };
117
118 fn defaults() -> (std::sync::Arc<ResolvedTheme>, BuiltinElementIds) {
130 let reg = InMemoryThemeRegistry::with_defaults();
131 let resolved = reg.resolved();
132 let ids = BuiltinElementIds::capture(®);
133 (resolved, ids)
134 }
135
136 #[test]
146 fn a_mode_registered_element_can_style_a_span() {
147 use lattice_theme::{ElementOwner, StyleSpec};
148 let reg = InMemoryThemeRegistry::with_defaults();
149 let id = reg.register(
150 "listing.file.rust".into(),
151 ElementOwner::Mode("directory-listing-mode".into()),
152 StyleSpec::new().fg(Color::Rgb(0xDE, 0xA5, 0x84)),
153 "test element",
154 );
155 let ids = BuiltinElementIds::capture(®);
156
157 assert_eq!(syntax_element_id(&ids, Style::Element(id)), id);
159 let resolved = reg.resolved();
161 let s = resolve_syntax_style(&resolved, &ids, Style::Element(id));
162 assert_eq!(s.fg, Some(Color::Rgb(0xDE, 0xA5, 0x84)));
163 }
164
165 #[test]
169 fn element_styles_fingerprint_distinctly() {
170 let reg = InMemoryThemeRegistry::with_defaults();
171 let a = reg.register(
172 "listing.file.rust".into(),
173 lattice_theme::ElementOwner::Mode("m".into()),
174 lattice_theme::StyleSpec::new(),
175 "a",
176 );
177 let b = reg.register(
178 "listing.file.python".into(),
179 lattice_theme::ElementOwner::Mode("m".into()),
180 lattice_theme::StyleSpec::new(),
181 "b",
182 );
183 assert_ne!(a, b, "precondition: distinct ids");
184 assert_ne!(
185 Style::Element(a).fingerprint(),
186 Style::Element(b).fingerprint()
187 );
188 assert_ne!(
189 Style::Element(a).fingerprint(),
190 Style::Keyword.fingerprint()
191 );
192 assert_eq!(
193 Style::Keyword.fingerprint(),
194 Style::Keyword.fingerprint(),
195 "stable within a process"
196 );
197 }
198
199 #[test]
200 fn resolve_syntax_keyword_carries_catppuccin_mauve_bold() {
201 let (resolved, ids) = defaults();
202 let s = resolve_syntax_style(&resolved, &ids, Style::Keyword);
203 assert_eq!(s.fg, Some(Color::Rgb(0xcb, 0xa6, 0xf7)));
204 assert!(s.modifiers.bold);
205 }
206
207 #[test]
208 fn resolve_syntax_comment_is_overlay0_italic() {
209 let (resolved, ids) = defaults();
210 let s = resolve_syntax_style(&resolved, &ids, Style::Comment);
211 assert_eq!(s.fg, Some(Color::Rgb(0x6c, 0x70, 0x86)));
212 assert!(s.modifiers.italic);
213 let line = resolve_syntax_style(&resolved, &ids, Style::LineComment);
215 assert_eq!(line, s);
216 }
217
218 #[test]
219 fn resolve_syntax_default_uses_text_foreground() {
220 let (resolved, ids) = defaults();
221 let s = resolve_syntax_style(&resolved, &ids, Style::Default);
222 assert_eq!(s.fg, Some(Color::Rgb(0xcd, 0xd6, 0xf4)));
223 }
224
225 #[test]
229 fn resolve_diagnostic_styles_match_severity_elements_and_differ() {
230 use crate::style::Style as S;
231 let (resolved, ids) = defaults();
232 let err = resolve_syntax_style(&resolved, &ids, S::DiagnosticError);
233 let warn = resolve_syntax_style(&resolved, &ids, S::DiagnosticWarning);
234 let info = resolve_syntax_style(&resolved, &ids, S::DiagnosticInfo);
235 let hint = resolve_syntax_style(&resolved, &ids, S::DiagnosticHint);
236 assert_eq!(err, resolved.get(ids.diagnostic_error));
238 assert_eq!(warn, resolved.get(ids.diagnostic_warning));
239 assert!(err.fg.is_some());
241 assert_ne!(err.fg, info.fg);
242 assert_ne!(warn.fg, hint.fg);
243 }
244}