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