1use std::sync::Arc;
32
33use crate::code_index::SharedIndex;
34use crate::registry::{BuiltinRegistry, HostlibCapability, RegisteredBuiltin, SyncHandler};
35
36mod apply_node;
37mod batch_apply;
38mod bracket_balance;
39mod capabilities;
40mod changeset;
41mod dry_run;
42mod edit_common;
43mod function_body;
44mod fuzzy;
45mod health;
46mod imports;
47mod insert_at_anchor;
48mod language;
49mod mutation;
50mod outline;
51mod parse;
52mod parse_errors;
53mod search;
54mod structural_diff;
55mod symbols;
56mod symbols_call;
57mod types;
58mod undefined_names;
59mod unified_diff;
60
61pub use health::{Coverage, ParserHealth, ParserOperation, SourceObservation};
62pub use language::{EditCapabilities, Language, TEXT_PATCH_FALLBACK};
63pub use types::{OutlineItem, ParseError, ParsedNode, Symbol, SymbolKind, UndefinedName};
64
65pub mod api {
69 use std::path::Path;
70
71 use tree_sitter::Tree;
72
73 use crate::error::HostlibError;
74
75 use super::language::Language;
76 use super::outline::build_outline;
77 use super::parse::{parse_source, read_source};
78 use super::symbols::extract;
79 use super::types::{OutlineItem, Symbol};
80
81 pub fn symbols(
83 path: &Path,
84 language_hint: Option<&str>,
85 ) -> Result<(Language, Vec<Symbol>), HostlibError> {
86 let language = detect(path, language_hint)?;
87 let source = read_source(&path.to_string_lossy(), 0)?;
88 let tree = parse_source(&source, language)?;
89 Ok((language, extract(&tree, &source, language)))
90 }
91
92 pub fn outline(
94 path: &Path,
95 language_hint: Option<&str>,
96 ) -> Result<(Language, Vec<OutlineItem>), HostlibError> {
97 let (language, symbols) = symbols(path, language_hint)?;
98 Ok((language, build_outline(symbols)))
99 }
100
101 pub fn symbols_from_source(
104 source: &str,
105 language: Language,
106 ) -> Result<Vec<Symbol>, HostlibError> {
107 let tree = parse_source(source, language)?;
108 Ok(extract(&tree, source, language))
109 }
110
111 pub fn parse_tree(source: &str, language: Language) -> Result<Tree, HostlibError> {
116 parse_source(source, language)
117 }
118
119 pub fn parse_with_symbols(
123 source: &str,
124 language: Language,
125 ) -> Result<(Tree, Vec<Symbol>), HostlibError> {
126 let tree = parse_source(source, language)?;
127 let symbols = extract(&tree, source, language);
128 Ok((tree, symbols))
129 }
130
131 fn detect(path: &Path, language_hint: Option<&str>) -> Result<Language, HostlibError> {
132 Language::detect(path, language_hint).ok_or_else(|| HostlibError::InvalidParameter {
133 builtin: "ast::api",
134 param: "language",
135 message: format!(
136 "could not infer a tree-sitter grammar for `{}` \
137 (extension or `language` field unrecognized)",
138 path.display()
139 ),
140 })
141 }
142}
143
144#[derive(Default)]
148pub struct AstCapability;
149
150pub struct AstCapabilityWithCodeIndex {
156 code_index: SharedIndex,
157}
158
159impl AstCapabilityWithCodeIndex {
160 pub fn new(code_index: SharedIndex) -> Self {
163 Self { code_index }
164 }
165}
166
167impl HostlibCapability for AstCapability {
168 fn module_name(&self) -> &'static str {
169 "ast"
170 }
171
172 fn register_builtins(&self, registry: &mut BuiltinRegistry) {
173 register_ast_builtins(registry, None);
174 }
175}
176
177impl HostlibCapability for AstCapabilityWithCodeIndex {
178 fn module_name(&self) -> &'static str {
179 "ast"
180 }
181
182 fn register_builtins(&self, registry: &mut BuiltinRegistry) {
183 register_ast_builtins(registry, Some(self.code_index.clone()));
184 }
185}
186
187fn register_ast_builtins(registry: &mut BuiltinRegistry, code_index: Option<SharedIndex>) {
188 registry.register_fn("ast", "hostlib_ast_parse_file", "parse_file", parse::run);
189 registry.register_fn("ast", "hostlib_ast_symbols", "symbols", symbols_call::run);
190 registry.register_fn("ast", "hostlib_ast_outline", "outline", outline::run);
191 registry.register_fn(
192 "ast",
193 "hostlib_ast_parse_errors",
194 "parse_errors",
195 parse_errors::run,
196 );
197 registry.register_fn(
198 "ast",
199 "hostlib_ast_undefined_names",
200 "undefined_names",
201 undefined_names::run,
202 );
203 registry.register_fn(
204 "ast",
205 "hostlib_ast_function_body",
206 "function_body",
207 function_body::run_single,
208 );
209 registry.register_fn(
210 "ast",
211 "hostlib_ast_function_bodies",
212 "function_bodies",
213 function_body::run_bulk,
214 );
215 registry.register_fn(
216 "ast",
217 "hostlib_ast_extract_imports",
218 "extract_imports",
219 imports::run,
220 );
221 registry.register_fn(
222 "ast",
223 "hostlib_ast_symbol_extract",
224 "symbol_extract",
225 mutation::run_extract,
226 );
227 registry.register_fn(
228 "ast",
229 "hostlib_ast_symbol_delete",
230 "symbol_delete",
231 mutation::run_delete,
232 );
233 registry.register_fn(
234 "ast",
235 "hostlib_ast_symbol_replace",
236 "symbol_replace",
237 mutation::run_replace,
238 );
239 registry.register_fn(
240 "ast",
241 "hostlib_ast_bracket_balance",
242 "bracket_balance",
243 bracket_balance::run,
244 );
245 registry.register_fn(
248 "ast",
249 "hostlib_ast_apply_node",
250 "apply_node",
251 apply_node::run,
252 );
253 registry.register_fn(
254 "ast",
255 "hostlib_ast_insert_at_anchor",
256 "insert_at_anchor",
257 insert_at_anchor::run,
258 );
259 registry.register_fn(
262 "ast",
263 "hostlib_ast_batch_apply",
264 "batch_apply",
265 batch_apply::run,
266 );
267 register_dry_run(registry, code_index.clone());
268 register_changeset_summary(registry, code_index);
269 registry.register_fn("ast", "hostlib_ast_search", "search", search::run);
273 registry.register_fn(
274 "ast",
275 "hostlib_ast_structural_diff",
276 "structural_diff",
277 structural_diff::run,
278 );
279 registry.register_fn(
280 "ast",
281 "hostlib_ast_capabilities",
282 "capabilities",
283 capabilities::run,
284 );
285}
286
287fn register_dry_run(registry: &mut BuiltinRegistry, code_index: Option<SharedIndex>) {
288 match code_index {
289 Some(index) => {
290 let handler: SyncHandler =
291 Arc::new(move |args| dry_run::run_with_code_index(Some(&index), args));
292 registry.register(RegisteredBuiltin {
293 name: "hostlib_ast_dry_run",
294 module: "ast",
295 method: "dry_run",
296 handler,
297 });
298 }
299 None => registry.register_fn("ast", "hostlib_ast_dry_run", "dry_run", dry_run::run),
300 }
301}
302
303fn register_changeset_summary(registry: &mut BuiltinRegistry, code_index: Option<SharedIndex>) {
304 match code_index {
305 Some(index) => {
306 let handler: SyncHandler =
307 Arc::new(move |args| changeset::run_with_code_index(Some(&index), args));
308 registry.register(RegisteredBuiltin {
309 name: "hostlib_ast_changeset_summary",
310 module: "ast",
311 method: "changeset_summary",
312 handler,
313 });
314 }
315 None => registry.register_fn(
316 "ast",
317 "hostlib_ast_changeset_summary",
318 "changeset_summary",
319 changeset::run,
320 ),
321 }
322}