1use crate::matcher::{Matcher, MatcherExt, NodeMatch};
2use crate::replacer::Replacer;
3use crate::source::{Content, Edit as E, SgNode};
4use crate::Doc;
5use crate::Language;
6
7type Edit<D> = E<<D as Doc>::Source>;
8
9use std::borrow::Cow;
10
11#[derive(Debug, Clone, Copy, PartialEq, Eq)]
16pub struct Position {
17 line: usize,
19 byte_column: usize,
21 byte_offset: usize,
23}
24
25impl Position {
26 pub fn new(line: usize, byte_column: usize, byte_offset: usize) -> Self {
27 Self {
28 line,
29 byte_column,
30 byte_offset,
31 }
32 }
33 pub fn line(&self) -> usize {
34 self.line
35 }
36 pub fn column<D: Doc>(&self, node: &Node<'_, D>) -> usize {
39 let source = node.get_doc().get_source();
40 source.get_char_column(self.byte_column, self.byte_offset)
41 }
42 pub fn byte_point(&self) -> (usize, usize) {
43 (self.line, self.byte_column)
44 }
45}
46
47#[derive(Clone)]
50pub struct Root<D: Doc> {
51 pub(crate) doc: D,
52}
53
54impl<D: Doc> Root<D> {
55 pub fn doc(doc: D) -> Self {
56 Self { doc }
57 }
58
59 pub fn lang(&self) -> &D::Lang {
60 self.doc.get_lang()
61 }
62 pub fn root(&self) -> Node<D> {
64 Node {
65 inner: self.doc.root_node(),
66 root: self,
67 }
68 }
69
70 pub fn edit(&mut self, edit: Edit<D>) -> Result<&mut Self, String> {
72 self.doc.do_edit(&edit)?;
73 Ok(self)
74 }
75
76 pub fn replace<M: Matcher, R: Replacer<D>>(
77 &mut self,
78 pattern: M,
79 replacer: R,
80 ) -> Result<bool, String> {
81 let root = self.root();
82 if let Some(edit) = root.replace(pattern, replacer) {
83 drop(root); self.edit(edit)?;
85 Ok(true)
86 } else {
87 Ok(false)
88 }
89 }
90
91 pub fn adopt<'r>(&'r self, inner: D::Node<'r>) -> Node<'r, D> {
94 debug_assert!(self.check_lineage(&inner));
95 Node { inner, root: self }
96 }
97
98 fn check_lineage(&self, inner: &D::Node<'_>) -> bool {
99 let mut node = inner.clone();
100 while let Some(n) = node.parent() {
101 node = n;
102 }
103 node.node_id() == self.doc.root_node().node_id()
104 }
105
106 #[doc(hidden)]
108 pub unsafe fn readopt<'a: 'b, 'b>(&'a self, node: &mut Node<'b, D>) {
109 debug_assert!(self.check_lineage(&node.inner));
110 node.root = self;
111 }
112}
113
114#[derive(Clone)]
117pub struct Node<'r, D: Doc> {
118 pub(crate) inner: D::Node<'r>,
119 pub(crate) root: &'r Root<D>,
120}
121pub type KindId = u16;
122
123impl<'r, D: Doc> Node<'r, D> {
125 pub fn get_doc(&self) -> &'r D {
126 &self.root.doc
127 }
128 pub fn node_id(&self) -> usize {
129 self.inner.node_id()
130 }
131 pub fn is_leaf(&self) -> bool {
132 self.inner.is_leaf()
133 }
134 pub fn is_named_leaf(&self) -> bool {
138 self.inner.is_named_leaf()
139 }
140 pub fn is_error(&self) -> bool {
141 self.inner.is_error()
142 }
143 pub fn kind(&self) -> Cow<str> {
144 self.inner.kind()
145 }
146 pub fn kind_id(&self) -> KindId {
147 self.inner.kind_id()
148 }
149
150 pub fn is_named(&self) -> bool {
151 self.inner.is_named()
152 }
153 pub fn is_missing(&self) -> bool {
154 self.inner.is_missing()
155 }
156
157 pub fn range(&self) -> std::ops::Range<usize> {
159 self.inner.range()
160 }
161
162 pub fn start_pos(&self) -> Position {
164 self.inner.start_pos()
165 }
166
167 pub fn end_pos(&self) -> Position {
169 self.inner.end_pos()
170 }
171
172 pub fn text(&self) -> Cow<'r, str> {
173 self.root.doc.get_node_text(&self.inner)
174 }
175
176 pub fn lang(&self) -> &'r D::Lang {
177 self.root.lang()
178 }
179
180 pub fn get_inner_node(&self) -> D::Node<'r> {
182 self.inner.clone()
183 }
184
185 pub fn root(&self) -> &'r Root<D> {
186 self.root
187 }
188}
189
190impl<D: Doc> Node<'_, D> {
194 pub fn matches<M: Matcher>(&self, m: M) -> bool {
195 m.match_node(self.clone()).is_some()
196 }
197
198 pub fn inside<M: Matcher>(&self, m: M) -> bool {
199 self.ancestors().find_map(|n| m.match_node(n)).is_some()
200 }
201
202 pub fn has<M: Matcher>(&self, m: M) -> bool {
203 self.dfs().skip(1).find_map(|n| m.match_node(n)).is_some()
204 }
205
206 pub fn precedes<M: Matcher>(&self, m: M) -> bool {
207 self.next_all().find_map(|n| m.match_node(n)).is_some()
208 }
209
210 pub fn follows<M: Matcher>(&self, m: M) -> bool {
211 self.prev_all().find_map(|n| m.match_node(n)).is_some()
212 }
213}
214
215impl<'r, D: Doc> Node<'r, D> {
217 #[must_use]
218 pub fn parent(&self) -> Option<Self> {
219 let inner = self.inner.parent()?;
220 Some(Node {
221 inner,
222 root: self.root,
223 })
224 }
225
226 pub fn children(&self) -> impl ExactSizeIterator<Item = Node<'r, D>> + '_ {
227 self.inner.children().map(|inner| Node {
228 inner,
229 root: self.root,
230 })
231 }
232
233 #[must_use]
234 pub fn child(&self, nth: usize) -> Option<Self> {
235 let inner = self.inner.child(nth)?;
236 Some(Node {
237 inner,
238 root: self.root,
239 })
240 }
241
242 pub fn field(&self, name: &str) -> Option<Self> {
243 let inner = self.inner.field(name)?;
244 Some(Node {
245 inner,
246 root: self.root,
247 })
248 }
249
250 pub fn child_by_field_id(&self, field_id: u16) -> Option<Self> {
251 let inner = self.inner.child_by_field_id(field_id)?;
252 Some(Node {
253 inner,
254 root: self.root,
255 })
256 }
257
258 pub fn field_children(&self, name: &str) -> impl Iterator<Item = Node<'r, D>> + '_ {
259 let field_id = self.lang().field_to_id(name);
260 self.inner.field_children(field_id).map(|inner| Node {
261 inner,
262 root: self.root,
263 })
264 }
265
266 pub fn ancestors(&self) -> impl Iterator<Item = Node<'r, D>> + '_ {
269 let root = self.root.doc.root_node();
270 self.inner.ancestors(root).map(|inner| Node {
271 inner,
272 root: self.root,
273 })
274 }
275 #[must_use]
276 pub fn next(&self) -> Option<Self> {
277 let inner = self.inner.next()?;
278 Some(Node {
279 inner,
280 root: self.root,
281 })
282 }
283
284 pub fn next_all(&self) -> impl Iterator<Item = Node<'r, D>> + '_ {
289 self.inner.next_all().map(|inner| Node {
290 inner,
291 root: self.root,
292 })
293 }
294
295 #[must_use]
296 pub fn prev(&self) -> Option<Node<'r, D>> {
297 let inner = self.inner.prev()?;
298 Some(Node {
299 inner,
300 root: self.root,
301 })
302 }
303
304 pub fn prev_all(&self) -> impl Iterator<Item = Node<'r, D>> + '_ {
305 self.inner.prev_all().map(|inner| Node {
306 inner,
307 root: self.root,
308 })
309 }
310
311 pub fn dfs<'s>(&'s self) -> impl Iterator<Item = Node<'r, D>> + 's {
312 self.inner.dfs().map(|inner| Node {
313 inner,
314 root: self.root,
315 })
316 }
317
318 #[must_use]
319 pub fn find<M: Matcher>(&self, pat: M) -> Option<NodeMatch<'r, D>> {
320 pat.find_node(self.clone())
321 }
322
323 pub fn find_all<'s, M: Matcher + 's>(
324 &'s self,
325 pat: M,
326 ) -> impl Iterator<Item = NodeMatch<'r, D>> + 's {
327 let kinds = pat.potential_kinds();
328 self.dfs().filter_map(move |cand| {
329 if let Some(k) = &kinds {
330 if !k.contains(cand.kind_id().into()) {
331 return None;
332 }
333 }
334 pat.match_node(cand)
335 })
336 }
337}
338
339impl<D: Doc> Node<'_, D> {
341 pub fn replace<M: Matcher, R: Replacer<D>>(&self, matcher: M, replacer: R) -> Option<Edit<D>> {
342 let matched = matcher.find_node(self.clone())?;
343 let edit = matched.make_edit(&matcher, &replacer);
344 Some(edit)
345 }
346
347 pub fn after(&self) -> Edit<D> {
348 todo!()
349 }
350 pub fn before(&self) -> Edit<D> {
351 todo!()
352 }
353 pub fn append(&self) -> Edit<D> {
354 todo!()
355 }
356 pub fn prepend(&self) -> Edit<D> {
357 todo!()
358 }
359
360 pub fn empty(&self) -> Option<Edit<D>> {
362 let mut children = self.children().peekable();
363 let start = children.peek()?.range().start;
364 let end = children.last()?.range().end;
365 Some(Edit::<D> {
366 position: start,
367 deleted_length: end - start,
368 inserted_text: Vec::new(),
369 })
370 }
371
372 pub fn remove(&self) -> Edit<D> {
374 let range = self.range();
375 Edit::<D> {
376 position: range.start,
377 deleted_length: range.end - range.start,
378 inserted_text: Vec::new(),
379 }
380 }
381}
382
383#[cfg(test)]
384mod test {
385 use crate::language::{Language, Tsx};
386 use crate::tree_sitter::LanguageExt;
387 #[test]
388 fn test_is_leaf() {
389 let root = Tsx.ast_grep("let a = 123");
390 let node = root.root();
391 assert!(!node.is_leaf());
392 }
393
394 #[test]
395 fn test_children() {
396 let root = Tsx.ast_grep("let a = 123");
397 let node = root.root();
398 let children: Vec<_> = node.children().collect();
399 assert_eq!(children.len(), 1);
400 let texts: Vec<_> = children[0]
401 .children()
402 .map(|c| c.text().to_string())
403 .collect();
404 assert_eq!(texts, vec!["let", "a = 123"]);
405 }
406 #[test]
407 fn test_empty() {
408 let root = Tsx.ast_grep("let a = 123");
409 let node = root.root();
410 let edit = node.empty().unwrap();
411 assert_eq!(edit.inserted_text.len(), 0);
412 assert_eq!(edit.deleted_length, 11);
413 assert_eq!(edit.position, 0);
414 }
415
416 #[test]
417 fn test_field_children() {
418 let root = Tsx.ast_grep("let a = 123");
419 let node = root.root().find("let a = $A").unwrap();
420 let children: Vec<_> = node.field_children("kind").collect();
421 assert_eq!(children.len(), 1);
422 assert_eq!(children[0].text(), "let");
423 }
424
425 const MULTI_LINE: &str = "
426if (a) {
427 test(1)
428} else {
429 x
430}
431";
432
433 #[test]
434 fn test_display_context() {
435 let cases = [
437 ["i()", "i()", "", ""],
438 ["i()", "i", "", "()"],
439 [MULTI_LINE, "test", " ", "(1)"],
440 ];
441 for [src, matcher, lead, trail] in cases {
443 let root = Tsx.ast_grep(src);
444 let node = root.root().find(matcher).expect("should match");
445 let display = node.display_context(0, 0);
446 assert_eq!(display.leading, lead);
447 assert_eq!(display.trailing, trail);
448 }
449 }
450
451 #[test]
452 fn test_multi_line_context() {
453 let cases = [
454 ["i()", "i()", "", ""],
455 [MULTI_LINE, "test", "if (a) {\n ", "(1)\n} else {"],
456 ];
457 for [src, matcher, lead, trail] in cases {
459 let root = Tsx.ast_grep(src);
460 let node = root.root().find(matcher).expect("should match");
461 let display = node.display_context(1, 1);
462 assert_eq!(display.leading, lead);
463 assert_eq!(display.trailing, trail);
464 }
465 }
466
467 #[test]
468 fn test_replace_all_nested() {
469 let root = Tsx.ast_grep("Some(Some(1))");
470 let node = root.root();
471 let edits = node.replace_all("Some($A)", "$A");
472 assert_eq!(edits.len(), 1);
473 assert_eq!(edits[0].inserted_text, "Some(1)".as_bytes());
474 }
475
476 #[test]
477 fn test_replace_all_multiple_sorted() {
478 let root = Tsx.ast_grep("Some(Some(1)); Some(2)");
479 let node = root.root();
480 let edits = node.replace_all("Some($A)", "$A");
481 assert_eq!(edits.len(), 2);
483 assert_eq!(edits[0].inserted_text, "Some(1)".as_bytes());
484 assert_eq!(edits[1].inserted_text, "2".as_bytes());
485 }
486
487 #[test]
488 fn test_inside() {
489 let root = Tsx.ast_grep("Some(Some(1)); Some(2)");
490 let root = root.root();
491 let node = root.find("Some(1)").expect("should exist");
492 assert!(node.inside("Some($A)"));
493 }
494 #[test]
495 fn test_has() {
496 let root = Tsx.ast_grep("Some(Some(1)); Some(2)");
497 let root = root.root();
498 let node = root.find("Some($A)").expect("should exist");
499 assert!(node.has("Some(1)"));
500 }
501 #[test]
502 fn precedes() {
503 let root = Tsx.ast_grep("Some(Some(1)); Some(2);");
504 let root = root.root();
505 let node = root.find("Some($A);").expect("should exist");
506 assert!(node.precedes("Some(2);"));
507 }
508 #[test]
509 fn follows() {
510 let root = Tsx.ast_grep("Some(Some(1)); Some(2);");
511 let root = root.root();
512 let node = root.find("Some(2);").expect("should exist");
513 assert!(node.follows("Some(Some(1));"));
514 }
515
516 #[test]
517 fn test_field() {
518 let root = Tsx.ast_grep("class A{}");
519 let root = root.root();
520 let node = root.find("class $C {}").expect("should exist");
521 assert!(node.field("name").is_some());
522 assert!(node.field("none").is_none());
523 }
524 #[test]
525 fn test_child_by_field_id() {
526 let root = Tsx.ast_grep("class A{}");
527 let root = root.root();
528 let node = root.find("class $C {}").expect("should exist");
529 let id = Tsx.field_to_id("name").unwrap();
530 assert!(node.child_by_field_id(id).is_some());
531 assert!(node.child_by_field_id(id + 1).is_none());
532 }
533
534 #[test]
535 fn test_remove() {
536 let root = Tsx.ast_grep("Some(Some(1)); Some(2);");
537 let root = root.root();
538 let node = root.find("Some(2);").expect("should exist");
539 let edit = node.remove();
540 assert_eq!(edit.position, 15);
541 assert_eq!(edit.deleted_length, 8);
542 }
543
544 #[test]
545 fn test_ascii_pos() {
546 let root = Tsx.ast_grep("a");
547 let root = root.root();
548 let node = root.find("$A").expect("should exist");
549 assert_eq!(node.start_pos().line(), 0);
550 assert_eq!(node.start_pos().column(&*node), 0);
551 assert_eq!(node.end_pos().line(), 0);
552 assert_eq!(node.end_pos().column(&*node), 1);
553 }
554
555 #[test]
556 fn test_unicode_pos() {
557 let root = Tsx.ast_grep("🦀");
558 let root = root.root();
559 let node = root.find("$A").expect("should exist");
560 assert_eq!(node.start_pos().line(), 0);
561 assert_eq!(node.start_pos().column(&*node), 0);
562 assert_eq!(node.end_pos().line(), 0);
563 assert_eq!(node.end_pos().column(&*node), 1);
564 let root = Tsx.ast_grep("\n 🦀🦀");
565 let root = root.root();
566 let node = root.find("$A").expect("should exist");
567 assert_eq!(node.start_pos().line(), 1);
568 assert_eq!(node.start_pos().column(&*node), 2);
569 assert_eq!(node.end_pos().line(), 1);
570 assert_eq!(node.end_pos().column(&*node), 4);
571 }
572}