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