lib.rs

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