1#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
28pub enum ThemeSlot {
29 Keyword,
30 Function,
31 String,
32 Comment,
33 Type,
34 Variable,
35 Constant,
36 Number,
37 Operator,
38 Punctuation,
39 Property,
40 Attribute,
41 Tag,
42 Macro,
43 Label,
44 Namespace,
45 Constructor,
46 Title,
48 Strong,
50 Emphasis,
52 Link,
54 Literal,
56 Strikethrough,
58 DiffAdd,
60 DiffDelete,
62 Embedded,
64 Error,
66 None,
68}
69
70impl ThemeSlot {
71 pub fn tag(self) -> Option<&'static str> {
74 match self {
75 ThemeSlot::Keyword => Some("k"),
76 ThemeSlot::Function => Some("f"),
77 ThemeSlot::String => Some("s"),
78 ThemeSlot::Comment => Some("c"),
79 ThemeSlot::Type => Some("t"),
80 ThemeSlot::Variable => Some("v"),
81 ThemeSlot::Constant => Some("co"),
82 ThemeSlot::Number => Some("n"),
83 ThemeSlot::Operator => Some("o"),
84 ThemeSlot::Punctuation => Some("p"),
85 ThemeSlot::Property => Some("pr"),
86 ThemeSlot::Attribute => Some("at"),
87 ThemeSlot::Tag => Some("tg"),
88 ThemeSlot::Macro => Some("m"),
89 ThemeSlot::Label => Some("l"),
90 ThemeSlot::Namespace => Some("ns"),
91 ThemeSlot::Constructor => Some("cr"),
92 ThemeSlot::Title => Some("tt"),
94 ThemeSlot::Strong => Some("st"),
96 ThemeSlot::Emphasis => Some("em"),
98 ThemeSlot::Link => Some("tu"),
100 ThemeSlot::Literal => Some("tl"),
102 ThemeSlot::Strikethrough => Some("tx"),
104 ThemeSlot::DiffAdd => Some("da"),
106 ThemeSlot::DiffDelete => Some("dd"),
108 ThemeSlot::Embedded => Some("eb"),
110 ThemeSlot::Error => Some("er"),
112 ThemeSlot::None => None,
114 }
115 }
116
117 pub fn name(self) -> Option<&'static str> {
120 match self {
121 ThemeSlot::Keyword => Some("keyword"),
122 ThemeSlot::Function => Some("function"),
123 ThemeSlot::String => Some("string"),
124 ThemeSlot::Comment => Some("comment"),
125 ThemeSlot::Type => Some("type"),
126 ThemeSlot::Variable => Some("variable"),
127 ThemeSlot::Constant => Some("constant"),
128 ThemeSlot::Number => Some("number"),
129 ThemeSlot::Operator => Some("operator"),
130 ThemeSlot::Punctuation => Some("punctuation"),
131 ThemeSlot::Property => Some("property"),
132 ThemeSlot::Attribute => Some("attribute"),
133 ThemeSlot::Tag => Some("tag"),
134 ThemeSlot::Macro => Some("macro"),
135 ThemeSlot::Label => Some("label"),
136 ThemeSlot::Namespace => Some("namespace"),
137 ThemeSlot::Constructor => Some("constructor"),
138 ThemeSlot::Title => Some("title"),
139 ThemeSlot::Strong => Some("strong"),
140 ThemeSlot::Emphasis => Some("emphasis"),
141 ThemeSlot::Link => Some("link"),
142 ThemeSlot::Literal => Some("literal"),
143 ThemeSlot::Strikethrough => Some("strikethrough"),
144 ThemeSlot::DiffAdd => Some("diff-add"),
145 ThemeSlot::DiffDelete => Some("diff-delete"),
146 ThemeSlot::Embedded => Some("embedded"),
147 ThemeSlot::Error => Some("error"),
148 ThemeSlot::None => None,
149 }
150 }
151}
152
153pub fn slot_to_highlight_index(slot: ThemeSlot) -> Option<usize> {
158 match slot {
159 ThemeSlot::Keyword => HIGHLIGHTS.iter().position(|h| h.name == "keyword"),
160 ThemeSlot::Function => HIGHLIGHTS.iter().position(|h| h.name == "function"),
161 ThemeSlot::String => HIGHLIGHTS.iter().position(|h| h.name == "string"),
162 ThemeSlot::Comment => HIGHLIGHTS.iter().position(|h| h.name == "comment"),
163 ThemeSlot::Type => HIGHLIGHTS.iter().position(|h| h.name == "type"),
164 ThemeSlot::Variable => HIGHLIGHTS.iter().position(|h| h.name == "variable"),
165 ThemeSlot::Constant => HIGHLIGHTS.iter().position(|h| h.name == "constant"),
166 ThemeSlot::Number => HIGHLIGHTS.iter().position(|h| h.name == "number"),
167 ThemeSlot::Operator => HIGHLIGHTS.iter().position(|h| h.name == "operator"),
168 ThemeSlot::Punctuation => HIGHLIGHTS.iter().position(|h| h.name == "punctuation"),
169 ThemeSlot::Property => HIGHLIGHTS.iter().position(|h| h.name == "property"),
170 ThemeSlot::Attribute => HIGHLIGHTS.iter().position(|h| h.name == "attribute"),
171 ThemeSlot::Tag => HIGHLIGHTS.iter().position(|h| h.name == "tag"),
172 ThemeSlot::Macro => HIGHLIGHTS.iter().position(|h| h.name == "macro"),
173 ThemeSlot::Label => HIGHLIGHTS.iter().position(|h| h.name == "label"),
174 ThemeSlot::Namespace => HIGHLIGHTS.iter().position(|h| h.name == "namespace"),
175 ThemeSlot::Constructor => HIGHLIGHTS.iter().position(|h| h.name == "constructor"),
176 ThemeSlot::Title => HIGHLIGHTS
177 .iter()
178 .position(|h| h.name == "text.title" || h.name == "markup.heading"),
179 ThemeSlot::Strong => HIGHLIGHTS
180 .iter()
181 .position(|h| h.name == "text.strong" || h.name == "markup.bold"),
182 ThemeSlot::Emphasis => HIGHLIGHTS
183 .iter()
184 .position(|h| h.name == "text.emphasis" || h.name == "markup.italic"),
185 ThemeSlot::Link => HIGHLIGHTS
186 .iter()
187 .position(|h| h.name == "text.uri" || h.name == "text.reference"),
188 ThemeSlot::Literal => HIGHLIGHTS.iter().position(|h| h.name == "text.literal"),
189 ThemeSlot::Strikethrough => HIGHLIGHTS
190 .iter()
191 .position(|h| h.name == "text.strikethrough"),
192 ThemeSlot::DiffAdd => HIGHLIGHTS.iter().position(|h| h.name == "diff.addition"),
193 ThemeSlot::DiffDelete => HIGHLIGHTS.iter().position(|h| h.name == "diff.deletion"),
194 ThemeSlot::Embedded => HIGHLIGHTS.iter().position(|h| h.name == "embedded"),
195 ThemeSlot::Error => HIGHLIGHTS.iter().position(|h| h.name == "error"),
196 ThemeSlot::None => None,
197 }
198}
199
200pub fn capture_to_slot(capture: &str) -> ThemeSlot {
210 let capture = capture.strip_prefix('@').unwrap_or(capture);
212
213 match capture {
214 "keyword" | "keyword.conditional" | "keyword.coroutine" | "keyword.debug"
216 | "keyword.exception" | "keyword.function" | "keyword.import" | "keyword.operator"
217 | "keyword.repeat" | "keyword.return" | "keyword.type" | "keyword.modifier"
218 | "keyword.directive" | "keyword.storage" | "keyword.control"
219 | "keyword.control.conditional" | "keyword.control.repeat" | "keyword.control.import"
220 | "keyword.control.return" | "keyword.control.exception"
221 | "include" | "conditional" | "repeat" | "exception" | "storageclass" | "preproc"
223 | "define" | "structure" => ThemeSlot::Keyword,
224
225 "function" | "function.builtin" | "function.method" | "function.definition"
227 | "function.call" | "function.special" | "method" | "method.call" => ThemeSlot::Function,
228
229 "string" | "string.special" | "string.special.symbol" | "string.special.path"
231 | "string.special.url" | "string.escape" | "string.regexp" | "string.regex"
232 | "character" | "character.special" | "escape" => ThemeSlot::String,
233
234 "comment" | "comment.documentation" | "comment.line" | "comment.block"
236 | "comment.error" | "comment.warning" | "comment.note" | "comment.todo" => {
237 ThemeSlot::Comment
238 }
239
240 "type" | "type.builtin" | "type.qualifier" | "type.definition" | "type.enum"
242 | "type.enum.variant" | "type.parameter" => ThemeSlot::Type,
243
244 "variable" | "variable.builtin" | "variable.parameter" | "variable.member"
246 | "variable.other" | "variable.other.member" | "parameter" | "field" => {
247 ThemeSlot::Variable
248 }
249
250 "constant" | "constant.builtin" | "constant.builtin.boolean" | "boolean" => {
252 ThemeSlot::Constant
253 }
254
255 "number" | "constant.numeric" | "float" | "number.float" => ThemeSlot::Number,
257
258 "operator" => ThemeSlot::Operator,
260
261 "punctuation" | "punctuation.bracket" | "punctuation.delimiter" | "punctuation.special" => {
263 ThemeSlot::Punctuation
264 }
265
266 "property" | "property.builtin" => ThemeSlot::Property,
268
269 "attribute" | "attribute.builtin" => ThemeSlot::Attribute,
271
272 "tag" | "tag.delimiter" | "tag.error" | "tag.attribute" | "tag.builtin" => ThemeSlot::Tag,
274
275 "macro" | "function.macro" | "preproc.macro" => ThemeSlot::Macro,
277
278 "label" => ThemeSlot::Label,
280
281 "namespace" | "module" => ThemeSlot::Namespace,
283
284 "constructor" | "constructor.builtin" => ThemeSlot::Constructor,
286
287 "text.title" | "markup.heading" | "markup.heading.1" | "markup.heading.2"
289 | "markup.heading.3" | "markup.heading.4" | "markup.heading.5" | "markup.heading.6" => {
290 ThemeSlot::Title
291 }
292
293 "text.strong" | "markup.bold" => ThemeSlot::Strong,
295
296 "text.emphasis" | "markup.italic" => ThemeSlot::Emphasis,
298
299 "text.uri" | "text.reference" | "markup.link" | "markup.link.url" | "markup.link.text"
301 | "markup.link.label" => ThemeSlot::Link,
302
303 "text.literal" | "markup.raw" | "markup.raw.block" | "markup.raw.inline"
305 | "markup.inline" => ThemeSlot::Literal,
306
307 "text.strikethrough" | "markup.strikethrough" => ThemeSlot::Strikethrough,
309
310 "markup.list" | "markup.list.checked" | "markup.list.unchecked"
312 | "markup.list.numbered" | "markup.list.unnumbered" | "markup.quote" => {
313 ThemeSlot::Punctuation
314 }
315
316 "diff.addition" | "diff.plus" | "diff.delta" => ThemeSlot::DiffAdd,
318 "diff.deletion" | "diff.minus" => ThemeSlot::DiffDelete,
319
320 "embedded" => ThemeSlot::Embedded,
322
323 "error" => ThemeSlot::Error,
325
326 "none" | "nospell" | "spell" | "text" | "markup" => ThemeSlot::None,
328
329 other => {
331 if other.starts_with("keyword") {
332 ThemeSlot::Keyword
333 } else if other.starts_with("function") || other.starts_with("method") {
334 ThemeSlot::Function
335 } else if other.starts_with("string") || other.starts_with("character") {
336 ThemeSlot::String
337 } else if other.starts_with("comment") {
338 ThemeSlot::Comment
339 } else if other.starts_with("type") {
340 ThemeSlot::Type
341 } else if other.starts_with("variable") || other.starts_with("parameter") {
342 ThemeSlot::Variable
343 } else if other.starts_with("constant") {
344 ThemeSlot::Constant
345 } else if other.starts_with("punctuation") {
346 ThemeSlot::Punctuation
347 } else if other.starts_with("tag") {
348 ThemeSlot::Tag
349 } else if other.starts_with("markup.heading") || other.starts_with("text.title") {
350 ThemeSlot::Title
351 } else if other.starts_with("markup") || other.starts_with("text") {
352 ThemeSlot::None
354 } else {
355 ThemeSlot::None
357 }
358 }
359 }
360}
361
362pub struct HighlightDef {
367 pub name: &'static str,
369 pub tag: &'static str,
372 pub parent_tag: &'static str,
375 pub aliases: &'static [&'static str],
377}
378
379pub const HIGHLIGHTS: &[HighlightDef] = &[
382 HighlightDef {
384 name: "attribute",
385 tag: "at",
386 parent_tag: "",
387 aliases: &[],
388 },
389 HighlightDef {
390 name: "constant",
391 tag: "co",
392 parent_tag: "",
393 aliases: &[],
394 },
395 HighlightDef {
396 name: "constant.builtin",
397 tag: "cb",
398 parent_tag: "co",
399 aliases: &["constant.builtin.boolean"],
400 },
401 HighlightDef {
402 name: "constructor",
403 tag: "cr",
404 parent_tag: "",
405 aliases: &[],
406 },
407 HighlightDef {
408 name: "function.builtin",
409 tag: "fb",
410 parent_tag: "f",
411 aliases: &[],
412 },
413 HighlightDef {
414 name: "function",
415 tag: "f",
416 parent_tag: "",
417 aliases: &[],
418 },
419 HighlightDef {
420 name: "function.method",
421 tag: "fm",
422 parent_tag: "f",
423 aliases: &[],
424 },
425 HighlightDef {
426 name: "keyword",
427 tag: "k",
428 parent_tag: "",
429 aliases: &[],
430 },
431 HighlightDef {
432 name: "keyword.conditional",
433 tag: "kc",
434 parent_tag: "k",
435 aliases: &[],
436 },
437 HighlightDef {
438 name: "keyword.coroutine",
439 tag: "ko",
440 parent_tag: "k",
441 aliases: &[],
442 },
443 HighlightDef {
444 name: "keyword.debug",
445 tag: "kd",
446 parent_tag: "k",
447 aliases: &[],
448 },
449 HighlightDef {
450 name: "keyword.exception",
451 tag: "ke",
452 parent_tag: "k",
453 aliases: &[],
454 },
455 HighlightDef {
456 name: "keyword.function",
457 tag: "kf",
458 parent_tag: "k",
459 aliases: &[],
460 },
461 HighlightDef {
462 name: "keyword.import",
463 tag: "ki",
464 parent_tag: "k",
465 aliases: &[],
466 },
467 HighlightDef {
468 name: "keyword.operator",
469 tag: "kp",
470 parent_tag: "k",
471 aliases: &[],
472 },
473 HighlightDef {
474 name: "keyword.repeat",
475 tag: "kr",
476 parent_tag: "k",
477 aliases: &[],
478 },
479 HighlightDef {
480 name: "keyword.return",
481 tag: "kt",
482 parent_tag: "k",
483 aliases: &[],
484 },
485 HighlightDef {
486 name: "keyword.type",
487 tag: "ky",
488 parent_tag: "k",
489 aliases: &[],
490 },
491 HighlightDef {
492 name: "operator",
493 tag: "o",
494 parent_tag: "",
495 aliases: &[],
496 },
497 HighlightDef {
498 name: "property",
499 tag: "pr",
500 parent_tag: "",
501 aliases: &[],
502 },
503 HighlightDef {
504 name: "punctuation",
505 tag: "p",
506 parent_tag: "",
507 aliases: &[],
508 },
509 HighlightDef {
510 name: "punctuation.bracket",
511 tag: "pb",
512 parent_tag: "p",
513 aliases: &[],
514 },
515 HighlightDef {
516 name: "punctuation.delimiter",
517 tag: "pd",
518 parent_tag: "p",
519 aliases: &[],
520 },
521 HighlightDef {
522 name: "punctuation.special",
523 tag: "ps",
524 parent_tag: "p",
525 aliases: &[],
526 },
527 HighlightDef {
528 name: "string",
529 tag: "s",
530 parent_tag: "",
531 aliases: &[],
532 },
533 HighlightDef {
534 name: "string.special",
535 tag: "ss",
536 parent_tag: "s",
537 aliases: &["string.special.symbol", "string.special.path"],
538 },
539 HighlightDef {
540 name: "tag",
541 tag: "tg",
542 parent_tag: "",
543 aliases: &[],
544 },
545 HighlightDef {
546 name: "tag.delimiter",
547 tag: "td",
548 parent_tag: "tg",
549 aliases: &[],
550 },
551 HighlightDef {
552 name: "tag.error",
553 tag: "te",
554 parent_tag: "tg",
555 aliases: &[],
556 },
557 HighlightDef {
558 name: "type",
559 tag: "t",
560 parent_tag: "",
561 aliases: &[],
562 },
563 HighlightDef {
564 name: "type.builtin",
565 tag: "tb",
566 parent_tag: "t",
567 aliases: &[],
568 },
569 HighlightDef {
570 name: "type.qualifier",
571 tag: "tq",
572 parent_tag: "t",
573 aliases: &[],
574 },
575 HighlightDef {
576 name: "variable",
577 tag: "v",
578 parent_tag: "",
579 aliases: &[],
580 },
581 HighlightDef {
582 name: "variable.builtin",
583 tag: "vb",
584 parent_tag: "v",
585 aliases: &[],
586 },
587 HighlightDef {
588 name: "variable.parameter",
589 tag: "vp",
590 parent_tag: "v",
591 aliases: &["parameter"],
592 },
593 HighlightDef {
594 name: "comment",
595 tag: "c",
596 parent_tag: "",
597 aliases: &[],
598 },
599 HighlightDef {
600 name: "comment.documentation",
601 tag: "cd",
602 parent_tag: "c",
603 aliases: &[],
604 },
605 HighlightDef {
606 name: "macro",
607 tag: "m",
608 parent_tag: "",
609 aliases: &[],
610 },
611 HighlightDef {
612 name: "label",
613 tag: "l",
614 parent_tag: "",
615 aliases: &[],
616 },
617 HighlightDef {
618 name: "diff.addition",
619 tag: "da",
620 parent_tag: "",
621 aliases: &["diff.plus", "diff.delta"],
622 },
623 HighlightDef {
624 name: "diff.deletion",
625 tag: "dd",
626 parent_tag: "",
627 aliases: &["diff.minus"],
628 },
629 HighlightDef {
630 name: "number",
631 tag: "n",
632 parent_tag: "",
633 aliases: &["constant.numeric"],
634 },
635 HighlightDef {
636 name: "text.literal",
637 tag: "tl",
638 parent_tag: "",
639 aliases: &["markup.raw"],
640 },
641 HighlightDef {
642 name: "text.emphasis",
643 tag: "em",
644 parent_tag: "",
645 aliases: &["markup.italic"],
646 },
647 HighlightDef {
648 name: "text.strong",
649 tag: "st",
650 parent_tag: "",
651 aliases: &["markup.bold"],
652 },
653 HighlightDef {
654 name: "text.uri",
655 tag: "tu",
656 parent_tag: "",
657 aliases: &["markup.link.url"],
658 },
659 HighlightDef {
660 name: "text.reference",
661 tag: "tr",
662 parent_tag: "",
663 aliases: &["markup.link.text"],
664 },
665 HighlightDef {
666 name: "string.escape",
667 tag: "se",
668 parent_tag: "s",
669 aliases: &["escape"],
670 },
671 HighlightDef {
672 name: "text.title",
673 tag: "tt",
674 parent_tag: "",
675 aliases: &["markup.heading"],
676 },
677 HighlightDef {
678 name: "text.strikethrough",
679 tag: "tx",
680 parent_tag: "",
681 aliases: &["markup.strikethrough"],
682 },
683 HighlightDef {
684 name: "spell",
685 tag: "sp",
686 parent_tag: "",
687 aliases: &[],
688 },
689 HighlightDef {
690 name: "embedded",
691 tag: "eb",
692 parent_tag: "",
693 aliases: &[],
694 },
695 HighlightDef {
696 name: "error",
697 tag: "er",
698 parent_tag: "",
699 aliases: &[],
700 },
701 HighlightDef {
702 name: "namespace",
703 tag: "ns",
704 parent_tag: "",
705 aliases: &["module"],
706 },
707 HighlightDef {
709 name: "include",
710 tag: "in",
711 parent_tag: "k",
712 aliases: &[],
713 },
714 HighlightDef {
715 name: "storageclass",
716 tag: "sc",
717 parent_tag: "k",
718 aliases: &[],
719 },
720 HighlightDef {
721 name: "repeat",
722 tag: "rp",
723 parent_tag: "k",
724 aliases: &[],
725 },
726 HighlightDef {
727 name: "conditional",
728 tag: "cn",
729 parent_tag: "k",
730 aliases: &[],
731 },
732 HighlightDef {
733 name: "exception",
734 tag: "ex",
735 parent_tag: "k",
736 aliases: &[],
737 },
738 HighlightDef {
739 name: "preproc",
740 tag: "pp",
741 parent_tag: "k",
742 aliases: &[],
743 },
744 HighlightDef {
745 name: "none",
746 tag: "",
747 parent_tag: "",
748 aliases: &[],
749 }, HighlightDef {
751 name: "character",
752 tag: "ch",
753 parent_tag: "s",
754 aliases: &[],
755 },
756 HighlightDef {
757 name: "character.special",
758 tag: "cs",
759 parent_tag: "s",
760 aliases: &[],
761 },
762 HighlightDef {
763 name: "variable.member",
764 tag: "vm",
765 parent_tag: "v",
766 aliases: &[],
767 },
768 HighlightDef {
769 name: "function.definition",
770 tag: "fd",
771 parent_tag: "f",
772 aliases: &[],
773 },
774 HighlightDef {
775 name: "type.definition",
776 tag: "tf",
777 parent_tag: "t",
778 aliases: &[],
779 },
780 HighlightDef {
781 name: "function.call",
782 tag: "fc",
783 parent_tag: "f",
784 aliases: &[],
785 },
786 HighlightDef {
787 name: "keyword.modifier",
788 tag: "km",
789 parent_tag: "k",
790 aliases: &[],
791 },
792 HighlightDef {
793 name: "keyword.directive",
794 tag: "dr",
795 parent_tag: "k",
796 aliases: &[],
797 },
798 HighlightDef {
799 name: "string.regexp",
800 tag: "rx",
801 parent_tag: "s",
802 aliases: &["string.regex"],
803 },
804 HighlightDef {
805 name: "nospell",
806 tag: "",
807 parent_tag: "",
808 aliases: &[],
809 }, HighlightDef {
811 name: "float",
812 tag: "n",
813 parent_tag: "",
814 aliases: &[],
815 }, HighlightDef {
817 name: "boolean",
818 tag: "cb",
819 parent_tag: "",
820 aliases: &[],
821 }, ];
823
824pub const fn names() -> [&'static str; HIGHLIGHTS.len()] {
826 let mut names = [""; HIGHLIGHTS.len()];
827 let mut i = 0;
828 while i < HIGHLIGHTS.len() {
829 names[i] = HIGHLIGHTS[i].name;
830 i += 1;
831 }
832 names
833}
834
835pub const COUNT: usize = HIGHLIGHTS.len();
837
838#[inline]
841pub fn tag(index: usize) -> Option<&'static str> {
842 HIGHLIGHTS
843 .get(index)
844 .map(|h| h.tag)
845 .filter(|t| !t.is_empty())
846}
847
848#[inline]
850pub fn prefixed_tag(index: usize) -> Option<String> {
851 tag(index).map(|t| format!("a-{t}"))
852}
853
854#[inline]
856pub fn parent_tag(index: usize) -> Option<&'static str> {
857 HIGHLIGHTS
858 .get(index)
859 .map(|h| h.parent_tag)
860 .filter(|t| !t.is_empty())
861}
862
863pub fn css_inheritance_rules() -> String {
866 use std::collections::HashMap;
867 use std::fmt::Write;
868
869 let mut parent_children: HashMap<&str, Vec<&str>> = HashMap::new();
871 for def in HIGHLIGHTS {
872 if !def.parent_tag.is_empty() && !def.tag.is_empty() {
873 parent_children
874 .entry(def.parent_tag)
875 .or_default()
876 .push(def.tag);
877 }
878 }
879
880 let mut css = String::new();
881 for (_parent, children) in parent_children {
882 if children.is_empty() {
883 continue;
884 }
885 let selectors: Vec<String> = children.iter().map(|c| format!("a-{c}")).collect();
887 writeln!(css, "{} {{ color: inherit; }}", selectors.join(", ")).unwrap();
888 }
889 css
890}
891
892pub fn tag_for_capture(capture: &str) -> Option<&'static str> {
914 capture_to_slot(capture).tag()
915}
916
917pub fn tag_to_name(tag: &str) -> Option<&'static str> {
931 match tag {
932 "k" => Some("keyword"),
933 "f" => Some("function"),
934 "s" => Some("string"),
935 "c" => Some("comment"),
936 "t" => Some("type"),
937 "v" => Some("variable"),
938 "co" => Some("constant"),
939 "n" => Some("number"),
940 "o" => Some("operator"),
941 "p" => Some("punctuation"),
942 "pr" => Some("property"),
943 "at" => Some("attribute"),
944 "tg" => Some("tag"),
945 "m" => Some("macro"),
946 "l" => Some("label"),
947 "ns" => Some("namespace"),
948 "cr" => Some("constructor"),
949 "tt" => Some("title"),
950 "st" => Some("strong"),
951 "em" => Some("emphasis"),
952 "tu" => Some("link"),
953 "tl" => Some("literal"),
954 "tx" => Some("strikethrough"),
955 "da" => Some("diff-add"),
956 "dd" => Some("diff-delete"),
957 "eb" => Some("embedded"),
958 "er" => Some("error"),
959 _ => None,
960 }
961}
962
963pub const CAPTURE_NAMES: &[&str] = &[
969 "keyword",
971 "keyword.conditional",
972 "keyword.coroutine",
973 "keyword.debug",
974 "keyword.exception",
975 "keyword.function",
976 "keyword.import",
977 "keyword.operator",
978 "keyword.repeat",
979 "keyword.return",
980 "keyword.type",
981 "keyword.modifier",
982 "keyword.directive",
983 "keyword.storage",
984 "keyword.control",
985 "keyword.control.conditional",
986 "keyword.control.repeat",
987 "keyword.control.import",
988 "keyword.control.return",
989 "keyword.control.exception",
990 "include",
992 "conditional",
993 "repeat",
994 "exception",
995 "storageclass",
996 "preproc",
997 "define",
998 "structure",
999 "function",
1001 "function.builtin",
1002 "function.method",
1003 "function.definition",
1004 "function.call",
1005 "function.macro",
1006 "function.special",
1007 "method",
1008 "method.call",
1009 "string",
1011 "string.special",
1012 "string.special.symbol",
1013 "string.special.path",
1014 "string.special.url",
1015 "string.escape",
1016 "string.regexp",
1017 "string.regex",
1018 "character",
1019 "character.special",
1020 "escape",
1021 "comment",
1023 "comment.documentation",
1024 "comment.line",
1025 "comment.block",
1026 "comment.error",
1027 "comment.warning",
1028 "comment.note",
1029 "comment.todo",
1030 "type",
1032 "type.builtin",
1033 "type.qualifier",
1034 "type.definition",
1035 "type.enum",
1036 "type.enum.variant",
1037 "type.parameter",
1038 "variable",
1040 "variable.builtin",
1041 "variable.parameter",
1042 "variable.member",
1043 "variable.other",
1044 "variable.other.member",
1045 "parameter",
1046 "field",
1047 "constant",
1049 "constant.builtin",
1050 "constant.builtin.boolean",
1051 "constant.numeric",
1052 "boolean",
1053 "number",
1055 "float",
1056 "number.float",
1057 "operator",
1059 "punctuation",
1061 "punctuation.bracket",
1062 "punctuation.delimiter",
1063 "punctuation.special",
1064 "property",
1066 "property.builtin",
1067 "attribute",
1069 "attribute.builtin",
1070 "tag",
1072 "tag.delimiter",
1073 "tag.error",
1074 "tag.attribute",
1075 "tag.builtin",
1076 "macro",
1078 "label",
1080 "namespace",
1082 "module",
1083 "constructor",
1085 "constructor.builtin",
1086 "text.title",
1088 "markup.heading",
1089 "markup.heading.1",
1090 "markup.heading.2",
1091 "markup.heading.3",
1092 "markup.heading.4",
1093 "markup.heading.5",
1094 "markup.heading.6",
1095 "text.strong",
1097 "markup.bold",
1098 "text.emphasis",
1099 "markup.italic",
1100 "text.uri",
1102 "text.reference",
1103 "markup.link",
1104 "markup.link.url",
1105 "markup.link.text",
1106 "markup.link.label",
1107 "text.literal",
1109 "markup.raw",
1110 "markup.raw.block",
1111 "markup.raw.inline",
1112 "markup.inline",
1113 "text.strikethrough",
1115 "markup.strikethrough",
1116 "markup.list",
1118 "markup.list.checked",
1119 "markup.list.unchecked",
1120 "markup.list.numbered",
1121 "markup.list.unnumbered",
1122 "markup.quote",
1123 "text",
1125 "markup",
1126 "diff.addition",
1128 "diff.plus",
1129 "diff.delta",
1130 "diff.deletion",
1131 "diff.minus",
1132 "embedded",
1134 "error",
1135 "none",
1136 "nospell",
1137 "spell",
1138];
1139
1140#[cfg(test)]
1141mod tests {
1142 use super::*;
1143
1144 #[test]
1145 fn test_names_count() {
1146 assert_eq!(names().len(), COUNT);
1147 }
1148
1149 #[test]
1150 fn test_none_produces_no_tag() {
1151 let none_idx = HIGHLIGHTS.iter().position(|h| h.name == "none").unwrap();
1153 assert_eq!(tag(none_idx), None);
1154 }
1155
1156 #[test]
1157 fn test_keyword_tag() {
1158 let kw_idx = HIGHLIGHTS.iter().position(|h| h.name == "keyword").unwrap();
1159 assert_eq!(tag(kw_idx), Some("k"));
1160 assert_eq!(prefixed_tag(kw_idx), Some("a-k".to_string()));
1161 }
1162
1163 #[test]
1164 fn test_inheritance() {
1165 let kc_idx = HIGHLIGHTS
1166 .iter()
1167 .position(|h| h.name == "keyword.conditional")
1168 .unwrap();
1169 assert_eq!(parent_tag(kc_idx), Some("k"));
1170 }
1171
1172 #[test]
1173 fn test_capture_to_slot_keywords() {
1174 assert_eq!(capture_to_slot("keyword"), ThemeSlot::Keyword);
1176 assert_eq!(capture_to_slot("keyword.function"), ThemeSlot::Keyword);
1177 assert_eq!(capture_to_slot("keyword.import"), ThemeSlot::Keyword);
1178 assert_eq!(capture_to_slot("include"), ThemeSlot::Keyword);
1179 assert_eq!(capture_to_slot("conditional"), ThemeSlot::Keyword);
1180 assert_eq!(capture_to_slot("repeat"), ThemeSlot::Keyword);
1181 assert_eq!(capture_to_slot("storageclass"), ThemeSlot::Keyword);
1182 }
1183
1184 #[test]
1185 fn test_capture_to_slot_functions() {
1186 assert_eq!(capture_to_slot("function"), ThemeSlot::Function);
1187 assert_eq!(capture_to_slot("function.builtin"), ThemeSlot::Function);
1188 assert_eq!(capture_to_slot("function.method"), ThemeSlot::Function);
1189 assert_eq!(capture_to_slot("method"), ThemeSlot::Function);
1190 }
1191
1192 #[test]
1193 fn test_capture_to_slot_markup() {
1194 assert_eq!(capture_to_slot("markup.heading"), ThemeSlot::Title);
1195 assert_eq!(capture_to_slot("markup.heading.1"), ThemeSlot::Title);
1196 assert_eq!(capture_to_slot("text.title"), ThemeSlot::Title);
1197 assert_eq!(capture_to_slot("markup.bold"), ThemeSlot::Strong);
1198 assert_eq!(capture_to_slot("markup.italic"), ThemeSlot::Emphasis);
1199 }
1200
1201 #[test]
1202 fn test_capture_to_slot_none() {
1203 assert_eq!(capture_to_slot("none"), ThemeSlot::None);
1204 assert_eq!(capture_to_slot("spell"), ThemeSlot::None);
1205 assert_eq!(capture_to_slot("nospell"), ThemeSlot::None);
1206 }
1207
1208 #[test]
1209 fn test_tag_for_capture() {
1210 assert_eq!(tag_for_capture("keyword"), Some("k"));
1212 assert_eq!(tag_for_capture("keyword.function"), Some("k"));
1213 assert_eq!(tag_for_capture("include"), Some("k"));
1214 assert_eq!(tag_for_capture("conditional"), Some("k"));
1215
1216 assert_eq!(tag_for_capture("function"), Some("f"));
1218 assert_eq!(tag_for_capture("function.builtin"), Some("f"));
1219
1220 assert_eq!(tag_for_capture("comment"), Some("c"));
1222 assert_eq!(tag_for_capture("comment.documentation"), Some("c"));
1223
1224 assert_eq!(tag_for_capture("spell"), None);
1226 assert_eq!(tag_for_capture("none"), None);
1227 }
1228
1229 #[test]
1230 fn test_theme_slot_tag() {
1231 assert_eq!(ThemeSlot::Keyword.tag(), Some("k"));
1232 assert_eq!(ThemeSlot::Function.tag(), Some("f"));
1233 assert_eq!(ThemeSlot::String.tag(), Some("s"));
1234 assert_eq!(ThemeSlot::Comment.tag(), Some("c"));
1235 assert_eq!(ThemeSlot::None.tag(), None);
1236 }
1237
1238 #[test]
1239 fn test_capture_names_all_map_to_slot() {
1240 for name in CAPTURE_NAMES {
1242 let slot = capture_to_slot(name);
1243 let _ = slot.tag();
1245 }
1246 }
1247}