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}