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