1use anyhow::Context;
2pub use language::*;
3use node_runtime::NodeRuntime;
4use rust_embed::RustEmbed;
5use std::{borrow::Cow, str, sync::Arc};
6use util::asset_str;
7
8mod c;
9mod elixir;
10mod go;
11mod html;
12mod json;
13#[cfg(feature = "plugin_runtime")]
14mod language_plugin;
15mod lua;
16mod php;
17mod python;
18mod ruby;
19mod rust;
20mod svelte;
21mod typescript;
22mod yaml;
23
24// 1. Add tree-sitter-{language} parser to zed crate
25// 2. Create a language directory in zed/crates/zed/src/languages and add the language to init function below
26// 3. Add config.toml to the newly created language directory using existing languages as a template
27// 4. Copy highlights from tree sitter repo for the language into a highlights.scm file.
28// Note: github highlights take the last match while zed takes the first
29// 5. Add indents.scm, outline.scm, and brackets.scm to implement indent on newline, outline/breadcrumbs,
30// and autoclosing brackets respectively
31// 6. If the language has injections add an injections.scm query file
32
33#[derive(RustEmbed)]
34#[folder = "src/languages"]
35#[exclude = "*.rs"]
36struct LanguageDir;
37
38pub fn init(languages: Arc<LanguageRegistry>, node_runtime: Arc<NodeRuntime>) {
39 let language = |name, grammar, adapters| {
40 languages.register(name, load_config(name), grammar, adapters, load_queries)
41 };
42
43 language("bash", tree_sitter_bash::language(), vec![]);
44 language(
45 "c",
46 tree_sitter_c::language(),
47 vec![Arc::new(c::CLspAdapter) as Arc<dyn LspAdapter>],
48 );
49 language(
50 "cpp",
51 tree_sitter_cpp::language(),
52 vec![Arc::new(c::CLspAdapter)],
53 );
54 language("css", tree_sitter_css::language(), vec![]);
55 language(
56 "elixir",
57 tree_sitter_elixir::language(),
58 vec![Arc::new(elixir::ElixirLspAdapter)],
59 );
60 language(
61 "go",
62 tree_sitter_go::language(),
63 vec![Arc::new(go::GoLspAdapter)],
64 );
65 language(
66 "heex",
67 tree_sitter_heex::language(),
68 vec![Arc::new(elixir::ElixirLspAdapter)],
69 );
70 language(
71 "json",
72 tree_sitter_json::language(),
73 vec![Arc::new(json::JsonLspAdapter::new(
74 node_runtime.clone(),
75 languages.clone(),
76 ))],
77 );
78 language("markdown", tree_sitter_markdown::language(), vec![]);
79 language(
80 "python",
81 tree_sitter_python::language(),
82 vec![Arc::new(python::PythonLspAdapter::new(
83 node_runtime.clone(),
84 ))],
85 );
86 language(
87 "rust",
88 tree_sitter_rust::language(),
89 vec![Arc::new(rust::RustLspAdapter)],
90 );
91 language("toml", tree_sitter_toml::language(), vec![]);
92 language(
93 "tsx",
94 tree_sitter_typescript::language_tsx(),
95 vec![
96 Arc::new(typescript::TypeScriptLspAdapter::new(node_runtime.clone())),
97 Arc::new(typescript::EsLintLspAdapter::new(node_runtime.clone())),
98 ],
99 );
100 language(
101 "typescript",
102 tree_sitter_typescript::language_typescript(),
103 vec![
104 Arc::new(typescript::TypeScriptLspAdapter::new(node_runtime.clone())),
105 Arc::new(typescript::EsLintLspAdapter::new(node_runtime.clone())),
106 ],
107 );
108 language(
109 "javascript",
110 tree_sitter_typescript::language_tsx(),
111 vec![
112 Arc::new(typescript::TypeScriptLspAdapter::new(node_runtime.clone())),
113 Arc::new(typescript::EsLintLspAdapter::new(node_runtime.clone())),
114 ],
115 );
116 language(
117 "html",
118 tree_sitter_html::language(),
119 vec![Arc::new(html::HtmlLspAdapter::new(node_runtime.clone()))],
120 );
121 language(
122 "ruby",
123 tree_sitter_ruby::language(),
124 vec![Arc::new(ruby::RubyLanguageServer)],
125 );
126 language(
127 "erb",
128 tree_sitter_embedded_template::language(),
129 vec![Arc::new(ruby::RubyLanguageServer)],
130 );
131 language("scheme", tree_sitter_scheme::language(), vec![]);
132 language("racket", tree_sitter_racket::language(), vec![]);
133 language(
134 "lua",
135 tree_sitter_lua::language(),
136 vec![Arc::new(lua::LuaLspAdapter)],
137 );
138 language(
139 "yaml",
140 tree_sitter_yaml::language(),
141 vec![Arc::new(yaml::YamlLspAdapter::new(node_runtime.clone()))],
142 );
143 language(
144 "svelte",
145 tree_sitter_svelte::language(),
146 vec![Arc::new(svelte::SvelteLspAdapter::new(
147 node_runtime.clone(),
148 ))],
149 );
150 language(
151 "php",
152 tree_sitter_php::language(),
153 vec![Arc::new(php::IntelephenseLspAdapter::new(node_runtime))],
154 );
155 language("elm", tree_sitter_elm::language(), vec![]);
156 language("glsl", tree_sitter_glsl::language(), vec![]);
157}
158
159#[cfg(any(test, feature = "test-support"))]
160pub async fn language(
161 name: &str,
162 grammar: tree_sitter::Language,
163 lsp_adapter: Option<Arc<dyn LspAdapter>>,
164) -> Arc<Language> {
165 Arc::new(
166 Language::new(load_config(name), Some(grammar))
167 .with_lsp_adapters(lsp_adapter.into_iter().collect())
168 .await
169 .with_queries(load_queries(name))
170 .unwrap(),
171 )
172}
173
174fn load_config(name: &str) -> LanguageConfig {
175 toml::from_slice(
176 &LanguageDir::get(&format!("{}/config.toml", name))
177 .unwrap()
178 .data,
179 )
180 .with_context(|| format!("failed to load config.toml for language {name:?}"))
181 .unwrap()
182}
183
184fn load_queries(name: &str) -> LanguageQueries {
185 LanguageQueries {
186 highlights: load_query(name, "/highlights"),
187 brackets: load_query(name, "/brackets"),
188 indents: load_query(name, "/indents"),
189 outline: load_query(name, "/outline"),
190 embedding: load_query(name, "/embedding"),
191 injections: load_query(name, "/injections"),
192 overrides: load_query(name, "/overrides"),
193 }
194}
195
196fn load_query(name: &str, filename_prefix: &str) -> Option<Cow<'static, str>> {
197 let mut result = None;
198 for path in LanguageDir::iter() {
199 if let Some(remainder) = path.strip_prefix(name) {
200 if remainder.starts_with(filename_prefix) {
201 let contents = asset_str::<LanguageDir>(path.as_ref());
202 match &mut result {
203 None => result = Some(contents),
204 Some(r) => r.to_mut().push_str(contents.as_ref()),
205 }
206 }
207 }
208 }
209 result
210}