1#[cfg(any(
9 feature = "syntax-rust",
10 feature = "syntax-python",
11 feature = "syntax-javascript",
12 feature = "syntax-typescript",
13 feature = "syntax-go",
14 feature = "syntax-bash",
15 feature = "syntax-json",
16 feature = "syntax-toml",
17 feature = "syntax-c",
18 feature = "syntax-cpp",
19 feature = "syntax-java",
20 feature = "syntax-ruby",
21 feature = "syntax-css",
22 feature = "syntax-html",
23 feature = "syntax-yaml",
24))]
25use crate::style::Color;
26use crate::style::{Style, Theme};
27
28#[cfg(any(
33 feature = "syntax-rust",
34 feature = "syntax-python",
35 feature = "syntax-javascript",
36 feature = "syntax-typescript",
37 feature = "syntax-go",
38 feature = "syntax-bash",
39 feature = "syntax-json",
40 feature = "syntax-toml",
41 feature = "syntax-c",
42 feature = "syntax-cpp",
43 feature = "syntax-java",
44 feature = "syntax-ruby",
45 feature = "syntax-css",
46 feature = "syntax-html",
47 feature = "syntax-yaml",
48))]
49const HIGHLIGHT_NAMES: &[&str] = &[
50 "attribute",
51 "comment",
52 "constant",
53 "constant.builtin",
54 "constructor",
55 "embedded",
56 "function",
57 "function.builtin",
58 "function.macro",
59 "keyword",
60 "module",
61 "number",
62 "operator",
63 "property",
64 "property.builtin",
65 "punctuation",
66 "punctuation.bracket",
67 "punctuation.delimiter",
68 "punctuation.special",
69 "string",
70 "string.special",
71 "tag",
72 "type",
73 "type.builtin",
74 "variable",
75 "variable.builtin",
76 "variable.parameter",
77];
78
79#[cfg(any(
80 feature = "syntax-rust",
81 feature = "syntax-python",
82 feature = "syntax-javascript",
83 feature = "syntax-typescript",
84 feature = "syntax-go",
85 feature = "syntax-bash",
86 feature = "syntax-json",
87 feature = "syntax-toml",
88 feature = "syntax-c",
89 feature = "syntax-cpp",
90 feature = "syntax-java",
91 feature = "syntax-ruby",
92 feature = "syntax-css",
93 feature = "syntax-html",
94 feature = "syntax-yaml",
95))]
96use std::sync::OnceLock;
97
98#[cfg(any(
99 feature = "syntax-rust",
100 feature = "syntax-python",
101 feature = "syntax-javascript",
102 feature = "syntax-typescript",
103 feature = "syntax-go",
104 feature = "syntax-bash",
105 feature = "syntax-json",
106 feature = "syntax-toml",
107 feature = "syntax-c",
108 feature = "syntax-cpp",
109 feature = "syntax-java",
110 feature = "syntax-ruby",
111 feature = "syntax-css",
112 feature = "syntax-html",
113 feature = "syntax-yaml",
114))]
115use tree_sitter_highlight::HighlightConfiguration;
116
117#[cfg(any(
120 feature = "syntax-rust",
121 feature = "syntax-python",
122 feature = "syntax-javascript",
123 feature = "syntax-typescript",
124 feature = "syntax-go",
125 feature = "syntax-bash",
126 feature = "syntax-json",
127 feature = "syntax-toml",
128 feature = "syntax-c",
129 feature = "syntax-cpp",
130 feature = "syntax-java",
131 feature = "syntax-ruby",
132 feature = "syntax-css",
133 feature = "syntax-html",
134 feature = "syntax-yaml",
135))]
136fn get_config(lang: &str) -> Option<&'static HighlightConfiguration> {
137 match lang {
138 #[cfg(feature = "syntax-rust")]
139 "rust" | "rs" => {
140 static CFG: OnceLock<Option<HighlightConfiguration>> = OnceLock::new();
141 CFG.get_or_init(|| {
142 HighlightConfiguration::new(
143 tree_sitter_rust::LANGUAGE.into(),
144 "rust",
145 tree_sitter_rust::HIGHLIGHTS_QUERY,
146 tree_sitter_rust::INJECTIONS_QUERY,
147 "",
148 )
149 .ok()
150 .map(|mut c| {
151 c.configure(HIGHLIGHT_NAMES);
152 c
153 })
154 })
155 .as_ref()
156 }
157
158 #[cfg(feature = "syntax-python")]
159 "python" | "py" => {
160 static CFG: OnceLock<Option<HighlightConfiguration>> = OnceLock::new();
161 CFG.get_or_init(|| {
162 HighlightConfiguration::new(
163 tree_sitter_python::LANGUAGE.into(),
164 "python",
165 tree_sitter_python::HIGHLIGHTS_QUERY,
166 "",
167 "",
168 )
169 .ok()
170 .map(|mut c| {
171 c.configure(HIGHLIGHT_NAMES);
172 c
173 })
174 })
175 .as_ref()
176 }
177
178 #[cfg(feature = "syntax-javascript")]
179 "javascript" | "js" | "jsx" => {
180 static CFG: OnceLock<Option<HighlightConfiguration>> = OnceLock::new();
181 CFG.get_or_init(|| {
182 HighlightConfiguration::new(
183 tree_sitter_javascript::LANGUAGE.into(),
184 "javascript",
185 tree_sitter_javascript::HIGHLIGHT_QUERY,
186 tree_sitter_javascript::INJECTIONS_QUERY,
187 tree_sitter_javascript::LOCALS_QUERY,
188 )
189 .ok()
190 .map(|mut c| {
191 c.configure(HIGHLIGHT_NAMES);
192 c
193 })
194 })
195 .as_ref()
196 }
197
198 #[cfg(feature = "syntax-go")]
199 "go" | "golang" => {
200 static CFG: OnceLock<Option<HighlightConfiguration>> = OnceLock::new();
201 CFG.get_or_init(|| {
202 HighlightConfiguration::new(
203 tree_sitter_go::LANGUAGE.into(),
204 "go",
205 tree_sitter_go::HIGHLIGHTS_QUERY,
206 "",
207 "",
208 )
209 .ok()
210 .map(|mut c| {
211 c.configure(HIGHLIGHT_NAMES);
212 c
213 })
214 })
215 .as_ref()
216 }
217
218 #[cfg(feature = "syntax-bash")]
219 "bash" | "sh" | "shell" | "zsh" => {
220 static CFG: OnceLock<Option<HighlightConfiguration>> = OnceLock::new();
221 CFG.get_or_init(|| {
222 HighlightConfiguration::new(
223 tree_sitter_bash::LANGUAGE.into(),
224 "bash",
225 tree_sitter_bash::HIGHLIGHT_QUERY,
226 "",
227 "",
228 )
229 .ok()
230 .map(|mut c| {
231 c.configure(HIGHLIGHT_NAMES);
232 c
233 })
234 })
235 .as_ref()
236 }
237
238 #[cfg(feature = "syntax-json")]
239 "json" | "jsonc" => {
240 static CFG: OnceLock<Option<HighlightConfiguration>> = OnceLock::new();
241 CFG.get_or_init(|| {
242 HighlightConfiguration::new(
243 tree_sitter_json::LANGUAGE.into(),
244 "json",
245 tree_sitter_json::HIGHLIGHTS_QUERY,
246 "",
247 "",
248 )
249 .ok()
250 .map(|mut c| {
251 c.configure(HIGHLIGHT_NAMES);
252 c
253 })
254 })
255 .as_ref()
256 }
257
258 #[cfg(feature = "syntax-toml")]
259 "toml" => {
260 static CFG: OnceLock<Option<HighlightConfiguration>> = OnceLock::new();
261 CFG.get_or_init(|| {
262 HighlightConfiguration::new(
263 tree_sitter_toml_ng::LANGUAGE.into(),
264 "toml",
265 tree_sitter_toml_ng::HIGHLIGHTS_QUERY,
266 "",
267 "",
268 )
269 .ok()
270 .map(|mut c| {
271 c.configure(HIGHLIGHT_NAMES);
272 c
273 })
274 })
275 .as_ref()
276 }
277
278 #[cfg(feature = "syntax-c")]
279 "c" | "h" => {
280 static CFG: OnceLock<Option<HighlightConfiguration>> = OnceLock::new();
281 CFG.get_or_init(|| {
282 HighlightConfiguration::new(
283 tree_sitter_c::LANGUAGE.into(),
284 "c",
285 tree_sitter_c::HIGHLIGHT_QUERY,
286 "",
287 "",
288 )
289 .ok()
290 .map(|mut c| {
291 c.configure(HIGHLIGHT_NAMES);
292 c
293 })
294 })
295 .as_ref()
296 }
297
298 #[cfg(feature = "syntax-cpp")]
299 "cpp" | "c++" | "cxx" | "cc" | "hpp" => {
300 static CFG: OnceLock<Option<HighlightConfiguration>> = OnceLock::new();
301 CFG.get_or_init(|| {
302 #[cfg(feature = "syntax-c")]
303 let highlights = {
304 let mut combined = String::with_capacity(
305 tree_sitter_c::HIGHLIGHT_QUERY.len()
306 + tree_sitter_cpp::HIGHLIGHT_QUERY.len()
307 + 1,
308 );
309 combined.push_str(tree_sitter_c::HIGHLIGHT_QUERY);
310 combined.push('\n');
311 combined.push_str(tree_sitter_cpp::HIGHLIGHT_QUERY);
312 combined
313 };
314 #[cfg(not(feature = "syntax-c"))]
315 let highlights = tree_sitter_cpp::HIGHLIGHT_QUERY.to_string();
316
317 HighlightConfiguration::new(
318 tree_sitter_cpp::LANGUAGE.into(),
319 "cpp",
320 &highlights,
321 "",
322 "",
323 )
324 .ok()
325 .map(|mut c| {
326 c.configure(HIGHLIGHT_NAMES);
327 c
328 })
329 })
330 .as_ref()
331 }
332
333 #[cfg(feature = "syntax-typescript")]
334 "typescript" | "ts" => {
335 static CFG: OnceLock<Option<HighlightConfiguration>> = OnceLock::new();
336 CFG.get_or_init(|| {
337 HighlightConfiguration::new(
338 tree_sitter_typescript::LANGUAGE_TYPESCRIPT.into(),
339 "typescript",
340 tree_sitter_typescript::HIGHLIGHTS_QUERY,
341 tree_sitter_typescript::LOCALS_QUERY,
342 "",
343 )
344 .ok()
345 .map(|mut c| {
346 c.configure(HIGHLIGHT_NAMES);
347 c
348 })
349 })
350 .as_ref()
351 }
352
353 #[cfg(feature = "syntax-typescript")]
354 "tsx" => {
355 static CFG: OnceLock<Option<HighlightConfiguration>> = OnceLock::new();
356 CFG.get_or_init(|| {
357 HighlightConfiguration::new(
358 tree_sitter_typescript::LANGUAGE_TSX.into(),
359 "tsx",
360 tree_sitter_typescript::HIGHLIGHTS_QUERY,
361 tree_sitter_typescript::LOCALS_QUERY,
362 "",
363 )
364 .ok()
365 .map(|mut c| {
366 c.configure(HIGHLIGHT_NAMES);
367 c
368 })
369 })
370 .as_ref()
371 }
372
373 #[cfg(feature = "syntax-java")]
374 "java" => {
375 static CFG: OnceLock<Option<HighlightConfiguration>> = OnceLock::new();
376 CFG.get_or_init(|| {
377 HighlightConfiguration::new(
378 tree_sitter_java::LANGUAGE.into(),
379 "java",
380 tree_sitter_java::HIGHLIGHTS_QUERY,
381 "",
382 "",
383 )
384 .ok()
385 .map(|mut c| {
386 c.configure(HIGHLIGHT_NAMES);
387 c
388 })
389 })
390 .as_ref()
391 }
392
393 #[cfg(feature = "syntax-ruby")]
394 "ruby" | "rb" => {
395 static CFG: OnceLock<Option<HighlightConfiguration>> = OnceLock::new();
396 CFG.get_or_init(|| {
397 HighlightConfiguration::new(
398 tree_sitter_ruby::LANGUAGE.into(),
399 "ruby",
400 tree_sitter_ruby::HIGHLIGHTS_QUERY,
401 tree_sitter_ruby::LOCALS_QUERY,
402 "",
403 )
404 .ok()
405 .map(|mut c| {
406 c.configure(HIGHLIGHT_NAMES);
407 c
408 })
409 })
410 .as_ref()
411 }
412
413 #[cfg(feature = "syntax-css")]
414 "css" => {
415 static CFG: OnceLock<Option<HighlightConfiguration>> = OnceLock::new();
416 CFG.get_or_init(|| {
417 HighlightConfiguration::new(
418 tree_sitter_css::LANGUAGE.into(),
419 "css",
420 tree_sitter_css::HIGHLIGHTS_QUERY,
421 "",
422 "",
423 )
424 .ok()
425 .map(|mut c| {
426 c.configure(HIGHLIGHT_NAMES);
427 c
428 })
429 })
430 .as_ref()
431 }
432
433 #[cfg(feature = "syntax-html")]
434 "html" | "htm" => {
435 static CFG: OnceLock<Option<HighlightConfiguration>> = OnceLock::new();
436 CFG.get_or_init(|| {
437 HighlightConfiguration::new(
438 tree_sitter_html::LANGUAGE.into(),
439 "html",
440 tree_sitter_html::HIGHLIGHTS_QUERY,
441 tree_sitter_html::INJECTIONS_QUERY,
442 "",
443 )
444 .ok()
445 .map(|mut c| {
446 c.configure(HIGHLIGHT_NAMES);
447 c
448 })
449 })
450 .as_ref()
451 }
452
453 #[cfg(feature = "syntax-yaml")]
454 "yaml" | "yml" => {
455 static CFG: OnceLock<Option<HighlightConfiguration>> = OnceLock::new();
456 CFG.get_or_init(|| {
457 HighlightConfiguration::new(
458 tree_sitter_yaml::LANGUAGE.into(),
459 "yaml",
460 tree_sitter_yaml::HIGHLIGHTS_QUERY,
461 "",
462 "",
463 )
464 .ok()
465 .map(|mut c| {
466 c.configure(HIGHLIGHT_NAMES);
467 c
468 })
469 })
470 .as_ref()
471 }
472
473 _ => None,
474 }
475}
476
477#[cfg(any(
482 feature = "syntax-rust",
483 feature = "syntax-python",
484 feature = "syntax-javascript",
485 feature = "syntax-typescript",
486 feature = "syntax-go",
487 feature = "syntax-bash",
488 feature = "syntax-json",
489 feature = "syntax-toml",
490 feature = "syntax-c",
491 feature = "syntax-cpp",
492 feature = "syntax-java",
493 feature = "syntax-ruby",
494 feature = "syntax-css",
495 feature = "syntax-html",
496 feature = "syntax-yaml",
497))]
498fn highlight_name_to_style(name: &str, theme: &Theme) -> Style {
499 let dark = theme.is_dark;
500 match name {
501 "keyword" => Style::new().fg(if dark {
502 Color::Rgb(198, 120, 221)
503 } else {
504 Color::Rgb(166, 38, 164)
505 }),
506 "string" | "string.special" => Style::new().fg(if dark {
507 Color::Rgb(152, 195, 121)
508 } else {
509 Color::Rgb(80, 161, 79)
510 }),
511 "comment" => Style::new().fg(theme.text_dim).italic(),
512 "number" | "constant" | "constant.builtin" => Style::new().fg(if dark {
513 Color::Rgb(209, 154, 102)
514 } else {
515 Color::Rgb(152, 104, 1)
516 }),
517 "function" | "function.builtin" => Style::new().fg(if dark {
518 Color::Rgb(97, 175, 239)
519 } else {
520 Color::Rgb(64, 120, 242)
521 }),
522 "function.macro" => Style::new().fg(if dark {
523 Color::Rgb(86, 182, 194)
524 } else {
525 Color::Rgb(1, 132, 188)
526 }),
527 "type" | "type.builtin" | "constructor" => Style::new().fg(if dark {
528 Color::Rgb(229, 192, 123)
529 } else {
530 Color::Rgb(152, 104, 1)
531 }),
532 "variable.builtin" => Style::new().fg(if dark {
533 Color::Rgb(224, 108, 117)
534 } else {
535 Color::Rgb(166, 38, 164)
536 }),
537 "property" | "property.builtin" => Style::new().fg(if dark {
538 Color::Rgb(97, 175, 239)
539 } else {
540 Color::Rgb(64, 120, 242)
541 }),
542 "tag" => Style::new().fg(if dark {
543 Color::Rgb(224, 108, 117)
544 } else {
545 Color::Rgb(166, 38, 164)
546 }),
547 "attribute" => Style::new().fg(if dark {
548 Color::Rgb(209, 154, 102)
549 } else {
550 Color::Rgb(152, 104, 1)
551 }),
552 "module" | "embedded" | "operator" | "variable" | "variable.parameter" => {
553 Style::new().fg(theme.text)
554 }
555 "punctuation" | "punctuation.bracket" | "punctuation.delimiter" | "punctuation.special" => {
556 Style::new().fg(theme.text_dim)
557 }
558 _ => Style::new().fg(theme.text),
559 }
560}
561
562#[allow(unused_variables)]
579pub fn highlight_code(code: &str, lang: &str, theme: &Theme) -> Option<Vec<Vec<(String, Style)>>> {
580 #[cfg(any(
581 feature = "syntax-rust",
582 feature = "syntax-python",
583 feature = "syntax-javascript",
584 feature = "syntax-typescript",
585 feature = "syntax-go",
586 feature = "syntax-bash",
587 feature = "syntax-json",
588 feature = "syntax-toml",
589 feature = "syntax-c",
590 feature = "syntax-cpp",
591 feature = "syntax-java",
592 feature = "syntax-ruby",
593 feature = "syntax-css",
594 feature = "syntax-html",
595 feature = "syntax-yaml",
596 ))]
597 {
598 use tree_sitter_highlight::{HighlightEvent, Highlighter};
599
600 let config = get_config(lang)?;
601 let mut highlighter = Highlighter::new();
602 let highlights = highlighter
603 .highlight(config, code.as_bytes(), None, |_| None)
604 .ok()?;
605
606 let default_style = Style::new().fg(theme.text);
607 let mut result: Vec<Vec<(String, Style)>> = Vec::new();
608 let mut current_line: Vec<(String, Style)> = Vec::new();
609 let mut style_stack: Vec<Style> = vec![default_style];
610
611 for event in highlights {
612 match event.ok()? {
613 HighlightEvent::Source { start, end } => {
614 let text = &code[start..end];
615 let style = *style_stack.last().unwrap_or(&default_style);
616 for (i, part) in text.split('\n').enumerate() {
618 if i > 0 {
619 result.push(std::mem::take(&mut current_line));
620 }
621 if !part.is_empty() {
622 current_line.push((part.to_string(), style));
623 }
624 }
625 }
626 HighlightEvent::HighlightStart(highlight) => {
627 let name = HIGHLIGHT_NAMES.get(highlight.0).copied().unwrap_or("");
628 let style = highlight_name_to_style(name, theme);
629 style_stack.push(style);
630 }
631 HighlightEvent::HighlightEnd => {
632 style_stack.pop();
633 }
634 }
635 }
636
637 if !current_line.is_empty() {
638 result.push(current_line);
639 }
640
641 Some(result)
642 }
643
644 #[cfg(not(any(
645 feature = "syntax-rust",
646 feature = "syntax-python",
647 feature = "syntax-javascript",
648 feature = "syntax-typescript",
649 feature = "syntax-go",
650 feature = "syntax-bash",
651 feature = "syntax-json",
652 feature = "syntax-toml",
653 feature = "syntax-c",
654 feature = "syntax-cpp",
655 feature = "syntax-java",
656 feature = "syntax-ruby",
657 feature = "syntax-css",
658 feature = "syntax-html",
659 feature = "syntax-yaml",
660 )))]
661 {
662 None
663 }
664}
665
666#[allow(unused_variables)]
671pub fn is_language_supported(lang: &str) -> bool {
672 #[cfg(any(
673 feature = "syntax-rust",
674 feature = "syntax-python",
675 feature = "syntax-javascript",
676 feature = "syntax-typescript",
677 feature = "syntax-go",
678 feature = "syntax-bash",
679 feature = "syntax-json",
680 feature = "syntax-toml",
681 feature = "syntax-c",
682 feature = "syntax-cpp",
683 feature = "syntax-java",
684 feature = "syntax-ruby",
685 feature = "syntax-css",
686 feature = "syntax-html",
687 feature = "syntax-yaml",
688 ))]
689 {
690 get_config(lang).is_some()
691 }
692 #[cfg(not(any(
693 feature = "syntax-rust",
694 feature = "syntax-python",
695 feature = "syntax-javascript",
696 feature = "syntax-typescript",
697 feature = "syntax-go",
698 feature = "syntax-bash",
699 feature = "syntax-json",
700 feature = "syntax-toml",
701 feature = "syntax-c",
702 feature = "syntax-cpp",
703 feature = "syntax-java",
704 feature = "syntax-ruby",
705 feature = "syntax-css",
706 feature = "syntax-html",
707 feature = "syntax-yaml",
708 )))]
709 {
710 false
711 }
712}
713
714#[cfg(test)]
715mod tests {
716 use super::*;
717 use crate::style::Theme;
718
719 #[test]
720 fn highlight_returns_none_for_unknown_lang() {
721 let theme = Theme::dark();
722 assert!(highlight_code("let x = 1;", "brainfuck", &theme).is_none());
723 }
724
725 #[test]
726 fn is_language_supported_unknown() {
727 assert!(!is_language_supported("haskell"));
728 }
729
730 #[cfg(feature = "syntax-rust")]
731 #[test]
732 fn highlight_rust_basic() {
733 let theme = Theme::dark();
734 let result = highlight_code("let x = 1;", "rust", &theme);
735 assert!(result.is_some());
736 let lines = result.unwrap();
737 assert_eq!(lines.len(), 1);
738 let flat: String = lines[0].iter().map(|(t, _)| t.as_str()).collect();
740 assert!(flat.contains("let"));
741 assert!(flat.contains("1"));
742 }
743
744 #[cfg(feature = "syntax-rust")]
745 #[test]
746 fn highlight_rust_multiline() {
747 let theme = Theme::dark();
748 let code = "fn main() {\n println!(\"hello\");\n}";
749 let result = highlight_code(code, "rust", &theme).unwrap();
750 assert_eq!(result.len(), 3);
751 }
752
753 #[cfg(feature = "syntax-rust")]
754 #[test]
755 fn highlight_rust_rs_alias() {
756 let theme = Theme::dark();
757 assert!(highlight_code("let x = 1;", "rs", &theme).is_some());
758 }
759
760 #[cfg(feature = "syntax-python")]
761 #[test]
762 fn highlight_python_basic() {
763 let theme = Theme::dark();
764 let result = highlight_code("def foo():\n return 42", "python", &theme);
765 assert!(result.is_some());
766 let lines = result.unwrap();
767 assert_eq!(lines.len(), 2);
768 }
769
770 #[cfg(feature = "syntax-javascript")]
771 #[test]
772 fn highlight_javascript_basic() {
773 let theme = Theme::dark();
774 let result = highlight_code("const x = () => 42;", "js", &theme);
775 assert!(result.is_some());
776 }
777
778 #[cfg(feature = "syntax-bash")]
779 #[test]
780 fn highlight_bash_basic() {
781 let theme = Theme::dark();
782 let result = highlight_code("echo \"hello\"", "sh", &theme);
783 assert!(result.is_some());
784 }
785
786 #[cfg(feature = "syntax-json")]
787 #[test]
788 fn highlight_json_basic() {
789 let theme = Theme::dark();
790 let result = highlight_code("{\"key\": 42}", "json", &theme);
791 assert!(result.is_some());
792 }
793
794 #[cfg(feature = "syntax-toml")]
795 #[test]
796 fn highlight_toml_basic() {
797 let theme = Theme::dark();
798 let result = highlight_code("[package]\nname = \"slt\"", "toml", &theme);
799 assert!(result.is_some());
800 }
801
802 #[cfg(feature = "syntax-go")]
803 #[test]
804 fn highlight_go_basic() {
805 let theme = Theme::dark();
806 let result = highlight_code("package main\nfunc main() {}", "go", &theme);
807 assert!(result.is_some());
808 }
809
810 #[cfg(feature = "syntax-rust")]
811 #[test]
812 fn highlight_light_theme_differs() {
813 let dark = Theme::dark();
814 let light = Theme::light();
815 let dark_result = highlight_code("let x = 1;", "rust", &dark).unwrap();
816 let light_result = highlight_code("let x = 1;", "rust", &light).unwrap();
817 let dark_styles: Vec<Style> = dark_result[0].iter().map(|(_, s)| *s).collect();
819 let light_styles: Vec<Style> = light_result[0].iter().map(|(_, s)| *s).collect();
820 assert_ne!(dark_styles, light_styles);
821 }
822
823 #[cfg(feature = "syntax-rust")]
824 #[test]
825 fn highlight_incomplete_code_does_not_panic() {
826 let theme = Theme::dark();
827 let result = highlight_code("fn main( {", "rust", &theme);
828 assert!(result.is_some());
829 }
830
831 #[cfg(feature = "syntax-c")]
832 #[test]
833 fn highlight_c_basic() {
834 let theme = Theme::dark();
835 assert!(
836 highlight_code("#include <stdio.h>\nint main() { return 0; }", "c", &theme).is_some()
837 );
838 }
839
840 #[cfg(feature = "syntax-cpp")]
841 #[test]
842 fn highlight_cpp_basic() {
843 let theme = Theme::dark();
844 assert!(highlight_code("class Foo { public: void bar(); };", "cpp", &theme).is_some());
845 }
846
847 #[cfg(feature = "syntax-typescript")]
848 #[test]
849 fn highlight_typescript_basic() {
850 let theme = Theme::dark();
851 assert!(highlight_code("const x: number = 42;", "ts", &theme).is_some());
852 }
853
854 #[cfg(feature = "syntax-typescript")]
855 #[test]
856 fn highlight_tsx_basic() {
857 let theme = Theme::dark();
858 assert!(highlight_code("const App = () => <div>hello</div>;", "tsx", &theme).is_some());
859 }
860
861 #[cfg(feature = "syntax-java")]
862 #[test]
863 fn highlight_java_basic() {
864 let theme = Theme::dark();
865 assert!(highlight_code(
866 "public class Main { public static void main(String[] args) {} }",
867 "java",
868 &theme
869 )
870 .is_some());
871 }
872
873 #[cfg(feature = "syntax-ruby")]
874 #[test]
875 fn highlight_ruby_basic() {
876 let theme = Theme::dark();
877 assert!(highlight_code("def hello\n puts 'world'\nend", "ruby", &theme).is_some());
878 }
879
880 #[cfg(feature = "syntax-css")]
881 #[test]
882 fn highlight_css_basic() {
883 let theme = Theme::dark();
884 assert!(highlight_code("body { color: red; }", "css", &theme).is_some());
885 }
886
887 #[cfg(feature = "syntax-html")]
888 #[test]
889 fn highlight_html_basic() {
890 let theme = Theme::dark();
891 assert!(highlight_code("<div class=\"test\">hello</div>", "html", &theme).is_some());
892 }
893
894 #[cfg(feature = "syntax-yaml")]
895 #[test]
896 fn highlight_yaml_basic() {
897 let theme = Theme::dark();
898 assert!(highlight_code("name: slt\nversion: 0.14", "yaml", &theme).is_some());
899 }
900}