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