1use gpui::executor::Background;
2pub use language::*;
3use rust_embed::RustEmbed;
4use std::{borrow::Cow, str, sync::Arc};
5use util::ResultExt;
6
7mod c;
8mod go;
9mod installation;
10mod language_plugin;
11mod python;
12mod rust;
13mod typescript;
14
15#[derive(RustEmbed)]
16#[folder = "src/languages"]
17#[exclude = "*.rs"]
18struct LanguageDir;
19
20pub async fn init(languages: Arc<LanguageRegistry>, executor: Arc<Background>) {
21 for (name, grammar, lsp_adapter) in [
22 (
23 "c",
24 tree_sitter_c::language(),
25 Some(CachedLspAdapter::new(c::CLspAdapter).await),
26 ),
27 (
28 "cpp",
29 tree_sitter_cpp::language(),
30 Some(CachedLspAdapter::new(c::CLspAdapter).await),
31 ),
32 (
33 "go",
34 tree_sitter_go::language(),
35 Some(CachedLspAdapter::new(go::GoLspAdapter).await),
36 ),
37 (
38 "json",
39 tree_sitter_json::language(),
40 match language_plugin::new_json(executor).await.log_err() {
41 Some(lang) => Some(CachedLspAdapter::new(lang).await),
42 None => None,
43 },
44 ),
45 (
46 "markdown",
47 tree_sitter_markdown::language(),
48 None, //
49 ),
50 (
51 "python",
52 tree_sitter_python::language(),
53 Some(CachedLspAdapter::new(python::PythonLspAdapter).await),
54 ),
55 (
56 "rust",
57 tree_sitter_rust::language(),
58 Some(CachedLspAdapter::new(rust::RustLspAdapter).await),
59 ),
60 (
61 "toml",
62 tree_sitter_toml::language(),
63 None, //
64 ),
65 (
66 "tsx",
67 tree_sitter_typescript::language_tsx(),
68 Some(CachedLspAdapter::new(typescript::TypeScriptLspAdapter).await),
69 ),
70 (
71 "typescript",
72 tree_sitter_typescript::language_typescript(),
73 Some(CachedLspAdapter::new(typescript::TypeScriptLspAdapter).await),
74 ),
75 (
76 "javascript",
77 tree_sitter_typescript::language_tsx(),
78 Some(CachedLspAdapter::new(typescript::TypeScriptLspAdapter).await),
79 ),
80 ] {
81 languages.add(Arc::new(language(name, grammar, lsp_adapter)));
82 }
83}
84
85pub(crate) fn language(
86 name: &str,
87 grammar: tree_sitter::Language,
88 lsp_adapter: Option<Arc<CachedLspAdapter>>,
89) -> Language {
90 let config = toml::from_slice(
91 &LanguageDir::get(&format!("{}/config.toml", name))
92 .unwrap()
93 .data,
94 )
95 .unwrap();
96 let mut language = Language::new(config, Some(grammar));
97
98 if let Some(query) = load_query(name, "/highlights") {
99 language = language
100 .with_highlights_query(query.as_ref())
101 .expect("failed to evaluate highlights query");
102 }
103 if let Some(query) = load_query(name, "/brackets") {
104 language = language
105 .with_brackets_query(query.as_ref())
106 .expect("failed to load brackets query");
107 }
108 if let Some(query) = load_query(name, "/indents") {
109 language = language
110 .with_indents_query(query.as_ref())
111 .expect("failed to load indents query");
112 }
113 if let Some(query) = load_query(name, "/outline") {
114 language = language
115 .with_outline_query(query.as_ref())
116 .expect("failed to load outline query");
117 }
118 if let Some(lsp_adapter) = lsp_adapter {
119 language = language.with_lsp_adapter(lsp_adapter)
120 }
121 language
122}
123
124fn load_query(name: &str, filename_prefix: &str) -> Option<Cow<'static, str>> {
125 let mut result = None;
126 for path in LanguageDir::iter() {
127 if let Some(remainder) = path.strip_prefix(name) {
128 if remainder.starts_with(filename_prefix) {
129 let contents = match LanguageDir::get(path.as_ref()).unwrap().data {
130 Cow::Borrowed(s) => Cow::Borrowed(str::from_utf8(s).unwrap()),
131 Cow::Owned(s) => Cow::Owned(String::from_utf8(s).unwrap()),
132 };
133 match &mut result {
134 None => result = Some(contents),
135 Some(r) => r.to_mut().push_str(contents.as_ref()),
136 }
137 }
138 }
139 }
140 result
141}