languages.rs

  1use anyhow::Context;
  2use gpui::AppContext;
  3pub use language::*;
  4use node_runtime::NodeRuntime;
  5use rust_embed::RustEmbed;
  6use std::{borrow::Cow, str, sync::Arc};
  7use util::asset_str;
  8
  9use self::elixir::ElixirSettings;
 10
 11mod c;
 12mod css;
 13mod elixir;
 14mod go;
 15mod html;
 16mod json;
 17#[cfg(feature = "plugin_runtime")]
 18mod language_plugin;
 19mod lua;
 20mod nu;
 21mod php;
 22mod python;
 23mod ruby;
 24mod rust;
 25mod svelte;
 26mod tailwind;
 27mod typescript;
 28mod uiua;
 29mod vue;
 30mod yaml;
 31
 32// 1. Add tree-sitter-{language} parser to zed crate
 33// 2. Create a language directory in zed/crates/zed/src/languages and add the language to init function below
 34// 3. Add config.toml to the newly created language directory using existing languages as a template
 35// 4. Copy highlights from tree sitter repo for the language into a highlights.scm file.
 36//      Note: github highlights take the last match while zed takes the first
 37// 5. Add indents.scm, outline.scm, and brackets.scm to implement indent on newline, outline/breadcrumbs,
 38//    and autoclosing brackets respectively
 39// 6. If the language has injections add an injections.scm query file
 40
 41#[derive(RustEmbed)]
 42#[folder = "src/languages"]
 43#[exclude = "*.rs"]
 44struct LanguageDir;
 45
 46pub fn init(
 47    languages: Arc<LanguageRegistry>,
 48    node_runtime: Arc<dyn NodeRuntime>,
 49    cx: &mut AppContext,
 50) {
 51    settings::register::<elixir::ElixirSettings>(cx);
 52
 53    let language = |name, grammar, adapters| {
 54        languages.register(name, load_config(name), grammar, adapters, load_queries)
 55    };
 56
 57    language("bash", tree_sitter_bash::language(), vec![]);
 58    language(
 59        "c",
 60        tree_sitter_c::language(),
 61        vec![Arc::new(c::CLspAdapter) as Arc<dyn LspAdapter>],
 62    );
 63    language(
 64        "cpp",
 65        tree_sitter_cpp::language(),
 66        vec![Arc::new(c::CLspAdapter)],
 67    );
 68    language(
 69        "css",
 70        tree_sitter_css::language(),
 71        vec![
 72            Arc::new(css::CssLspAdapter::new(node_runtime.clone())),
 73            Arc::new(tailwind::TailwindLspAdapter::new(node_runtime.clone())),
 74        ],
 75    );
 76
 77    match &settings::get::<ElixirSettings>(cx).lsp {
 78        elixir::ElixirLspSetting::ElixirLs => language(
 79            "elixir",
 80            tree_sitter_elixir::language(),
 81            vec![
 82                Arc::new(elixir::ElixirLspAdapter),
 83                Arc::new(tailwind::TailwindLspAdapter::new(node_runtime.clone())),
 84            ],
 85        ),
 86        elixir::ElixirLspSetting::NextLs => language(
 87            "elixir",
 88            tree_sitter_elixir::language(),
 89            vec![Arc::new(elixir::NextLspAdapter)],
 90        ),
 91        elixir::ElixirLspSetting::Local { path, arguments } => language(
 92            "elixir",
 93            tree_sitter_elixir::language(),
 94            vec![Arc::new(elixir::LocalLspAdapter {
 95                path: path.clone(),
 96                arguments: arguments.clone(),
 97            })],
 98        ),
 99    }
100
101    language(
102        "go",
103        tree_sitter_go::language(),
104        vec![Arc::new(go::GoLspAdapter)],
105    );
106    language(
107        "heex",
108        tree_sitter_heex::language(),
109        vec![
110            Arc::new(elixir::ElixirLspAdapter),
111            Arc::new(tailwind::TailwindLspAdapter::new(node_runtime.clone())),
112        ],
113    );
114    language(
115        "json",
116        tree_sitter_json::language(),
117        vec![Arc::new(json::JsonLspAdapter::new(
118            node_runtime.clone(),
119            languages.clone(),
120        ))],
121    );
122    language("markdown", tree_sitter_markdown::language(), vec![]);
123    language(
124        "python",
125        tree_sitter_python::language(),
126        vec![Arc::new(python::PythonLspAdapter::new(
127            node_runtime.clone(),
128        ))],
129    );
130    language(
131        "rust",
132        tree_sitter_rust::language(),
133        vec![Arc::new(rust::RustLspAdapter)],
134    );
135    language("toml", tree_sitter_toml::language(), vec![]);
136    language(
137        "tsx",
138        tree_sitter_typescript::language_tsx(),
139        vec![
140            Arc::new(typescript::TypeScriptLspAdapter::new(node_runtime.clone())),
141            Arc::new(typescript::EsLintLspAdapter::new(node_runtime.clone())),
142            Arc::new(tailwind::TailwindLspAdapter::new(node_runtime.clone())),
143        ],
144    );
145    language(
146        "typescript",
147        tree_sitter_typescript::language_typescript(),
148        vec![
149            Arc::new(typescript::TypeScriptLspAdapter::new(node_runtime.clone())),
150            Arc::new(typescript::EsLintLspAdapter::new(node_runtime.clone())),
151        ],
152    );
153    language(
154        "javascript",
155        tree_sitter_typescript::language_tsx(),
156        vec![
157            Arc::new(typescript::TypeScriptLspAdapter::new(node_runtime.clone())),
158            Arc::new(typescript::EsLintLspAdapter::new(node_runtime.clone())),
159            Arc::new(tailwind::TailwindLspAdapter::new(node_runtime.clone())),
160        ],
161    );
162    language(
163        "html",
164        tree_sitter_html::language(),
165        vec![
166            Arc::new(html::HtmlLspAdapter::new(node_runtime.clone())),
167            Arc::new(tailwind::TailwindLspAdapter::new(node_runtime.clone())),
168        ],
169    );
170    language(
171        "ruby",
172        tree_sitter_ruby::language(),
173        vec![Arc::new(ruby::RubyLanguageServer)],
174    );
175    language(
176        "erb",
177        tree_sitter_embedded_template::language(),
178        vec![
179            Arc::new(ruby::RubyLanguageServer),
180            Arc::new(tailwind::TailwindLspAdapter::new(node_runtime.clone())),
181        ],
182    );
183    language("scheme", tree_sitter_scheme::language(), vec![]);
184    language("racket", tree_sitter_racket::language(), vec![]);
185    language(
186        "lua",
187        tree_sitter_lua::language(),
188        vec![Arc::new(lua::LuaLspAdapter)],
189    );
190    language(
191        "yaml",
192        tree_sitter_yaml::language(),
193        vec![Arc::new(yaml::YamlLspAdapter::new(node_runtime.clone()))],
194    );
195    language(
196        "svelte",
197        tree_sitter_svelte::language(),
198        vec![
199            Arc::new(svelte::SvelteLspAdapter::new(node_runtime.clone())),
200            Arc::new(tailwind::TailwindLspAdapter::new(node_runtime.clone())),
201        ],
202    );
203    language(
204        "php",
205        tree_sitter_php::language(),
206        vec![
207            Arc::new(php::IntelephenseLspAdapter::new(node_runtime.clone())),
208            Arc::new(tailwind::TailwindLspAdapter::new(node_runtime.clone())),
209        ],
210    );
211
212    language("elm", tree_sitter_elm::language(), vec![]);
213    language("glsl", tree_sitter_glsl::language(), vec![]);
214    language("nix", tree_sitter_nix::language(), vec![]);
215    language(
216        "nu",
217        tree_sitter_nu::language(),
218        vec![Arc::new(nu::NuLanguageServer {})],
219    );
220    language(
221        "vue",
222        tree_sitter_vue::language(),
223        vec![Arc::new(vue::VueLspAdapter::new(node_runtime))],
224    );
225    language(
226        "uiua",
227        tree_sitter_uiua::language(),
228        vec![Arc::new(uiua::UiuaLanguageServer {})],
229    );
230}
231
232#[cfg(any(test, feature = "test-support"))]
233pub async fn language(
234    name: &str,
235    grammar: tree_sitter::Language,
236    lsp_adapter: Option<Arc<dyn LspAdapter>>,
237) -> Arc<Language> {
238    Arc::new(
239        Language::new(load_config(name), Some(grammar))
240            .with_lsp_adapters(lsp_adapter.into_iter().collect())
241            .await
242            .with_queries(load_queries(name))
243            .unwrap(),
244    )
245}
246
247fn load_config(name: &str) -> LanguageConfig {
248    toml::from_slice(
249        &LanguageDir::get(&format!("{}/config.toml", name))
250            .unwrap()
251            .data,
252    )
253    .with_context(|| format!("failed to load config.toml for language {name:?}"))
254    .unwrap()
255}
256
257fn load_queries(name: &str) -> LanguageQueries {
258    LanguageQueries {
259        highlights: load_query(name, "/highlights"),
260        brackets: load_query(name, "/brackets"),
261        indents: load_query(name, "/indents"),
262        outline: load_query(name, "/outline"),
263        embedding: load_query(name, "/embedding"),
264        injections: load_query(name, "/injections"),
265        overrides: load_query(name, "/overrides"),
266    }
267}
268
269fn load_query(name: &str, filename_prefix: &str) -> Option<Cow<'static, str>> {
270    let mut result = None;
271    for path in LanguageDir::iter() {
272        if let Some(remainder) = path.strip_prefix(name) {
273            if remainder.starts_with(filename_prefix) {
274                let contents = asset_str::<LanguageDir>(path.as_ref());
275                match &mut result {
276                    None => result = Some(contents),
277                    Some(r) => r.to_mut().push_str(contents.as_ref()),
278                }
279            }
280        }
281    }
282    result
283}