1use nu_ansi_term::{Color, Style};
6use sdml_errors::diagnostics::UseColor;
7use std::fmt::Display;
8use std::sync::OnceLock;
9use std::sync::RwLock;
10
11macro_rules! method {
16 ($name:ident, $el:ident) => {
17 #[inline(always)]
18 fn $name<S>(&self, value: S) -> String
19 where
20 S: AsRef<str>,
21 {
22 self.colorize(LanguageElement::$el, value)
23 }
24 };
25}
26
27#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
36pub enum LanguageElement {
37 Comment,
38 Constant,
39 ConstantDefinition,
40 Embedded,
41 Error,
42 Function,
43 FunctionCall,
44 FunctionDefinition,
45 Keyword,
46 LiteralBoolean,
47 LiteralNumber,
48 LiteralString,
49 LiteralStringSpecial,
50 Operator,
51 Method,
52 MethodDefinition,
53 Module,
54 ModuleDefinition,
55 Property,
56 PropertyDefinition,
57 Punctuation,
58 PunctuationBracket,
59 PunctuationDelimiter,
60 PunctuationSeparator,
61 Type,
62 TypeBuiltin,
63 TypeDefinition,
64 Variable,
65 VariableBuiltin,
66 VariableField,
67 VariableParameter,
68}
69
70pub trait Colorizer {
74 fn colorize<S>(&self, el: LanguageElement, value: S) -> String
78 where
79 S: AsRef<str>;
80
81 method!(comment, Comment);
82 method!(constant, Constant);
83 method!(constant_definition, ConstantDefinition);
84 method!(embedded, Embedded);
85 method!(error, Error);
86 method!(function, Function);
87 method!(function_call, FunctionCall);
88 method!(function_definition, FunctionDefinition);
89 method!(keyword, Keyword);
90 method!(boolean, LiteralBoolean);
91 method!(number, LiteralNumber);
92 method!(string, LiteralString);
93 method!(string_special, LiteralStringSpecial);
94 method!(url, LiteralStringSpecial);
95 method!(operator, Operator);
96 method!(method, Method);
97 method!(method_definition, MethodDefinition);
98 method!(module, Module);
99 method!(module_definition, ModuleDefinition);
100 method!(property, Property);
101 method!(property_definitions, PropertyDefinition);
102 method!(punctuation, Punctuation);
103 method!(bracket, PunctuationBracket);
104 method!(delimiter, PunctuationDelimiter);
105 method!(separator, PunctuationSeparator);
106 method!(type_ref, Type);
107 method!(type_builtin, TypeBuiltin);
108 method!(type_definition, TypeDefinition);
109 method!(variable, Variable);
110 method!(variable_field, VariableField);
111 method!(variable_parameter, VariableParameter);
112}
113
114#[derive(Clone, Copy, Debug, Default, PartialEq, Eq, Hash)]
118pub struct ConsoleColor {}
119
120#[derive(Clone, Copy, Debug, Default, PartialEq, Eq, Hash)]
124pub struct HtmlColor {}
125
126static COLORIZE: OnceLock<RwLock<UseColor>> = OnceLock::new();
131
132pub fn colorize() -> UseColor {
136 *COLORIZE.get_or_init(init_colorize).read().unwrap()
137}
138
139pub fn set_colorize(colorize: UseColor) {
143 *COLORIZE.get_or_init(init_colorize).write().unwrap() = colorize;
144}
145
146fn init_colorize() -> RwLock<UseColor> {
155 RwLock::new(UseColor::from_env())
156}
157
158impl Display for LanguageElement {
163 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
164 write!(
165 f,
166 "{}",
167 match self {
168 LanguageElement::Comment => "comment",
169 LanguageElement::Constant => "constant",
170 LanguageElement::ConstantDefinition => "constant.definition",
171 LanguageElement::Embedded => "embedded",
172 LanguageElement::Error => "error",
173 LanguageElement::Function => "function",
174 LanguageElement::FunctionCall => "function.call",
175 LanguageElement::FunctionDefinition => "function.definition",
176 LanguageElement::Keyword => "keyword",
177 LanguageElement::LiteralBoolean => "boolean",
178 LanguageElement::LiteralNumber => "number",
179 LanguageElement::LiteralString => "string",
180 LanguageElement::LiteralStringSpecial => "string.special",
181 LanguageElement::Operator => "operator",
182 LanguageElement::Method => "method",
183 LanguageElement::MethodDefinition => "method.definition",
184 LanguageElement::Module => "module",
185 LanguageElement::ModuleDefinition => "module.definition",
186 LanguageElement::Property => "property",
187 LanguageElement::PropertyDefinition => "property.definition",
188 LanguageElement::Punctuation => "punctuation",
189 LanguageElement::PunctuationBracket => "punctuation.bracket",
190 LanguageElement::PunctuationDelimiter => "punctuation.delimiter",
191 LanguageElement::PunctuationSeparator => "punctuation.separator",
192 LanguageElement::Type => "type",
193 LanguageElement::TypeBuiltin => "type.builtin",
194 LanguageElement::TypeDefinition => "type.definition",
195 LanguageElement::Variable => "variable",
196 LanguageElement::VariableBuiltin => "variable.builtin",
197 LanguageElement::VariableField => "variable.field",
198 LanguageElement::VariableParameter => "variable.parameter",
199 }
200 )
201 }
202}
203
204impl Colorizer for ConsoleColor {
207 fn colorize<S>(&self, el: LanguageElement, value: S) -> String
208 where
209 S: AsRef<str>,
210 {
211 if colorize().use_color() {
212 self.style(el).paint(value.as_ref()).to_string()
213 } else {
214 value.as_ref().to_string()
215 }
216 }
217}
218
219impl ConsoleColor {
220 pub const fn new() -> Self {
221 Self {}
222 }
223
224 fn style(&self, el: LanguageElement) -> Style {
225 match el {
226 LanguageElement::Comment => Style::new().fg(Color::Fixed(248)).italic(),
227 LanguageElement::Constant => Style::new().fg(Color::Fixed(58)),
229 LanguageElement::ConstantDefinition => Style::new().fg(Color::Fixed(58)).bold(),
230 LanguageElement::Embedded => Style::new().fg(Color::Fixed(248)).italic(),
232 LanguageElement::Error => Style::new().fg(Color::Fixed(9)).underline(),
234 LanguageElement::Function => Style::new().fg(Color::Fixed(26)),
236 LanguageElement::FunctionCall => Style::new().fg(Color::Fixed(26)),
237 LanguageElement::FunctionDefinition => Style::new().fg(Color::Fixed(26)).bold(),
238 LanguageElement::Keyword => Style::new().fg(Color::Fixed(100)),
240 LanguageElement::LiteralBoolean => Style::new().fg(Color::Fixed(58)),
242 LanguageElement::LiteralNumber => Style::new().fg(Color::Fixed(58)),
243 LanguageElement::LiteralString => Style::new().fg(Color::Fixed(70)),
244 LanguageElement::LiteralStringSpecial => Style::new().fg(Color::Fixed(92)),
245 LanguageElement::Operator => Style::new().fg(Color::Fixed(239)).bold(),
247 LanguageElement::Method => Style::new().fg(Color::Fixed(26)),
249 LanguageElement::MethodDefinition => Style::new().fg(Color::Fixed(26)).bold(),
250 LanguageElement::Module => Style::new().fg(Color::Fixed(19)),
252 LanguageElement::ModuleDefinition => Style::new().fg(Color::Fixed(19)).bold(),
253 LanguageElement::Property => Style::new().fg(Color::Fixed(160)),
255 LanguageElement::PropertyDefinition => Style::new().fg(Color::Fixed(160)).bold(),
256 LanguageElement::Punctuation => Style::new().fg(Color::Fixed(239)),
258 LanguageElement::PunctuationBracket => Style::new().fg(Color::Fixed(239)),
259 LanguageElement::PunctuationDelimiter => Style::new().fg(Color::Fixed(239)),
260 LanguageElement::PunctuationSeparator => Style::new().fg(Color::Fixed(239)),
261 LanguageElement::Type => Style::new().fg(Color::Fixed(27)),
263 LanguageElement::TypeBuiltin => Style::new().fg(Color::Fixed(21)),
264 LanguageElement::TypeDefinition => Style::new().fg(Color::Fixed(27)).bold(),
265 LanguageElement::Variable => Style::new().fg(Color::Fixed(67)),
267 LanguageElement::VariableBuiltin => Style::new().fg(Color::Fixed(67)),
268 LanguageElement::VariableField => Style::new().fg(Color::Fixed(67)),
269 LanguageElement::VariableParameter => Style::new().fg(Color::Fixed(67)),
270 }
271 }
272}
273
274impl Colorizer for HtmlColor {
277 fn colorize<S>(&self, el: LanguageElement, value: S) -> String
278 where
279 S: AsRef<str>,
280 {
281 if colorize().use_color() {
282 format!(
283 "<span class=\"{}\">{}</span>",
284 el.to_string().replace('.', "-"),
285 value.as_ref()
286 )
287 } else {
288 value.as_ref().to_string()
289 }
290 }
291}
292
293pub mod rdf;
298
299pub mod sdml;