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