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![
177            Arc::new(ruby::RubyLanguageServer),
178            Arc::new(tailwind::TailwindLspAdapter::new(node_runtime.clone())),
179        ],
180    );
181    language("scheme", tree_sitter_scheme::language(), vec![]);
182    language("racket", tree_sitter_racket::language(), vec![]);
183    language(
184        "lua",
185        tree_sitter_lua::language(),
186        vec![Arc::new(lua::LuaLspAdapter)],
187    );
188    language(
189        "yaml",
190        tree_sitter_yaml::language(),
191        vec![Arc::new(yaml::YamlLspAdapter::new(node_runtime.clone()))],
192    );
193    language(
194        "svelte",
195        tree_sitter_svelte::language(),
196        vec![
197            Arc::new(svelte::SvelteLspAdapter::new(node_runtime.clone())),
198            Arc::new(tailwind::TailwindLspAdapter::new(node_runtime.clone())),
199        ],
200    );
201    language(
202        "php",
203        tree_sitter_php::language(),
204        vec![
205            Arc::new(php::IntelephenseLspAdapter::new(node_runtime.clone())),
206            Arc::new(tailwind::TailwindLspAdapter::new(node_runtime.clone())),
207        ],
208    );
209
210    language("elm", tree_sitter_elm::language(), vec![]);
211    language("glsl", tree_sitter_glsl::language(), vec![]);
212    language("nix", tree_sitter_nix::language(), vec![]);
213    language("nu", tree_sitter_nu::language(), vec![]);
214    language(
215        "vue",
216        tree_sitter_vue::language(),
217        vec![Arc::new(vue::VueLspAdapter::new(node_runtime))],
218    );
219}
220
221#[cfg(any(test, feature = "test-support"))]
222pub async fn language(
223    name: &str,
224    grammar: tree_sitter::Language,
225    lsp_adapter: Option<Arc<dyn LspAdapter>>,
226) -> Arc<Language> {
227    Arc::new(
228        Language::new(load_config(name), Some(grammar))
229            .with_lsp_adapters(lsp_adapter.into_iter().collect())
230            .await
231            .with_queries(load_queries(name))
232            .unwrap(),
233    )
234}
235
236fn load_config(name: &str) -> LanguageConfig {
237    toml::from_slice(
238        &LanguageDir::get(&format!("{}/config.toml", name))
239            .unwrap()
240            .data,
241    )
242    .with_context(|| format!("failed to load config.toml for language {name:?}"))
243    .unwrap()
244}
245
246fn load_queries(name: &str) -> LanguageQueries {
247    LanguageQueries {
248        highlights: load_query(name, "/highlights"),
249        brackets: load_query(name, "/brackets"),
250        indents: load_query(name, "/indents"),
251        outline: load_query(name, "/outline"),
252        embedding: load_query(name, "/embedding"),
253        injections: load_query(name, "/injections"),
254        overrides: load_query(name, "/overrides"),
255    }
256}
257
258fn load_query(name: &str, filename_prefix: &str) -> Option<Cow<'static, str>> {
259    let mut result = None;
260    for path in LanguageDir::iter() {
261        if let Some(remainder) = path.strip_prefix(name) {
262            if remainder.starts_with(filename_prefix) {
263                let contents = asset_str::<LanguageDir>(path.as_ref());
264                match &mut result {
265                    None => result = Some(contents),
266                    Some(r) => r.to_mut().push_str(contents.as_ref()),
267                }
268            }
269        }
270    }
271    result
272}