1use anyhow::Context;
2use gpui::AppContext;
3pub use language::*;
4use node_runtime::NodeRuntime;
5use rust_embed::RustEmbed;
6use settings::Settings;
7use std::{str, sync::Arc};
8use util::asset_str;
9
10use crate::{elixir::elixir_task_context, rust::RustContextProvider};
11
12use self::{deno::DenoSettings, elixir::ElixirSettings};
13
14mod c;
15mod clojure;
16mod csharp;
17mod css;
18mod dart;
19mod deno;
20mod elixir;
21mod elm;
22mod erlang;
23mod go;
24mod html;
25mod json;
26mod lua;
27mod nu;
28mod ocaml;
29mod php;
30mod python;
31mod ruby;
32mod rust;
33mod tailwind;
34mod terraform;
35mod toml;
36mod typescript;
37mod vue;
38mod yaml;
39
40// 1. Add tree-sitter-{language} parser to zed crate
41// 2. Create a language directory in zed/crates/zed/src/languages and add the language to init function below
42// 3. Add config.toml to the newly created language directory using existing languages as a template
43// 4. Copy highlights from tree sitter repo for the language into a highlights.scm file.
44// Note: github highlights take the last match while zed takes the first
45// 5. Add indents.scm, outline.scm, and brackets.scm to implement indent on newline, outline/breadcrumbs,
46// and autoclosing brackets respectively
47// 6. If the language has injections add an injections.scm query file
48
49#[derive(RustEmbed)]
50#[folder = "src/"]
51#[exclude = "*.rs"]
52struct LanguageDir;
53
54pub fn init(
55 languages: Arc<LanguageRegistry>,
56 node_runtime: Arc<dyn NodeRuntime>,
57 cx: &mut AppContext,
58) {
59 ElixirSettings::register(cx);
60 DenoSettings::register(cx);
61
62 languages.register_native_grammars([
63 ("bash", tree_sitter_bash::language()),
64 ("c", tree_sitter_c::language()),
65 ("c_sharp", tree_sitter_c_sharp::language()),
66 ("clojure", tree_sitter_clojure::language()),
67 ("cpp", tree_sitter_cpp::language()),
68 ("css", tree_sitter_css::language()),
69 ("elixir", tree_sitter_elixir::language()),
70 ("elm", tree_sitter_elm::language()),
71 (
72 "embedded_template",
73 tree_sitter_embedded_template::language(),
74 ),
75 ("erlang", tree_sitter_erlang::language()),
76 ("glsl", tree_sitter_glsl::language()),
77 ("go", tree_sitter_go::language()),
78 ("gomod", tree_sitter_gomod::language()),
79 ("gowork", tree_sitter_gowork::language()),
80 ("hcl", tree_sitter_hcl::language()),
81 ("heex", tree_sitter_heex::language()),
82 ("html", tree_sitter_html::language()),
83 ("jsdoc", tree_sitter_jsdoc::language()),
84 ("json", tree_sitter_json::language()),
85 ("lua", tree_sitter_lua::language()),
86 ("markdown", tree_sitter_markdown::language()),
87 ("nix", tree_sitter_nix::language()),
88 ("nu", tree_sitter_nu::language()),
89 ("ocaml", tree_sitter_ocaml::language_ocaml()),
90 (
91 "ocaml_interface",
92 tree_sitter_ocaml::language_ocaml_interface(),
93 ),
94 ("php", tree_sitter_php::language_php()),
95 ("proto", tree_sitter_proto::language()),
96 ("python", tree_sitter_python::language()),
97 ("racket", tree_sitter_racket::language()),
98 ("regex", tree_sitter_regex::language()),
99 ("ruby", tree_sitter_ruby::language()),
100 ("rust", tree_sitter_rust::language()),
101 ("scheme", tree_sitter_scheme::language()),
102 ("toml", tree_sitter_toml::language()),
103 ("tsx", tree_sitter_typescript::language_tsx()),
104 ("typescript", tree_sitter_typescript::language_typescript()),
105 ("vue", tree_sitter_vue::language()),
106 ("yaml", tree_sitter_yaml::language()),
107 ("dart", tree_sitter_dart::language()),
108 ]);
109
110 macro_rules! language {
111 ($name:literal) => {
112 let config = load_config($name);
113 languages.register_language(
114 config.name.clone(),
115 config.grammar.clone(),
116 config.matcher.clone(),
117 move || {
118 Ok((
119 config.clone(),
120 load_queries($name),
121 Some(Arc::new(language::SymbolContextProvider)),
122 ))
123 },
124 );
125 };
126 ($name:literal, $adapters:expr) => {
127 let config = load_config($name);
128 // typeck helper
129 let adapters: Vec<Arc<dyn LspAdapter>> = $adapters;
130 for adapter in adapters {
131 languages.register_lsp_adapter(config.name.clone(), adapter);
132 }
133 languages.register_language(
134 config.name.clone(),
135 config.grammar.clone(),
136 config.matcher.clone(),
137 move || {
138 Ok((
139 config.clone(),
140 load_queries($name),
141 Some(Arc::new(language::SymbolContextProvider)),
142 ))
143 },
144 );
145 };
146 ($name:literal, $adapters:expr, $context_provider:expr) => {
147 let config = load_config($name);
148 // typeck helper
149 let adapters: Vec<Arc<dyn LspAdapter>> = $adapters;
150 for adapter in adapters {
151 languages.register_lsp_adapter(config.name.clone(), adapter);
152 }
153 languages.register_language(
154 config.name.clone(),
155 config.grammar.clone(),
156 config.matcher.clone(),
157 move || {
158 Ok((
159 config.clone(),
160 load_queries($name),
161 Some(Arc::new($context_provider)),
162 ))
163 },
164 );
165 };
166 }
167 language!("bash");
168 language!("c", vec![Arc::new(c::CLspAdapter) as Arc<dyn LspAdapter>]);
169 language!("clojure", vec![Arc::new(clojure::ClojureLspAdapter)]);
170 language!("cpp", vec![Arc::new(c::CLspAdapter)]);
171 language!("csharp", vec![Arc::new(csharp::OmniSharpAdapter {})]);
172 language!(
173 "css",
174 vec![
175 Arc::new(css::CssLspAdapter::new(node_runtime.clone())),
176 Arc::new(tailwind::TailwindLspAdapter::new(node_runtime.clone())),
177 ]
178 );
179
180 match &ElixirSettings::get(None, cx).lsp {
181 elixir::ElixirLspSetting::ElixirLs => {
182 language!(
183 "elixir",
184 vec![
185 Arc::new(elixir::ElixirLspAdapter),
186 Arc::new(tailwind::TailwindLspAdapter::new(node_runtime.clone())),
187 ],
188 elixir_task_context()
189 );
190 }
191 elixir::ElixirLspSetting::NextLs => {
192 language!(
193 "elixir",
194 vec![Arc::new(elixir::NextLspAdapter)],
195 elixir_task_context()
196 );
197 }
198 elixir::ElixirLspSetting::Local { path, arguments } => {
199 language!(
200 "elixir",
201 vec![Arc::new(elixir::LocalLspAdapter {
202 path: path.clone(),
203 arguments: arguments.clone(),
204 })],
205 elixir_task_context()
206 );
207 }
208 }
209 language!("erlang", vec![Arc::new(erlang::ErlangLspAdapter)]);
210 language!("go", vec![Arc::new(go::GoLspAdapter)]);
211 language!("gomod");
212 language!("gowork");
213 language!(
214 "heex",
215 vec![
216 Arc::new(elixir::ElixirLspAdapter),
217 Arc::new(tailwind::TailwindLspAdapter::new(node_runtime.clone())),
218 ]
219 );
220 language!(
221 "json",
222 vec![Arc::new(json::JsonLspAdapter::new(
223 node_runtime.clone(),
224 languages.clone(),
225 ))]
226 );
227 language!("markdown");
228 language!(
229 "python",
230 vec![Arc::new(python::PythonLspAdapter::new(
231 node_runtime.clone(),
232 ))]
233 );
234 language!(
235 "rust",
236 vec![Arc::new(rust::RustLspAdapter)],
237 RustContextProvider
238 );
239 language!("toml", vec![Arc::new(toml::TaploLspAdapter)]);
240 match &DenoSettings::get(None, cx).enable {
241 true => {
242 language!(
243 "tsx",
244 vec![
245 Arc::new(deno::DenoLspAdapter::new()),
246 Arc::new(tailwind::TailwindLspAdapter::new(node_runtime.clone())),
247 ]
248 );
249 language!("typescript", vec![Arc::new(deno::DenoLspAdapter::new())]);
250 language!(
251 "javascript",
252 vec![
253 Arc::new(deno::DenoLspAdapter::new()),
254 Arc::new(tailwind::TailwindLspAdapter::new(node_runtime.clone())),
255 ]
256 );
257 language!("jsdoc", vec![Arc::new(deno::DenoLspAdapter::new())]);
258 }
259 false => {
260 language!(
261 "tsx",
262 vec![
263 Arc::new(typescript::TypeScriptLspAdapter::new(node_runtime.clone())),
264 Arc::new(typescript::EsLintLspAdapter::new(node_runtime.clone())),
265 Arc::new(tailwind::TailwindLspAdapter::new(node_runtime.clone())),
266 ]
267 );
268 language!(
269 "typescript",
270 vec![
271 Arc::new(typescript::TypeScriptLspAdapter::new(node_runtime.clone())),
272 Arc::new(typescript::EsLintLspAdapter::new(node_runtime.clone())),
273 ]
274 );
275 language!(
276 "javascript",
277 vec![
278 Arc::new(typescript::TypeScriptLspAdapter::new(node_runtime.clone())),
279 Arc::new(typescript::EsLintLspAdapter::new(node_runtime.clone())),
280 Arc::new(tailwind::TailwindLspAdapter::new(node_runtime.clone())),
281 ]
282 );
283 language!(
284 "jsdoc",
285 vec![Arc::new(typescript::TypeScriptLspAdapter::new(
286 node_runtime.clone(),
287 ))]
288 );
289 }
290 }
291
292 language!(
293 "html",
294 vec![
295 Arc::new(html::HtmlLspAdapter::new(node_runtime.clone())),
296 Arc::new(tailwind::TailwindLspAdapter::new(node_runtime.clone())),
297 ]
298 );
299 language!("ruby", vec![Arc::new(ruby::RubyLanguageServer)]);
300 language!(
301 "erb",
302 vec![
303 Arc::new(ruby::RubyLanguageServer),
304 Arc::new(tailwind::TailwindLspAdapter::new(node_runtime.clone())),
305 ]
306 );
307 language!("scheme");
308 language!("racket");
309 language!("regex");
310 language!("lua", vec![Arc::new(lua::LuaLspAdapter)]);
311 language!(
312 "yaml",
313 vec![Arc::new(yaml::YamlLspAdapter::new(node_runtime.clone()))]
314 );
315 language!(
316 "php",
317 vec![
318 Arc::new(php::IntelephenseLspAdapter::new(node_runtime.clone())),
319 Arc::new(tailwind::TailwindLspAdapter::new(node_runtime.clone())),
320 ]
321 );
322 language!(
323 "elm",
324 vec![Arc::new(elm::ElmLspAdapter::new(node_runtime.clone()))]
325 );
326 language!("glsl");
327 language!("nix");
328 language!("nu", vec![Arc::new(nu::NuLanguageServer {})]);
329 language!("ocaml", vec![Arc::new(ocaml::OCamlLspAdapter)]);
330 language!("ocaml-interface", vec![Arc::new(ocaml::OCamlLspAdapter)]);
331 language!(
332 "vue",
333 vec![Arc::new(vue::VueLspAdapter::new(node_runtime.clone()))]
334 );
335 language!("proto");
336 language!("terraform", vec![Arc::new(terraform::TerraformLspAdapter)]);
337 language!(
338 "terraform-vars",
339 vec![Arc::new(terraform::TerraformLspAdapter)]
340 );
341 language!("hcl", vec![]);
342 language!("dart", vec![Arc::new(dart::DartLanguageServer {})]);
343
344 languages.register_secondary_lsp_adapter(
345 "Astro".into(),
346 Arc::new(tailwind::TailwindLspAdapter::new(node_runtime.clone())),
347 );
348 languages.register_secondary_lsp_adapter(
349 "Svelte".into(),
350 Arc::new(tailwind::TailwindLspAdapter::new(node_runtime.clone())),
351 );
352}
353
354#[cfg(any(test, feature = "test-support"))]
355pub fn language(name: &str, grammar: tree_sitter::Language) -> Arc<Language> {
356 Arc::new(
357 Language::new(load_config(name), Some(grammar))
358 .with_queries(load_queries(name))
359 .unwrap(),
360 )
361}
362
363fn load_config(name: &str) -> LanguageConfig {
364 let config_toml = String::from_utf8(
365 LanguageDir::get(&format!("{}/config.toml", name))
366 .unwrap()
367 .data
368 .to_vec(),
369 )
370 .unwrap();
371
372 ::toml::from_str(&config_toml)
373 .with_context(|| format!("failed to load config.toml for language {name:?}"))
374 .unwrap()
375}
376
377fn load_queries(name: &str) -> LanguageQueries {
378 let mut result = LanguageQueries::default();
379 for path in LanguageDir::iter() {
380 if let Some(remainder) = path.strip_prefix(name).and_then(|p| p.strip_prefix('/')) {
381 if !remainder.ends_with(".scm") {
382 continue;
383 }
384 for (name, query) in QUERY_FILENAME_PREFIXES {
385 if remainder.starts_with(name) {
386 let contents = asset_str::<LanguageDir>(path.as_ref());
387 match query(&mut result) {
388 None => *query(&mut result) = Some(contents),
389 Some(r) => r.to_mut().push_str(contents.as_ref()),
390 }
391 }
392 }
393 }
394 }
395 result
396}