1use std::path::Path;
2
3pub use tree_sitter;
5pub use tree_sitter_highlight;
6pub use tree_sitter_highlight::HighlightConfiguration;
7
8#[cfg(feature = "tree-sitter-bash")]
10pub use tree_sitter_bash;
11#[cfg(feature = "tree-sitter-c")]
12pub use tree_sitter_c;
13#[cfg(feature = "tree-sitter-c-sharp")]
14pub use tree_sitter_c_sharp;
15#[cfg(feature = "tree-sitter-cpp")]
16pub use tree_sitter_cpp;
17#[cfg(feature = "tree-sitter-css")]
18pub use tree_sitter_css;
19#[cfg(feature = "tree-sitter-go")]
20pub use tree_sitter_go;
21#[cfg(feature = "tree-sitter-html")]
22pub use tree_sitter_html;
23#[cfg(feature = "tree-sitter-java")]
24pub use tree_sitter_java;
25#[cfg(feature = "tree-sitter-javascript")]
26pub use tree_sitter_javascript;
27#[cfg(feature = "tree-sitter-json")]
28pub use tree_sitter_json;
29#[cfg(feature = "tree-sitter-lua")]
30pub use tree_sitter_lua;
31#[cfg(feature = "tree-sitter-odin")]
32pub use tree_sitter_odin;
33#[cfg(feature = "tree-sitter-pascal")]
34pub use tree_sitter_pascal;
35#[cfg(feature = "tree-sitter-php")]
36pub use tree_sitter_php;
37#[cfg(feature = "tree-sitter-python")]
38pub use tree_sitter_python;
39#[cfg(feature = "tree-sitter-ruby")]
40pub use tree_sitter_ruby;
41#[cfg(feature = "tree-sitter-rust")]
42pub use tree_sitter_rust;
43#[cfg(feature = "tree-sitter-typescript")]
44pub use tree_sitter_typescript;
45
46#[derive(Debug, Clone, Copy, PartialEq, Eq)]
48pub enum HighlightCategory {
49 Attribute,
50 Comment,
51 Constant,
52 Function,
53 Keyword,
54 Number,
55 Operator,
56 PunctuationBracket,
57 PunctuationDelimiter,
58 Property,
59 String,
60 Type,
61 Variable,
62}
63
64impl HighlightCategory {
65 pub fn from_default_index(index: usize) -> Option<Self> {
67 match index {
68 0 => Some(Self::Attribute),
69 1 => Some(Self::Comment),
70 2 => Some(Self::Constant),
71 3 => Some(Self::Function),
72 4 => Some(Self::Keyword),
73 5 => Some(Self::Number),
74 6 => Some(Self::Operator),
75 7 => Some(Self::PunctuationBracket),
76 8 => Some(Self::PunctuationDelimiter),
77 9 => Some(Self::Property),
78 10 => Some(Self::String),
79 11 => Some(Self::Type),
80 12 => Some(Self::Variable),
81 _ => None,
82 }
83 }
84
85 pub fn from_typescript_index(index: usize) -> Option<Self> {
87 match index {
88 0 => Some(Self::Attribute), 1 => Some(Self::Comment), 2 => Some(Self::Constant), 3 => Some(Self::Constant), 4 => Some(Self::Type), 5 => Some(Self::String), 6 => Some(Self::Function), 7 => Some(Self::Function), 8 => Some(Self::Function), 9 => Some(Self::Keyword), 10 => Some(Self::Number), 11 => Some(Self::Operator), 12 => Some(Self::Property), 13 => Some(Self::PunctuationBracket), 14 => Some(Self::PunctuationDelimiter), 15 => Some(Self::Constant), 16 => Some(Self::String), 17 => Some(Self::String), 18 => Some(Self::Type), 19 => Some(Self::Type), 20 => Some(Self::Variable), 21 => Some(Self::Constant), 22 => Some(Self::Variable), _ => None,
112 }
113 }
114
115 pub fn theme_key(&self) -> &'static str {
117 match self {
118 Self::Keyword => "syntax.keyword",
119 Self::String => "syntax.string",
120 Self::Comment => "syntax.comment",
121 Self::Function => "syntax.function",
122 Self::Type => "syntax.type",
123 Self::Variable | Self::Property => "syntax.variable",
124 Self::Constant | Self::Number | Self::Attribute => "syntax.constant",
125 Self::Operator => "syntax.operator",
126 Self::PunctuationBracket => "syntax.punctuation_bracket",
127 Self::PunctuationDelimiter => "syntax.punctuation_delimiter",
128 }
129 }
130
131 pub fn display_name(&self) -> &'static str {
133 match self {
134 Self::Attribute => "Attribute",
135 Self::Comment => "Comment",
136 Self::Constant => "Constant",
137 Self::Function => "Function",
138 Self::Keyword => "Keyword",
139 Self::Number => "Number",
140 Self::Operator => "Operator",
141 Self::PunctuationBracket => "Punctuation Bracket",
142 Self::PunctuationDelimiter => "Punctuation Delimiter",
143 Self::Property => "Property",
144 Self::String => "String",
145 Self::Type => "Type",
146 Self::Variable => "Variable",
147 }
148 }
149}
150
151#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
153pub enum Language {
154 Rust,
155 Python,
156 JavaScript,
157 TypeScript,
158 HTML,
159 CSS,
160 C,
161 Cpp,
162 Go,
163 Json,
164 Jsonc,
165 Java,
166 CSharp,
167 Php,
168 Ruby,
169 Bash,
170 Lua,
171 Pascal,
172 Odin,
173}
174
175impl Language {
176 pub fn from_path(path: &Path) -> Option<Self> {
182 let ext = path.extension()?.to_str()?;
183 Self::all()
184 .iter()
185 .find(|lang| lang.extensions().contains(&ext))
186 .copied()
187 }
188
189 pub fn highlight_config(&self) -> Result<HighlightConfiguration, String> {
191 match self {
192 Self::Rust => {
193 #[cfg(feature = "tree-sitter-rust")]
194 {
195 let mut config = HighlightConfiguration::new(
196 tree_sitter_rust::LANGUAGE.into(),
197 "rust",
198 tree_sitter_rust::HIGHLIGHTS_QUERY,
199 "",
200 "",
201 )
202 .map_err(|e| format!("Failed to create Rust highlight config: {e}"))?;
203 config.configure(DEFAULT_HIGHLIGHT_CAPTURES);
204 Ok(config)
205 }
206 #[cfg(not(feature = "tree-sitter-rust"))]
207 Err("Rust language support not enabled".to_string())
208 }
209 Self::Python => {
210 #[cfg(feature = "tree-sitter-python")]
211 {
212 let mut config = HighlightConfiguration::new(
213 tree_sitter_python::LANGUAGE.into(),
214 "python",
215 tree_sitter_python::HIGHLIGHTS_QUERY,
216 "",
217 "",
218 )
219 .map_err(|e| format!("Failed to create Python highlight config: {e}"))?;
220 config.configure(DEFAULT_HIGHLIGHT_CAPTURES);
221 Ok(config)
222 }
223 #[cfg(not(feature = "tree-sitter-python"))]
224 Err("Python language support not enabled".to_string())
225 }
226 Self::JavaScript => {
227 #[cfg(feature = "tree-sitter-javascript")]
228 {
229 let mut config = HighlightConfiguration::new(
230 tree_sitter_javascript::LANGUAGE.into(),
231 "javascript",
232 tree_sitter_javascript::HIGHLIGHT_QUERY,
233 "",
234 "",
235 )
236 .map_err(|e| format!("Failed to create JavaScript highlight config: {e}"))?;
237 config.configure(DEFAULT_HIGHLIGHT_CAPTURES);
238 Ok(config)
239 }
240 #[cfg(not(feature = "tree-sitter-javascript"))]
241 Err("JavaScript language support not enabled".to_string())
242 }
243 Self::TypeScript => {
244 #[cfg(all(feature = "tree-sitter-typescript", feature = "tree-sitter-javascript"))]
245 {
246 let combined_highlights = format!(
247 "{}\n{}",
248 tree_sitter_typescript::HIGHLIGHTS_QUERY,
249 tree_sitter_javascript::HIGHLIGHT_QUERY
250 );
251 let mut config = HighlightConfiguration::new(
252 tree_sitter_typescript::LANGUAGE_TYPESCRIPT.into(),
253 "typescript",
254 &combined_highlights,
255 "",
256 tree_sitter_typescript::LOCALS_QUERY,
257 )
258 .map_err(|e| format!("Failed to create TypeScript highlight config: {e}"))?;
259 config.configure(TYPESCRIPT_HIGHLIGHT_CAPTURES);
260 Ok(config)
261 }
262 #[cfg(not(all(
263 feature = "tree-sitter-typescript",
264 feature = "tree-sitter-javascript"
265 )))]
266 Err("TypeScript language support not enabled".to_string())
267 }
268 Self::HTML => {
269 #[cfg(feature = "tree-sitter-html")]
270 {
271 let mut config = HighlightConfiguration::new(
272 tree_sitter_html::LANGUAGE.into(),
273 "html",
274 tree_sitter_html::HIGHLIGHTS_QUERY,
275 "",
276 "",
277 )
278 .map_err(|e| format!("Failed to create HTML highlight config: {e}"))?;
279 config.configure(DEFAULT_HIGHLIGHT_CAPTURES);
280 Ok(config)
281 }
282 #[cfg(not(feature = "tree-sitter-html"))]
283 Err("HTML language support not enabled".to_string())
284 }
285 Self::CSS => {
286 #[cfg(feature = "tree-sitter-css")]
287 {
288 let mut config = HighlightConfiguration::new(
289 tree_sitter_css::LANGUAGE.into(),
290 "css",
291 tree_sitter_css::HIGHLIGHTS_QUERY,
292 "",
293 "",
294 )
295 .map_err(|e| format!("Failed to create CSS highlight config: {e}"))?;
296 config.configure(DEFAULT_HIGHLIGHT_CAPTURES);
297 Ok(config)
298 }
299 #[cfg(not(feature = "tree-sitter-css"))]
300 Err("CSS language support not enabled".to_string())
301 }
302 Self::C => {
303 #[cfg(feature = "tree-sitter-c")]
304 {
305 let mut config = HighlightConfiguration::new(
306 tree_sitter_c::LANGUAGE.into(),
307 "c",
308 tree_sitter_c::HIGHLIGHT_QUERY,
309 "",
310 "",
311 )
312 .map_err(|e| format!("Failed to create C highlight config: {e}"))?;
313 config.configure(DEFAULT_HIGHLIGHT_CAPTURES);
314 Ok(config)
315 }
316 #[cfg(not(feature = "tree-sitter-c"))]
317 Err("C language support not enabled".to_string())
318 }
319 Self::Cpp => {
320 #[cfg(feature = "tree-sitter-cpp")]
321 {
322 let mut config = HighlightConfiguration::new(
323 tree_sitter_cpp::LANGUAGE.into(),
324 "cpp",
325 tree_sitter_cpp::HIGHLIGHT_QUERY,
326 "",
327 "",
328 )
329 .map_err(|e| format!("Failed to create C++ highlight config: {e}"))?;
330 config.configure(DEFAULT_HIGHLIGHT_CAPTURES);
331 Ok(config)
332 }
333 #[cfg(not(feature = "tree-sitter-cpp"))]
334 Err("C++ language support not enabled".to_string())
335 }
336 Self::Go => {
337 #[cfg(feature = "tree-sitter-go")]
338 {
339 let mut config = HighlightConfiguration::new(
340 tree_sitter_go::LANGUAGE.into(),
341 "go",
342 tree_sitter_go::HIGHLIGHTS_QUERY,
343 "",
344 "",
345 )
346 .map_err(|e| format!("Failed to create Go highlight config: {e}"))?;
347 config.configure(DEFAULT_HIGHLIGHT_CAPTURES);
348 Ok(config)
349 }
350 #[cfg(not(feature = "tree-sitter-go"))]
351 Err("Go language support not enabled".to_string())
352 }
353 Self::Json => {
354 #[cfg(feature = "tree-sitter-json")]
355 {
356 let mut config = HighlightConfiguration::new(
357 tree_sitter_json::LANGUAGE.into(),
358 "json",
359 tree_sitter_json::HIGHLIGHTS_QUERY,
360 "",
361 "",
362 )
363 .map_err(|e| format!("Failed to create JSON highlight config: {e}"))?;
364 config.configure(DEFAULT_HIGHLIGHT_CAPTURES);
365 Ok(config)
366 }
367 #[cfg(not(feature = "tree-sitter-json"))]
368 Err("JSON language support not enabled".to_string())
369 }
370 Self::Jsonc => {
371 #[cfg(feature = "tree-sitter-json")]
376 {
377 let mut config = HighlightConfiguration::new(
378 tree_sitter_json::LANGUAGE.into(),
379 "jsonc",
380 tree_sitter_json::HIGHLIGHTS_QUERY,
381 "",
382 "",
383 )
384 .map_err(|e| format!("Failed to create JSONC highlight config: {e}"))?;
385 config.configure(DEFAULT_HIGHLIGHT_CAPTURES);
386 Ok(config)
387 }
388 #[cfg(not(feature = "tree-sitter-json"))]
389 Err("JSONC language support not enabled".to_string())
390 }
391 Self::Java => {
392 #[cfg(feature = "tree-sitter-java")]
393 {
394 let mut config = HighlightConfiguration::new(
395 tree_sitter_java::LANGUAGE.into(),
396 "java",
397 tree_sitter_java::HIGHLIGHTS_QUERY,
398 "",
399 "",
400 )
401 .map_err(|e| format!("Failed to create Java highlight config: {e}"))?;
402 config.configure(DEFAULT_HIGHLIGHT_CAPTURES);
403 Ok(config)
404 }
405 #[cfg(not(feature = "tree-sitter-java"))]
406 Err("Java language support not enabled".to_string())
407 }
408 Self::CSharp => {
409 #[cfg(feature = "tree-sitter-c-sharp")]
410 {
411 let mut config = HighlightConfiguration::new(
412 tree_sitter_c_sharp::LANGUAGE.into(),
413 "c_sharp",
414 "",
415 "",
416 "",
417 )
418 .map_err(|e| format!("Failed to create C# highlight config: {e}"))?;
419 config.configure(DEFAULT_HIGHLIGHT_CAPTURES);
420 Ok(config)
421 }
422 #[cfg(not(feature = "tree-sitter-c-sharp"))]
423 Err("C# language support not enabled".to_string())
424 }
425 Self::Php => {
426 #[cfg(feature = "tree-sitter-php")]
427 {
428 let mut config = HighlightConfiguration::new(
429 tree_sitter_php::LANGUAGE_PHP.into(),
430 "php",
431 tree_sitter_php::HIGHLIGHTS_QUERY,
432 "",
433 "",
434 )
435 .map_err(|e| format!("Failed to create PHP highlight config: {e}"))?;
436 config.configure(DEFAULT_HIGHLIGHT_CAPTURES);
437 Ok(config)
438 }
439 #[cfg(not(feature = "tree-sitter-php"))]
440 Err("PHP language support not enabled".to_string())
441 }
442 Self::Ruby => {
443 #[cfg(feature = "tree-sitter-ruby")]
444 {
445 let mut config = HighlightConfiguration::new(
446 tree_sitter_ruby::LANGUAGE.into(),
447 "ruby",
448 tree_sitter_ruby::HIGHLIGHTS_QUERY,
449 "",
450 "",
451 )
452 .map_err(|e| format!("Failed to create Ruby highlight config: {e}"))?;
453 config.configure(DEFAULT_HIGHLIGHT_CAPTURES);
454 Ok(config)
455 }
456 #[cfg(not(feature = "tree-sitter-ruby"))]
457 Err("Ruby language support not enabled".to_string())
458 }
459 Self::Bash => {
460 #[cfg(feature = "tree-sitter-bash")]
461 {
462 let mut config = HighlightConfiguration::new(
463 tree_sitter_bash::LANGUAGE.into(),
464 "bash",
465 tree_sitter_bash::HIGHLIGHT_QUERY,
466 "",
467 "",
468 )
469 .map_err(|e| format!("Failed to create Bash highlight config: {e}"))?;
470 config.configure(DEFAULT_HIGHLIGHT_CAPTURES);
471 Ok(config)
472 }
473 #[cfg(not(feature = "tree-sitter-bash"))]
474 Err("Bash language support not enabled".to_string())
475 }
476 Self::Lua => {
477 #[cfg(feature = "tree-sitter-lua")]
478 {
479 let mut config = HighlightConfiguration::new(
480 tree_sitter_lua::LANGUAGE.into(),
481 "lua",
482 tree_sitter_lua::HIGHLIGHTS_QUERY,
483 "",
484 "",
485 )
486 .map_err(|e| format!("Failed to create Lua highlight config: {e}"))?;
487 config.configure(DEFAULT_HIGHLIGHT_CAPTURES);
488 Ok(config)
489 }
490 #[cfg(not(feature = "tree-sitter-lua"))]
491 Err("Lua language support not enabled".to_string())
492 }
493 Self::Pascal => {
494 #[cfg(feature = "tree-sitter-pascal")]
495 {
496 let mut config = HighlightConfiguration::new(
497 tree_sitter_pascal::LANGUAGE.into(),
498 "pascal",
499 "",
500 "",
501 "",
502 )
503 .map_err(|e| format!("Failed to create Pascal highlight config: {e}"))?;
504 config.configure(DEFAULT_HIGHLIGHT_CAPTURES);
505 Ok(config)
506 }
507 #[cfg(not(feature = "tree-sitter-pascal"))]
508 Err("Pascal language support not enabled".to_string())
509 }
510 Self::Odin => {
511 #[cfg(feature = "tree-sitter-odin")]
512 {
513 let mut config = HighlightConfiguration::new(
514 tree_sitter_odin::LANGUAGE.into(),
515 "odin",
516 "",
517 "",
518 "",
519 )
520 .map_err(|e| format!("Failed to create Odin highlight config: {e}"))?;
521 config.configure(DEFAULT_HIGHLIGHT_CAPTURES);
522 Ok(config)
523 }
524 #[cfg(not(feature = "tree-sitter-odin"))]
525 Err("Odin language support not enabled".to_string())
526 }
527 }
528 }
529
530 pub fn highlight_category(&self, index: usize) -> Option<HighlightCategory> {
532 match self {
533 Self::TypeScript => HighlightCategory::from_typescript_index(index),
534 _ => HighlightCategory::from_default_index(index),
535 }
536 }
537}
538
539impl Language {
540 pub fn all() -> &'static [Language] {
542 &[
543 Language::Rust,
544 Language::Python,
545 Language::JavaScript,
546 Language::TypeScript,
547 Language::HTML,
548 Language::CSS,
549 Language::C,
550 Language::Cpp,
551 Language::Go,
552 Language::Json,
553 Language::Jsonc,
554 Language::Java,
555 Language::CSharp,
556 Language::Php,
557 Language::Ruby,
558 Language::Bash,
559 Language::Lua,
560 Language::Pascal,
561 Language::Odin,
562 ]
563 }
564
565 pub fn id(&self) -> &'static str {
567 match self {
568 Self::Rust => "rust",
569 Self::Python => "python",
570 Self::JavaScript => "javascript",
571 Self::TypeScript => "typescript",
572 Self::HTML => "html",
573 Self::CSS => "css",
574 Self::C => "c",
575 Self::Cpp => "cpp",
576 Self::Go => "go",
577 Self::Json => "json",
578 Self::Jsonc => "jsonc",
579 Self::Java => "java",
580 Self::CSharp => "csharp",
581 Self::Php => "php",
582 Self::Ruby => "ruby",
583 Self::Bash => "bash",
584 Self::Lua => "lua",
585 Self::Pascal => "pascal",
586 Self::Odin => "odin",
587 }
588 }
589
590 pub fn lsp_language_id(&self, path: &Path) -> &'static str {
598 let ext = path.extension().and_then(|e| e.to_str()).unwrap_or("");
599 match (self, ext) {
600 (Self::TypeScript, "tsx") => "typescriptreact",
601 (Self::JavaScript, "jsx") => "javascriptreact",
602 _ => self.id(),
603 }
604 }
605
606 pub fn extensions(&self) -> &'static [&'static str] {
612 match self {
613 Self::Rust => &["rs"],
614 Self::Python => &["py"],
615 Self::JavaScript => &["js", "jsx", "mjs", "cjs"],
616 Self::TypeScript => &["ts", "tsx", "mts", "cts"],
617 Self::HTML => &["html"],
618 Self::CSS => &["css"],
619 Self::C => &["c", "h"],
620 Self::Cpp => &["cpp", "hpp", "cc", "hh", "cxx", "hxx", "cppm", "ixx"],
621 Self::Go => &["go"],
622 Self::Json => &["json"],
623 Self::Jsonc => &["jsonc"],
624 Self::Java => &["java"],
625 Self::CSharp => &["cs"],
626 Self::Php => &["php"],
627 Self::Ruby => &["rb"],
628 Self::Bash => &["sh", "bash"],
629 Self::Lua => &["lua"],
630 Self::Pascal => &["pas", "p"],
631 Self::Odin => &["odin"],
632 }
633 }
634
635 pub fn display_name(&self) -> &'static str {
637 match self {
638 Self::Rust => "Rust",
639 Self::Python => "Python",
640 Self::JavaScript => "JavaScript",
641 Self::TypeScript => "TypeScript",
642 Self::HTML => "HTML",
643 Self::CSS => "CSS",
644 Self::C => "C",
645 Self::Cpp => "C++",
646 Self::Go => "Go",
647 Self::Json => "JSON",
648 Self::Jsonc => "JSON with Comments",
649 Self::Java => "Java",
650 Self::CSharp => "C#",
651 Self::Php => "PHP",
652 Self::Ruby => "Ruby",
653 Self::Bash => "Bash",
654 Self::Lua => "Lua",
655 Self::Pascal => "Pascal",
656 Self::Odin => "Odin",
657 }
658 }
659
660 pub fn from_id(id: &str) -> Option<Self> {
662 let id_lower = id.to_lowercase();
663 match id_lower.as_str() {
664 "rust" => Some(Self::Rust),
665 "python" => Some(Self::Python),
666 "javascript" => Some(Self::JavaScript),
667 "typescript" => Some(Self::TypeScript),
668 "html" => Some(Self::HTML),
669 "css" => Some(Self::CSS),
670 "c" => Some(Self::C),
671 "cpp" | "c++" => Some(Self::Cpp),
672 "go" => Some(Self::Go),
673 "json" => Some(Self::Json),
674 "jsonc" => Some(Self::Jsonc),
675 "java" => Some(Self::Java),
676 "c_sharp" | "c#" | "csharp" => Some(Self::CSharp),
677 "php" => Some(Self::Php),
678 "ruby" => Some(Self::Ruby),
679 "bash" => Some(Self::Bash),
680 "lua" => Some(Self::Lua),
681 "pascal" => Some(Self::Pascal),
682 "odin" => Some(Self::Odin),
683 _ => None,
684 }
685 }
686
687 pub fn from_name(name: &str) -> Option<Self> {
696 for lang in Self::all() {
698 if lang.display_name() == name {
699 return Some(*lang);
700 }
701 }
702
703 let name_lower = name.to_lowercase();
705 match name_lower.as_str() {
706 "rust" => Some(Self::Rust),
707 "python" => Some(Self::Python),
708 "javascript" | "javascript (babel)" => Some(Self::JavaScript),
709 "typescript" | "typescriptreact" => Some(Self::TypeScript),
710 "html" => Some(Self::HTML),
711 "css" => Some(Self::CSS),
712 "c" => Some(Self::C),
713 "c++" => Some(Self::Cpp),
714 "go" | "golang" => Some(Self::Go),
715 "json" => Some(Self::Json),
716 "jsonc" | "json with comments" => Some(Self::Jsonc),
717 "java" => Some(Self::Java),
718 "c#" => Some(Self::CSharp),
719 "php" => Some(Self::Php),
720 "ruby" => Some(Self::Ruby),
721 "lua" => Some(Self::Lua),
722 "pascal" => Some(Self::Pascal),
723 "odin" => Some(Self::Odin),
724 _ => {
725 if name_lower.contains("bash") || name_lower.contains("shell") {
727 return Some(Self::Bash);
728 }
729 None
730 }
731 }
732 }
733}
734
735impl std::fmt::Display for Language {
736 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
737 write!(f, "{}", self.id())
738 }
739}
740
741const DEFAULT_HIGHLIGHT_CAPTURES: &[&str] = &[
742 "attribute",
743 "comment",
744 "constant",
745 "function",
746 "keyword",
747 "number",
748 "operator",
749 "punctuation.bracket",
750 "punctuation.delimiter",
751 "property",
752 "string",
753 "type",
754 "variable",
755];
756
757const TYPESCRIPT_HIGHLIGHT_CAPTURES: &[&str] = &[
758 "attribute",
759 "comment",
760 "constant",
761 "constant.builtin",
762 "constructor",
763 "embedded",
764 "function",
765 "function.builtin",
766 "function.method",
767 "keyword",
768 "number",
769 "operator",
770 "property",
771 "punctuation.bracket",
772 "punctuation.delimiter",
773 "punctuation.special",
774 "string",
775 "string.special",
776 "type",
777 "type.builtin",
778 "variable",
779 "variable.builtin",
780 "variable.parameter",
781];
782
783#[cfg(test)]
784mod tests {
785 use super::*;
786 use std::path::Path;
787
788 #[test]
789 fn test_lsp_language_id_tsx() {
790 let lang = Language::TypeScript;
791 assert_eq!(
792 lang.lsp_language_id(Path::new("app.tsx")),
793 "typescriptreact"
794 );
795 }
796
797 #[test]
798 fn test_lsp_language_id_ts() {
799 let lang = Language::TypeScript;
800 assert_eq!(lang.lsp_language_id(Path::new("app.ts")), "typescript");
801 }
802
803 #[test]
804 fn test_lsp_language_id_jsx() {
805 let lang = Language::JavaScript;
806 assert_eq!(
807 lang.lsp_language_id(Path::new("component.jsx")),
808 "javascriptreact"
809 );
810 }
811
812 #[test]
813 fn test_lsp_language_id_js() {
814 let lang = Language::JavaScript;
815 assert_eq!(lang.lsp_language_id(Path::new("app.js")), "javascript");
816 }
817
818 #[test]
819 fn test_lsp_language_id_csharp() {
820 let lang = Language::CSharp;
821 assert_eq!(lang.lsp_language_id(Path::new("main.cs")), "csharp");
822 }
823
824 #[test]
825 fn test_lsp_language_id_other_languages() {
826 assert_eq!(Language::Rust.lsp_language_id(Path::new("main.rs")), "rust");
827 assert_eq!(
828 Language::Python.lsp_language_id(Path::new("script.py")),
829 "python"
830 );
831 assert_eq!(Language::Go.lsp_language_id(Path::new("main.go")), "go");
832 }
833
834 #[test]
835 fn test_csharp_id_matches_config_key() {
836 assert_eq!(Language::CSharp.id(), "csharp");
839 }
840
841 #[test]
845 fn test_from_path_matches_extensions() {
846 for lang in Language::all() {
847 for ext in lang.extensions() {
848 let path = std::path::PathBuf::from(format!("x.{}", ext));
849 let detected = Language::from_path(&path).unwrap_or_else(|| {
850 panic!(
851 "extension .{} listed by {:?} but from_path returned None",
852 ext, lang
853 )
854 });
855 assert_eq!(
856 detected, *lang,
857 "extension .{} listed by {:?} but from_path returned {:?}",
858 ext, lang, detected
859 );
860 }
861 }
862 }
863}