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}