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