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 self::{deno::DenoSettings, elixir::ElixirSettings};
11
12mod c;
13mod csharp;
14mod css;
15mod deno;
16mod elixir;
17mod elm;
18mod erlang;
19mod gleam;
20mod go;
21mod haskell;
22mod html;
23mod json;
24#[cfg(feature = "plugin_runtime")]
25mod language_plugin;
26mod lua;
27mod nu;
28mod ocaml;
29mod php;
30mod purescript;
31mod python;
32mod ruby;
33mod rust;
34mod svelte;
35mod tailwind;
36mod toml;
37mod typescript;
38mod uiua;
39mod vue;
40mod yaml;
41mod zig;
42
43// 1. Add tree-sitter-{language} parser to zed crate
44// 2. Create a language directory in zed/crates/zed/src/languages and add the language to init function below
45// 3. Add config.toml to the newly created language directory using existing languages as a template
46// 4. Copy highlights from tree sitter repo for the language into a highlights.scm file.
47// Note: github highlights take the last match while zed takes the first
48// 5. Add indents.scm, outline.scm, and brackets.scm to implement indent on newline, outline/breadcrumbs,
49// and autoclosing brackets respectively
50// 6. If the language has injections add an injections.scm query file
51
52#[derive(RustEmbed)]
53#[folder = "src/languages"]
54#[exclude = "*.rs"]
55struct LanguageDir;
56
57pub fn init(
58 languages: Arc<LanguageRegistry>,
59 node_runtime: Arc<dyn NodeRuntime>,
60 cx: &mut AppContext,
61) {
62 ElixirSettings::register(cx);
63 DenoSettings::register(cx);
64
65 languages.add_grammars([
66 ("bash", tree_sitter_bash::language()),
67 ("beancount", tree_sitter_beancount::language()),
68 ("c", tree_sitter_c::language()),
69 ("c_sharp", tree_sitter_c_sharp::language()),
70 ("cpp", tree_sitter_cpp::language()),
71 ("css", tree_sitter_css::language()),
72 ("elixir", tree_sitter_elixir::language()),
73 ("elm", tree_sitter_elm::language()),
74 (
75 "embedded_template",
76 tree_sitter_embedded_template::language(),
77 ),
78 ("erlang", tree_sitter_erlang::language()),
79 ("gitcommit", tree_sitter_gitcommit::language()),
80 ("gleam", tree_sitter_gleam::language()),
81 ("glsl", tree_sitter_glsl::language()),
82 ("go", tree_sitter_go::language()),
83 ("gomod", tree_sitter_gomod::language()),
84 ("gowork", tree_sitter_gowork::language()),
85 ("haskell", tree_sitter_haskell::language()),
86 ("hcl", tree_sitter_hcl::language()),
87 ("heex", tree_sitter_heex::language()),
88 ("html", tree_sitter_html::language()),
89 ("json", tree_sitter_json::language()),
90 ("lua", tree_sitter_lua::language()),
91 ("markdown", tree_sitter_markdown::language()),
92 ("nix", tree_sitter_nix::language()),
93 ("nu", tree_sitter_nu::language()),
94 ("ocaml", tree_sitter_ocaml::language_ocaml()),
95 (
96 "ocaml_interface",
97 tree_sitter_ocaml::language_ocaml_interface(),
98 ),
99 ("php", tree_sitter_php::language_php()),
100 ("proto", tree_sitter_proto::language()),
101 #[cfg(not(target_os = "linux"))]
102 ("purescript", tree_sitter_purescript::language()),
103 ("python", tree_sitter_python::language()),
104 ("racket", tree_sitter_racket::language()),
105 ("ruby", tree_sitter_ruby::language()),
106 ("rust", tree_sitter_rust::language()),
107 ("scheme", tree_sitter_scheme::language()),
108 ("svelte", tree_sitter_svelte::language()),
109 ("toml", tree_sitter_toml::language()),
110 ("tsx", tree_sitter_typescript::language_tsx()),
111 ("typescript", tree_sitter_typescript::language_typescript()),
112 ("uiua", tree_sitter_uiua::language()),
113 ("vue", tree_sitter_vue::language()),
114 ("yaml", tree_sitter_yaml::language()),
115 ("zig", tree_sitter_zig::language()),
116 ]);
117
118 let language = |name: &'static str, adapters| {
119 languages.register(name, load_config(name), adapters, load_queries)
120 };
121
122 language("bash", vec![]);
123 language("beancount", vec![]);
124 language("c", vec![Arc::new(c::CLspAdapter) as Arc<dyn LspAdapter>]);
125 language("cpp", vec![Arc::new(c::CLspAdapter)]);
126 language("csharp", vec![Arc::new(csharp::OmniSharpAdapter {})]);
127 language(
128 "css",
129 vec![
130 Arc::new(css::CssLspAdapter::new(node_runtime.clone())),
131 Arc::new(tailwind::TailwindLspAdapter::new(node_runtime.clone())),
132 ],
133 );
134
135 match &ElixirSettings::get(None, cx).lsp {
136 elixir::ElixirLspSetting::ElixirLs => language(
137 "elixir",
138 vec![
139 Arc::new(elixir::ElixirLspAdapter),
140 Arc::new(tailwind::TailwindLspAdapter::new(node_runtime.clone())),
141 ],
142 ),
143 elixir::ElixirLspSetting::NextLs => {
144 language("elixir", vec![Arc::new(elixir::NextLspAdapter)])
145 }
146 elixir::ElixirLspSetting::Local { path, arguments } => language(
147 "elixir",
148 vec![Arc::new(elixir::LocalLspAdapter {
149 path: path.clone(),
150 arguments: arguments.clone(),
151 })],
152 ),
153 }
154 language("gitcommit", vec![]);
155 language("erlang", vec![Arc::new(erlang::ErlangLspAdapter)]);
156
157 language("gleam", vec![Arc::new(gleam::GleamLspAdapter)]);
158 language("go", vec![Arc::new(go::GoLspAdapter)]);
159 language("gomod", vec![]);
160 language("gowork", vec![]);
161 language("zig", vec![Arc::new(zig::ZlsAdapter)]);
162 language(
163 "heex",
164 vec![
165 Arc::new(elixir::ElixirLspAdapter),
166 Arc::new(tailwind::TailwindLspAdapter::new(node_runtime.clone())),
167 ],
168 );
169 language(
170 "json",
171 vec![Arc::new(json::JsonLspAdapter::new(
172 node_runtime.clone(),
173 languages.clone(),
174 ))],
175 );
176 language("markdown", vec![]);
177 language(
178 "python",
179 vec![Arc::new(python::PythonLspAdapter::new(
180 node_runtime.clone(),
181 ))],
182 );
183 language("rust", vec![Arc::new(rust::RustLspAdapter)]);
184 language("toml", vec![Arc::new(toml::TaploLspAdapter)]);
185 match &DenoSettings::get(None, cx).enable {
186 true => {
187 language(
188 "tsx",
189 vec![
190 Arc::new(deno::DenoLspAdapter::new()),
191 Arc::new(tailwind::TailwindLspAdapter::new(node_runtime.clone())),
192 ],
193 );
194 language("typescript", vec![Arc::new(deno::DenoLspAdapter::new())]);
195 language(
196 "javascript",
197 vec![
198 Arc::new(deno::DenoLspAdapter::new()),
199 Arc::new(tailwind::TailwindLspAdapter::new(node_runtime.clone())),
200 ],
201 );
202 }
203 false => {
204 language(
205 "tsx",
206 vec![
207 Arc::new(typescript::TypeScriptLspAdapter::new(node_runtime.clone())),
208 Arc::new(typescript::EsLintLspAdapter::new(node_runtime.clone())),
209 Arc::new(tailwind::TailwindLspAdapter::new(node_runtime.clone())),
210 ],
211 );
212 language(
213 "typescript",
214 vec![
215 Arc::new(typescript::TypeScriptLspAdapter::new(node_runtime.clone())),
216 Arc::new(typescript::EsLintLspAdapter::new(node_runtime.clone())),
217 ],
218 );
219 language(
220 "javascript",
221 vec![
222 Arc::new(typescript::TypeScriptLspAdapter::new(node_runtime.clone())),
223 Arc::new(typescript::EsLintLspAdapter::new(node_runtime.clone())),
224 Arc::new(tailwind::TailwindLspAdapter::new(node_runtime.clone())),
225 ],
226 );
227 }
228 }
229
230 language("haskell", vec![Arc::new(haskell::HaskellLanguageServer {})]);
231 language(
232 "html",
233 vec![
234 Arc::new(html::HtmlLspAdapter::new(node_runtime.clone())),
235 Arc::new(tailwind::TailwindLspAdapter::new(node_runtime.clone())),
236 ],
237 );
238 language("ruby", vec![Arc::new(ruby::RubyLanguageServer)]);
239 language(
240 "erb",
241 vec![
242 Arc::new(ruby::RubyLanguageServer),
243 Arc::new(tailwind::TailwindLspAdapter::new(node_runtime.clone())),
244 ],
245 );
246 language("scheme", vec![]);
247 language("racket", vec![]);
248 language("lua", vec![Arc::new(lua::LuaLspAdapter)]);
249 language(
250 "yaml",
251 vec![Arc::new(yaml::YamlLspAdapter::new(node_runtime.clone()))],
252 );
253 language(
254 "svelte",
255 vec![
256 Arc::new(svelte::SvelteLspAdapter::new(node_runtime.clone())),
257 Arc::new(tailwind::TailwindLspAdapter::new(node_runtime.clone())),
258 ],
259 );
260 language(
261 "php",
262 vec![
263 Arc::new(php::IntelephenseLspAdapter::new(node_runtime.clone())),
264 Arc::new(tailwind::TailwindLspAdapter::new(node_runtime.clone())),
265 ],
266 );
267
268 // Produces a link error on linux due to duplicated `state_new` symbol
269 // todo!(linux): Restore purescript
270 #[cfg(not(target_os = "linux"))]
271 language(
272 "purescript",
273 vec![Arc::new(purescript::PurescriptLspAdapter::new(
274 node_runtime.clone(),
275 ))],
276 );
277 language(
278 "elm",
279 vec![Arc::new(elm::ElmLspAdapter::new(node_runtime.clone()))],
280 );
281 language("glsl", vec![]);
282 language("nix", vec![]);
283 language("nu", vec![Arc::new(nu::NuLanguageServer {})]);
284 language("ocaml", vec![Arc::new(ocaml::OCamlLspAdapter)]);
285 language("ocaml-interface", vec![Arc::new(ocaml::OCamlLspAdapter)]);
286 language("vue", vec![Arc::new(vue::VueLspAdapter::new(node_runtime))]);
287 language("uiua", vec![Arc::new(uiua::UiuaLanguageServer {})]);
288 language("proto", vec![]);
289 language("terraform", vec![]);
290 language("hcl", vec![]);
291}
292
293#[cfg(any(test, feature = "test-support"))]
294pub async fn language(
295 name: &str,
296 grammar: tree_sitter::Language,
297 lsp_adapter: Option<Arc<dyn LspAdapter>>,
298) -> Arc<Language> {
299 Arc::new(
300 Language::new(load_config(name), Some(grammar))
301 .with_lsp_adapters(lsp_adapter.into_iter().collect())
302 .await
303 .with_queries(load_queries(name))
304 .unwrap(),
305 )
306}
307
308fn load_config(name: &str) -> LanguageConfig {
309 ::toml::from_slice(
310 &LanguageDir::get(&format!("{}/config.toml", name))
311 .unwrap()
312 .data,
313 )
314 .with_context(|| format!("failed to load config.toml for language {name:?}"))
315 .unwrap()
316}
317
318fn load_queries(name: &str) -> LanguageQueries {
319 let mut result = LanguageQueries::default();
320 for path in LanguageDir::iter() {
321 if let Some(remainder) = path.strip_prefix(name).and_then(|p| p.strip_prefix('/')) {
322 if !remainder.ends_with(".scm") {
323 continue;
324 }
325 for (name, query) in QUERY_FILENAME_PREFIXES {
326 if remainder.starts_with(name) {
327 let contents = asset_str::<LanguageDir>(path.as_ref());
328 match query(&mut result) {
329 None => *query(&mut result) = Some(contents),
330 Some(r) => r.to_mut().push_str(contents.as_ref()),
331 }
332 }
333 }
334 }
335 }
336 result
337}