languages.rs

  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}