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