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