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