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