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;
  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
233#[cfg(any(test, feature = "test-support"))]
234pub async fn language(
235    name: &str,
236    grammar: tree_sitter::Language,
237    lsp_adapter: Option<Arc<dyn LspAdapter>>,
238) -> Arc<Language> {
239    Arc::new(
240        Language::new(load_config(name), Some(grammar))
241            .with_lsp_adapters(lsp_adapter.into_iter().collect())
242            .await
243            .with_queries(load_queries(name))
244            .unwrap(),
245    )
246}
247
248fn load_config(name: &str) -> LanguageConfig {
249    toml::from_slice(
250        &LanguageDir::get(&format!("{}/config.toml", name))
251            .unwrap()
252            .data,
253    )
254    .with_context(|| format!("failed to load config.toml for language {name:?}"))
255    .unwrap()
256}
257
258fn load_queries(name: &str) -> LanguageQueries {
259    LanguageQueries {
260        highlights: load_query(name, "/highlights"),
261        brackets: load_query(name, "/brackets"),
262        indents: load_query(name, "/indents"),
263        outline: load_query(name, "/outline"),
264        embedding: load_query(name, "/embedding"),
265        injections: load_query(name, "/injections"),
266        overrides: load_query(name, "/overrides"),
267    }
268}
269
270fn load_query(name: &str, filename_prefix: &str) -> Option<Cow<'static, str>> {
271    let mut result = None;
272    for path in LanguageDir::iter() {
273        if let Some(remainder) = path.strip_prefix(name) {
274            if remainder.starts_with(filename_prefix) {
275                let contents = asset_str::<LanguageDir>(path.as_ref());
276                match &mut result {
277                    None => result = Some(contents),
278                    Some(r) => r.to_mut().push_str(contents.as_ref()),
279                }
280            }
281        }
282    }
283    result
284}