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 Property,
57 String,
58 Type,
59 Variable,
60}
61
62impl HighlightCategory {
63 pub fn from_default_index(index: usize) -> Option<Self> {
65 match index {
66 0 => Some(Self::Attribute),
67 1 => Some(Self::Comment),
68 2 => Some(Self::Constant),
69 3 => Some(Self::Function),
70 4 => Some(Self::Keyword),
71 5 => Some(Self::Number),
72 6 => Some(Self::Operator),
73 7 => Some(Self::Property),
74 8 => Some(Self::String),
75 9 => Some(Self::Type),
76 10 => Some(Self::Variable),
77 _ => None,
78 }
79 }
80
81 pub fn from_typescript_index(index: usize) -> Option<Self> {
83 match index {
84 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::Operator), 14 => Some(Self::Operator), 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,
108 }
109 }
110
111 pub fn theme_key(&self) -> &'static str {
113 match self {
114 Self::Keyword => "syntax.keyword",
115 Self::String => "syntax.string",
116 Self::Comment => "syntax.comment",
117 Self::Function => "syntax.function",
118 Self::Type => "syntax.type",
119 Self::Variable | Self::Property => "syntax.variable",
120 Self::Constant | Self::Number | Self::Attribute => "syntax.constant",
121 Self::Operator => "syntax.operator",
122 }
123 }
124
125 pub fn display_name(&self) -> &'static str {
127 match self {
128 Self::Attribute => "Attribute",
129 Self::Comment => "Comment",
130 Self::Constant => "Constant",
131 Self::Function => "Function",
132 Self::Keyword => "Keyword",
133 Self::Number => "Number",
134 Self::Operator => "Operator",
135 Self::Property => "Property",
136 Self::String => "String",
137 Self::Type => "Type",
138 Self::Variable => "Variable",
139 }
140 }
141}
142
143#[derive(Debug, Clone, Copy, PartialEq, Eq)]
145pub enum Language {
146 Rust,
147 Python,
148 JavaScript,
149 TypeScript,
150 HTML,
151 CSS,
152 C,
153 Cpp,
154 Go,
155 Json,
156 Java,
157 CSharp,
158 Php,
159 Ruby,
160 Bash,
161 Lua,
162 Pascal,
163 Odin,
164}
165
166impl Language {
167 pub fn from_path(path: &Path) -> Option<Self> {
169 match path.extension()?.to_str()? {
170 "rs" => Some(Language::Rust),
171 "py" => Some(Language::Python),
172 "js" | "jsx" => Some(Language::JavaScript),
173 "ts" | "tsx" => Some(Language::TypeScript),
174 "html" => Some(Language::HTML),
175 "css" => Some(Language::CSS),
176 "c" | "h" => Some(Language::C),
177 "cpp" | "hpp" | "cc" | "hh" | "cxx" | "hxx" | "cppm" | "ixx" => Some(Language::Cpp),
178 "go" => Some(Language::Go),
179 "json" => Some(Language::Json),
180 "java" => Some(Language::Java),
181 "cs" => Some(Language::CSharp),
182 "php" => Some(Language::Php),
183 "rb" => Some(Language::Ruby),
184 "sh" | "bash" => Some(Language::Bash),
185 "lua" => Some(Language::Lua),
186 "pas" | "p" => Some(Language::Pascal),
187 "odin" => Some(Language::Odin),
188 _ => None,
189 }
190 }
191
192 pub fn highlight_config(&self) -> Result<HighlightConfiguration, String> {
194 match self {
195 Self::Rust => {
196 #[cfg(feature = "tree-sitter-rust")]
197 {
198 let mut config = HighlightConfiguration::new(
199 tree_sitter_rust::LANGUAGE.into(),
200 "rust",
201 tree_sitter_rust::HIGHLIGHTS_QUERY,
202 "",
203 "",
204 )
205 .map_err(|e| format!("Failed to create Rust highlight config: {e}"))?;
206 config.configure(DEFAULT_HIGHLIGHT_CAPTURES);
207 Ok(config)
208 }
209 #[cfg(not(feature = "tree-sitter-rust"))]
210 Err("Rust language support not enabled".to_string())
211 }
212 Self::Python => {
213 #[cfg(feature = "tree-sitter-python")]
214 {
215 let mut config = HighlightConfiguration::new(
216 tree_sitter_python::LANGUAGE.into(),
217 "python",
218 tree_sitter_python::HIGHLIGHTS_QUERY,
219 "",
220 "",
221 )
222 .map_err(|e| format!("Failed to create Python highlight config: {e}"))?;
223 config.configure(DEFAULT_HIGHLIGHT_CAPTURES);
224 Ok(config)
225 }
226 #[cfg(not(feature = "tree-sitter-python"))]
227 Err("Python language support not enabled".to_string())
228 }
229 Self::JavaScript => {
230 #[cfg(feature = "tree-sitter-javascript")]
231 {
232 let mut config = HighlightConfiguration::new(
233 tree_sitter_javascript::LANGUAGE.into(),
234 "javascript",
235 tree_sitter_javascript::HIGHLIGHT_QUERY,
236 "",
237 "",
238 )
239 .map_err(|e| format!("Failed to create JavaScript highlight config: {e}"))?;
240 config.configure(DEFAULT_HIGHLIGHT_CAPTURES);
241 Ok(config)
242 }
243 #[cfg(not(feature = "tree-sitter-javascript"))]
244 Err("JavaScript language support not enabled".to_string())
245 }
246 Self::TypeScript => {
247 #[cfg(all(feature = "tree-sitter-typescript", feature = "tree-sitter-javascript"))]
248 {
249 let combined_highlights = format!(
250 "{}\n{}",
251 tree_sitter_typescript::HIGHLIGHTS_QUERY,
252 tree_sitter_javascript::HIGHLIGHT_QUERY
253 );
254 let mut config = HighlightConfiguration::new(
255 tree_sitter_typescript::LANGUAGE_TYPESCRIPT.into(),
256 "typescript",
257 &combined_highlights,
258 "",
259 tree_sitter_typescript::LOCALS_QUERY,
260 )
261 .map_err(|e| format!("Failed to create TypeScript highlight config: {e}"))?;
262 config.configure(TYPESCRIPT_HIGHLIGHT_CAPTURES);
263 Ok(config)
264 }
265 #[cfg(not(all(
266 feature = "tree-sitter-typescript",
267 feature = "tree-sitter-javascript"
268 )))]
269 Err("TypeScript language support not enabled".to_string())
270 }
271 Self::HTML => {
272 #[cfg(feature = "tree-sitter-html")]
273 {
274 let mut config = HighlightConfiguration::new(
275 tree_sitter_html::LANGUAGE.into(),
276 "html",
277 tree_sitter_html::HIGHLIGHTS_QUERY,
278 "",
279 "",
280 )
281 .map_err(|e| format!("Failed to create HTML highlight config: {e}"))?;
282 config.configure(DEFAULT_HIGHLIGHT_CAPTURES);
283 Ok(config)
284 }
285 #[cfg(not(feature = "tree-sitter-html"))]
286 Err("HTML language support not enabled".to_string())
287 }
288 Self::CSS => {
289 #[cfg(feature = "tree-sitter-css")]
290 {
291 let mut config = HighlightConfiguration::new(
292 tree_sitter_css::LANGUAGE.into(),
293 "css",
294 tree_sitter_css::HIGHLIGHTS_QUERY,
295 "",
296 "",
297 )
298 .map_err(|e| format!("Failed to create CSS highlight config: {e}"))?;
299 config.configure(DEFAULT_HIGHLIGHT_CAPTURES);
300 Ok(config)
301 }
302 #[cfg(not(feature = "tree-sitter-css"))]
303 Err("CSS language support not enabled".to_string())
304 }
305 Self::C => {
306 #[cfg(feature = "tree-sitter-c")]
307 {
308 let mut config = HighlightConfiguration::new(
309 tree_sitter_c::LANGUAGE.into(),
310 "c",
311 tree_sitter_c::HIGHLIGHT_QUERY,
312 "",
313 "",
314 )
315 .map_err(|e| format!("Failed to create C highlight config: {e}"))?;
316 config.configure(DEFAULT_HIGHLIGHT_CAPTURES);
317 Ok(config)
318 }
319 #[cfg(not(feature = "tree-sitter-c"))]
320 Err("C language support not enabled".to_string())
321 }
322 Self::Cpp => {
323 #[cfg(feature = "tree-sitter-cpp")]
324 {
325 let mut config = HighlightConfiguration::new(
326 tree_sitter_cpp::LANGUAGE.into(),
327 "cpp",
328 tree_sitter_cpp::HIGHLIGHT_QUERY,
329 "",
330 "",
331 )
332 .map_err(|e| format!("Failed to create C++ highlight config: {e}"))?;
333 config.configure(DEFAULT_HIGHLIGHT_CAPTURES);
334 Ok(config)
335 }
336 #[cfg(not(feature = "tree-sitter-cpp"))]
337 Err("C++ language support not enabled".to_string())
338 }
339 Self::Go => {
340 #[cfg(feature = "tree-sitter-go")]
341 {
342 let mut config = HighlightConfiguration::new(
343 tree_sitter_go::LANGUAGE.into(),
344 "go",
345 tree_sitter_go::HIGHLIGHTS_QUERY,
346 "",
347 "",
348 )
349 .map_err(|e| format!("Failed to create Go highlight config: {e}"))?;
350 config.configure(DEFAULT_HIGHLIGHT_CAPTURES);
351 Ok(config)
352 }
353 #[cfg(not(feature = "tree-sitter-go"))]
354 Err("Go language support not enabled".to_string())
355 }
356 Self::Json => {
357 #[cfg(feature = "tree-sitter-json")]
358 {
359 let mut config = HighlightConfiguration::new(
360 tree_sitter_json::LANGUAGE.into(),
361 "json",
362 tree_sitter_json::HIGHLIGHTS_QUERY,
363 "",
364 "",
365 )
366 .map_err(|e| format!("Failed to create JSON highlight config: {e}"))?;
367 config.configure(DEFAULT_HIGHLIGHT_CAPTURES);
368 Ok(config)
369 }
370 #[cfg(not(feature = "tree-sitter-json"))]
371 Err("JSON language support not enabled".to_string())
372 }
373 Self::Java => {
374 #[cfg(feature = "tree-sitter-java")]
375 {
376 let mut config = HighlightConfiguration::new(
377 tree_sitter_java::LANGUAGE.into(),
378 "java",
379 tree_sitter_java::HIGHLIGHTS_QUERY,
380 "",
381 "",
382 )
383 .map_err(|e| format!("Failed to create Java highlight config: {e}"))?;
384 config.configure(DEFAULT_HIGHLIGHT_CAPTURES);
385 Ok(config)
386 }
387 #[cfg(not(feature = "tree-sitter-java"))]
388 Err("Java language support not enabled".to_string())
389 }
390 Self::CSharp => {
391 #[cfg(feature = "tree-sitter-c-sharp")]
392 {
393 let mut config = HighlightConfiguration::new(
394 tree_sitter_c_sharp::LANGUAGE.into(),
395 "c_sharp",
396 "",
397 "",
398 "",
399 )
400 .map_err(|e| format!("Failed to create C# highlight config: {e}"))?;
401 config.configure(DEFAULT_HIGHLIGHT_CAPTURES);
402 Ok(config)
403 }
404 #[cfg(not(feature = "tree-sitter-c-sharp"))]
405 Err("C# language support not enabled".to_string())
406 }
407 Self::Php => {
408 #[cfg(feature = "tree-sitter-php")]
409 {
410 let mut config = HighlightConfiguration::new(
411 tree_sitter_php::LANGUAGE_PHP.into(),
412 "php",
413 tree_sitter_php::HIGHLIGHTS_QUERY,
414 "",
415 "",
416 )
417 .map_err(|e| format!("Failed to create PHP highlight config: {e}"))?;
418 config.configure(DEFAULT_HIGHLIGHT_CAPTURES);
419 Ok(config)
420 }
421 #[cfg(not(feature = "tree-sitter-php"))]
422 Err("PHP language support not enabled".to_string())
423 }
424 Self::Ruby => {
425 #[cfg(feature = "tree-sitter-ruby")]
426 {
427 let mut config = HighlightConfiguration::new(
428 tree_sitter_ruby::LANGUAGE.into(),
429 "ruby",
430 tree_sitter_ruby::HIGHLIGHTS_QUERY,
431 "",
432 "",
433 )
434 .map_err(|e| format!("Failed to create Ruby highlight config: {e}"))?;
435 config.configure(DEFAULT_HIGHLIGHT_CAPTURES);
436 Ok(config)
437 }
438 #[cfg(not(feature = "tree-sitter-ruby"))]
439 Err("Ruby language support not enabled".to_string())
440 }
441 Self::Bash => {
442 #[cfg(feature = "tree-sitter-bash")]
443 {
444 let mut config = HighlightConfiguration::new(
445 tree_sitter_bash::LANGUAGE.into(),
446 "bash",
447 tree_sitter_bash::HIGHLIGHT_QUERY,
448 "",
449 "",
450 )
451 .map_err(|e| format!("Failed to create Bash highlight config: {e}"))?;
452 config.configure(DEFAULT_HIGHLIGHT_CAPTURES);
453 Ok(config)
454 }
455 #[cfg(not(feature = "tree-sitter-bash"))]
456 Err("Bash language support not enabled".to_string())
457 }
458 Self::Lua => {
459 #[cfg(feature = "tree-sitter-lua")]
460 {
461 let mut config = HighlightConfiguration::new(
462 tree_sitter_lua::LANGUAGE.into(),
463 "lua",
464 tree_sitter_lua::HIGHLIGHTS_QUERY,
465 "",
466 "",
467 )
468 .map_err(|e| format!("Failed to create Lua highlight config: {e}"))?;
469 config.configure(DEFAULT_HIGHLIGHT_CAPTURES);
470 Ok(config)
471 }
472 #[cfg(not(feature = "tree-sitter-lua"))]
473 Err("Lua language support not enabled".to_string())
474 }
475 Self::Pascal => {
476 #[cfg(feature = "tree-sitter-pascal")]
477 {
478 let mut config = HighlightConfiguration::new(
479 tree_sitter_pascal::LANGUAGE.into(),
480 "pascal",
481 "",
482 "",
483 "",
484 )
485 .map_err(|e| format!("Failed to create Pascal highlight config: {e}"))?;
486 config.configure(DEFAULT_HIGHLIGHT_CAPTURES);
487 Ok(config)
488 }
489 #[cfg(not(feature = "tree-sitter-pascal"))]
490 Err("Pascal language support not enabled".to_string())
491 }
492 Self::Odin => {
493 #[cfg(feature = "tree-sitter-odin")]
494 {
495 let mut config = HighlightConfiguration::new(
496 tree_sitter_odin::LANGUAGE.into(),
497 "odin",
498 "",
499 "",
500 "",
501 )
502 .map_err(|e| format!("Failed to create Odin highlight config: {e}"))?;
503 config.configure(DEFAULT_HIGHLIGHT_CAPTURES);
504 Ok(config)
505 }
506 #[cfg(not(feature = "tree-sitter-odin"))]
507 Err("Odin language support not enabled".to_string())
508 }
509 }
510 }
511
512 pub fn highlight_category(&self, index: usize) -> Option<HighlightCategory> {
514 match self {
515 Self::TypeScript => HighlightCategory::from_typescript_index(index),
516 _ => HighlightCategory::from_default_index(index),
517 }
518 }
519}
520
521impl Language {
522 pub fn all() -> &'static [Language] {
524 &[
525 Language::Rust,
526 Language::Python,
527 Language::JavaScript,
528 Language::TypeScript,
529 Language::HTML,
530 Language::CSS,
531 Language::C,
532 Language::Cpp,
533 Language::Go,
534 Language::Json,
535 Language::Java,
536 Language::CSharp,
537 Language::Php,
538 Language::Ruby,
539 Language::Bash,
540 Language::Lua,
541 Language::Pascal,
542 Language::Odin,
543 ]
544 }
545
546 pub fn id(&self) -> &'static str {
548 match self {
549 Self::Rust => "rust",
550 Self::Python => "python",
551 Self::JavaScript => "javascript",
552 Self::TypeScript => "typescript",
553 Self::HTML => "html",
554 Self::CSS => "css",
555 Self::C => "c",
556 Self::Cpp => "cpp",
557 Self::Go => "go",
558 Self::Json => "json",
559 Self::Java => "java",
560 Self::CSharp => "c_sharp",
561 Self::Php => "php",
562 Self::Ruby => "ruby",
563 Self::Bash => "bash",
564 Self::Lua => "lua",
565 Self::Pascal => "pascal",
566 Self::Odin => "odin",
567 }
568 }
569
570 pub fn lsp_language_id(&self, path: &Path) -> &'static str {
578 let ext = path.extension().and_then(|e| e.to_str()).unwrap_or("");
579 match (self, ext) {
580 (Self::TypeScript, "tsx") => "typescriptreact",
581 (Self::JavaScript, "jsx") => "javascriptreact",
582 _ => self.id(),
583 }
584 }
585
586 pub fn display_name(&self) -> &'static str {
588 match self {
589 Self::Rust => "Rust",
590 Self::Python => "Python",
591 Self::JavaScript => "JavaScript",
592 Self::TypeScript => "TypeScript",
593 Self::HTML => "HTML",
594 Self::CSS => "CSS",
595 Self::C => "C",
596 Self::Cpp => "C++",
597 Self::Go => "Go",
598 Self::Json => "JSON",
599 Self::Java => "Java",
600 Self::CSharp => "C#",
601 Self::Php => "PHP",
602 Self::Ruby => "Ruby",
603 Self::Bash => "Bash",
604 Self::Lua => "Lua",
605 Self::Pascal => "Pascal",
606 Self::Odin => "Odin",
607 }
608 }
609
610 pub fn from_id(id: &str) -> Option<Self> {
612 let id_lower = id.to_lowercase();
613 match id_lower.as_str() {
614 "rust" => Some(Self::Rust),
615 "python" => Some(Self::Python),
616 "javascript" => Some(Self::JavaScript),
617 "typescript" => Some(Self::TypeScript),
618 "html" => Some(Self::HTML),
619 "css" => Some(Self::CSS),
620 "c" => Some(Self::C),
621 "cpp" | "c++" => Some(Self::Cpp),
622 "go" => Some(Self::Go),
623 "json" => Some(Self::Json),
624 "java" => Some(Self::Java),
625 "c_sharp" | "c#" | "csharp" => Some(Self::CSharp),
626 "php" => Some(Self::Php),
627 "ruby" => Some(Self::Ruby),
628 "bash" => Some(Self::Bash),
629 "lua" => Some(Self::Lua),
630 "pascal" => Some(Self::Pascal),
631 "odin" => Some(Self::Odin),
632 _ => None,
633 }
634 }
635
636 pub fn from_name(name: &str) -> Option<Self> {
645 for lang in Self::all() {
647 if lang.display_name() == name {
648 return Some(*lang);
649 }
650 }
651
652 let name_lower = name.to_lowercase();
654 match name_lower.as_str() {
655 "rust" => Some(Self::Rust),
656 "python" => Some(Self::Python),
657 "javascript" | "javascript (babel)" => Some(Self::JavaScript),
658 "typescript" | "typescriptreact" => Some(Self::TypeScript),
659 "html" => Some(Self::HTML),
660 "css" => Some(Self::CSS),
661 "c" => Some(Self::C),
662 "c++" => Some(Self::Cpp),
663 "go" | "golang" => Some(Self::Go),
664 "json" => Some(Self::Json),
665 "java" => Some(Self::Java),
666 "c#" => Some(Self::CSharp),
667 "php" => Some(Self::Php),
668 "ruby" => Some(Self::Ruby),
669 "lua" => Some(Self::Lua),
670 "pascal" => Some(Self::Pascal),
671 "odin" => Some(Self::Odin),
672 _ => {
673 if name_lower.contains("bash") || name_lower.contains("shell") {
675 return Some(Self::Bash);
676 }
677 None
678 }
679 }
680 }
681}
682
683impl std::fmt::Display for Language {
684 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
685 write!(f, "{}", self.id())
686 }
687}
688
689const DEFAULT_HIGHLIGHT_CAPTURES: &[&str] = &[
690 "attribute",
691 "comment",
692 "constant",
693 "function",
694 "keyword",
695 "number",
696 "operator",
697 "property",
698 "string",
699 "type",
700 "variable",
701];
702
703const TYPESCRIPT_HIGHLIGHT_CAPTURES: &[&str] = &[
704 "attribute",
705 "comment",
706 "constant",
707 "constant.builtin",
708 "constructor",
709 "embedded",
710 "function",
711 "function.builtin",
712 "function.method",
713 "keyword",
714 "number",
715 "operator",
716 "property",
717 "punctuation.bracket",
718 "punctuation.delimiter",
719 "punctuation.special",
720 "string",
721 "string.special",
722 "type",
723 "type.builtin",
724 "variable",
725 "variable.builtin",
726 "variable.parameter",
727];
728
729#[cfg(test)]
730mod tests {
731 use super::*;
732 use std::path::Path;
733
734 #[test]
735 fn test_lsp_language_id_tsx() {
736 let lang = Language::TypeScript;
737 assert_eq!(
738 lang.lsp_language_id(Path::new("app.tsx")),
739 "typescriptreact"
740 );
741 }
742
743 #[test]
744 fn test_lsp_language_id_ts() {
745 let lang = Language::TypeScript;
746 assert_eq!(lang.lsp_language_id(Path::new("app.ts")), "typescript");
747 }
748
749 #[test]
750 fn test_lsp_language_id_jsx() {
751 let lang = Language::JavaScript;
752 assert_eq!(
753 lang.lsp_language_id(Path::new("component.jsx")),
754 "javascriptreact"
755 );
756 }
757
758 #[test]
759 fn test_lsp_language_id_js() {
760 let lang = Language::JavaScript;
761 assert_eq!(lang.lsp_language_id(Path::new("app.js")), "javascript");
762 }
763
764 #[test]
765 fn test_lsp_language_id_other_languages() {
766 assert_eq!(Language::Rust.lsp_language_id(Path::new("main.rs")), "rust");
767 assert_eq!(
768 Language::Python.lsp_language_id(Path::new("script.py")),
769 "python"
770 );
771 assert_eq!(Language::Go.lsp_language_id(Path::new("main.go")), "go");
772 }
773}