languages.rs

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