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