1use crate::Doc;
2use crate::Language;
3use crate::matcher::{Matcher, MatcherExt, NodeMatch};
4use crate::replacer::Replacer;
5use crate::source::{Content, Edit as E, SgNode};
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 pub fn is_extra(&self) -> bool {
157 self.inner.is_extra()
158 }
159
160 pub fn range(&self) -> std::ops::Range<usize> {
162 self.inner.range()
163 }
164
165 pub fn start_pos(&self) -> Position {
167 self.inner.start_pos()
168 }
169
170 pub fn end_pos(&self) -> Position {
172 self.inner.end_pos()
173 }
174
175 pub fn text(&self) -> Cow<'r, str> {
176 self.root.doc.get_node_text(&self.inner)
177 }
178
179 pub fn lang(&self) -> &'r D::Lang {
180 self.root.lang()
181 }
182
183 pub fn get_inner_node(&self) -> D::Node<'r> {
185 self.inner.clone()
186 }
187
188 pub fn root(&self) -> &'r Root<D> {
189 self.root
190 }
191}
192
193impl<D: Doc> Node<'_, D> {
197 pub fn matches<M: Matcher>(&self, m: M) -> bool {
198 m.match_node(self.clone()).is_some()
199 }
200
201 pub fn inside<M: Matcher>(&self, m: M) -> bool {
202 self.ancestors().find_map(|n| m.match_node(n)).is_some()
203 }
204
205 pub fn has<M: Matcher>(&self, m: M) -> bool {
206 self.dfs().skip(1).find_map(|n| m.match_node(n)).is_some()
207 }
208
209 pub fn precedes<M: Matcher>(&self, m: M) -> bool {
210 self.next_all().find_map(|n| m.match_node(n)).is_some()
211 }
212
213 pub fn follows<M: Matcher>(&self, m: M) -> bool {
214 self.prev_all().find_map(|n| m.match_node(n)).is_some()
215 }
216}
217
218impl<'r, D: Doc> Node<'r, D> {
220 #[must_use]
221 pub fn parent(&self) -> Option<Self> {
222 let inner = self.inner.parent()?;
223 Some(Node {
224 inner,
225 root: self.root,
226 })
227 }
228
229 pub fn children(&self) -> impl ExactSizeIterator<Item = Node<'r, D>> + '_ {
230 self.inner.children().map(|inner| Node {
231 inner,
232 root: self.root,
233 })
234 }
235
236 pub fn named_children(&self) -> impl Iterator<Item = Node<'r, D>> + '_ {
237 self.inner.named_children().map(|inner| Node {
238 inner,
239 root: self.root,
240 })
241 }
242
243 #[must_use]
244 pub fn child(&self, nth: usize) -> Option<Self> {
245 let inner = self.inner.child(nth)?;
246 Some(Node {
247 inner,
248 root: self.root,
249 })
250 }
251
252 pub fn field(&self, name: &str) -> Option<Self> {
253 let inner = self.inner.field(name)?;
254 Some(Node {
255 inner,
256 root: self.root,
257 })
258 }
259
260 pub fn child_by_field_id(&self, field_id: u16) -> Option<Self> {
261 let inner = self.inner.child_by_field_id(field_id)?;
262 Some(Node {
263 inner,
264 root: self.root,
265 })
266 }
267
268 pub fn field_children(&self, name: &str) -> impl Iterator<Item = Node<'r, D>> + '_ {
269 let field_id = self.lang().field_to_id(name);
270 self.inner.field_children(field_id).map(|inner| Node {
271 inner,
272 root: self.root,
273 })
274 }
275
276 pub fn ancestors(&self) -> impl Iterator<Item = Node<'r, D>> + '_ {
279 let root = self.root.doc.root_node();
280 self.inner.ancestors(root).map(|inner| Node {
281 inner,
282 root: self.root,
283 })
284 }
285 #[must_use]
286 pub fn next(&self) -> Option<Self> {
287 let inner = self.inner.next()?;
288 Some(Node {
289 inner,
290 root: self.root,
291 })
292 }
293
294 pub fn next_all(&self) -> impl Iterator<Item = Node<'r, D>> + '_ {
299 self.inner.next_all().map(|inner| Node {
300 inner,
301 root: self.root,
302 })
303 }
304
305 #[must_use]
306 pub fn prev(&self) -> Option<Node<'r, D>> {
307 let inner = self.inner.prev()?;
308 Some(Node {
309 inner,
310 root: self.root,
311 })
312 }
313
314 pub fn prev_all(&self) -> impl Iterator<Item = Node<'r, D>> + '_ {
315 self.inner.prev_all().map(|inner| Node {
316 inner,
317 root: self.root,
318 })
319 }
320
321 pub fn dfs<'s>(&'s self) -> impl Iterator<Item = Node<'r, D>> + 's {
322 self.inner.dfs().map(|inner| Node {
323 inner,
324 root: self.root,
325 })
326 }
327
328 #[must_use]
329 pub fn find<M: Matcher>(&self, pat: M) -> Option<NodeMatch<'r, D>> {
330 pat.find_node(self.clone())
331 }
332
333 pub fn find_all<'s, M: Matcher + 's>(
334 &'s self,
335 pat: M,
336 ) -> impl Iterator<Item = NodeMatch<'r, D>> + 's {
337 let kinds = pat.potential_kinds();
338 self.dfs().filter_map(move |cand| {
339 if let Some(k) = &kinds
340 && !k.contains(cand.kind_id().into())
341 {
342 return None;
343 }
344 pat.match_node(cand)
345 })
346 }
347}
348
349impl<D: Doc> Node<'_, D> {
351 pub fn replace<M: Matcher, R: Replacer<D>>(&self, matcher: M, replacer: R) -> Option<Edit<D>> {
352 let matched = matcher.find_node(self.clone())?;
353 let edit = matched.make_edit(&matcher, &replacer);
354 Some(edit)
355 }
356
357 pub fn after(&self) -> Edit<D> {
358 todo!()
359 }
360 pub fn before(&self) -> Edit<D> {
361 todo!()
362 }
363 pub fn append(&self) -> Edit<D> {
364 todo!()
365 }
366 pub fn prepend(&self) -> Edit<D> {
367 todo!()
368 }
369
370 pub fn empty(&self) -> Option<Edit<D>> {
372 let mut children = self.children().peekable();
373 let start = children.peek()?.range().start;
374 let end = children.last()?.range().end;
375 Some(Edit::<D> {
376 position: start,
377 deleted_length: end - start,
378 inserted_text: Vec::new(),
379 })
380 }
381
382 pub fn remove(&self) -> Edit<D> {
384 let range = self.range();
385 Edit::<D> {
386 position: range.start,
387 deleted_length: range.end - range.start,
388 inserted_text: Vec::new(),
389 }
390 }
391}
392
393#[cfg(test)]
394mod test {
395 use crate::language::{Language, Tsx};
396 use crate::tree_sitter::LanguageExt;
397 #[test]
398 fn test_is_leaf() {
399 let root = Tsx.ast_grep("let a = 123");
400 let node = root.root();
401 assert!(!node.is_leaf());
402 }
403
404 #[test]
405 fn test_children() {
406 let root = Tsx.ast_grep("let a = 123");
407 let node = root.root();
408 let children: Vec<_> = node.children().collect();
409 assert_eq!(children.len(), 1);
410 let texts: Vec<_> = children[0]
411 .children()
412 .map(|c| c.text().to_string())
413 .collect();
414 assert_eq!(texts, vec!["let", "a = 123"]);
415 }
416 #[test]
417 fn test_empty() {
418 let root = Tsx.ast_grep("let a = 123");
419 let node = root.root();
420 let edit = node.empty().unwrap();
421 assert_eq!(edit.inserted_text.len(), 0);
422 assert_eq!(edit.deleted_length, 11);
423 assert_eq!(edit.position, 0);
424 }
425
426 #[test]
427 fn test_field_children() {
428 let root = Tsx.ast_grep("let a = 123");
429 let node = root.root().find("let a = $A").unwrap();
430 let children: Vec<_> = node.field_children("kind").collect();
431 assert_eq!(children.len(), 1);
432 assert_eq!(children[0].text(), "let");
433 }
434
435 const MULTI_LINE: &str = "
436if (a) {
437 test(1)
438} else {
439 x
440}
441";
442
443 #[test]
444 fn test_display_context() {
445 let cases = [
447 ["i()", "i()", "", ""],
448 ["i()", "i", "", "()"],
449 [MULTI_LINE, "test", " ", "(1)"],
450 ];
451 for [src, matcher, lead, trail] in cases {
453 let root = Tsx.ast_grep(src);
454 let node = root.root().find(matcher).expect("should match");
455 let display = node.display_context(0, 0);
456 assert_eq!(display.leading, lead);
457 assert_eq!(display.trailing, trail);
458 }
459 }
460
461 #[test]
462 fn test_multi_line_context() {
463 let cases = [
464 ["i()", "i()", "", ""],
465 [MULTI_LINE, "test", "if (a) {\n ", "(1)\n} else {"],
466 ];
467 for [src, matcher, lead, trail] in cases {
469 let root = Tsx.ast_grep(src);
470 let node = root.root().find(matcher).expect("should match");
471 let display = node.display_context(1, 1);
472 assert_eq!(display.leading, lead);
473 assert_eq!(display.trailing, trail);
474 }
475 }
476
477 #[test]
478 fn test_replace_all_nested() {
479 let root = Tsx.ast_grep("Some(Some(1))");
480 let node = root.root();
481 let edits = node.replace_all("Some($A)", "$A");
482 assert_eq!(edits.len(), 1);
483 assert_eq!(edits[0].inserted_text, "Some(1)".as_bytes());
484 }
485
486 #[test]
487 fn test_replace_all_multiple_sorted() {
488 let root = Tsx.ast_grep("Some(Some(1)); Some(2)");
489 let node = root.root();
490 let edits = node.replace_all("Some($A)", "$A");
491 assert_eq!(edits.len(), 2);
493 assert_eq!(edits[0].inserted_text, "Some(1)".as_bytes());
494 assert_eq!(edits[1].inserted_text, "2".as_bytes());
495 }
496
497 #[test]
498 fn test_inside() {
499 let root = Tsx.ast_grep("Some(Some(1)); Some(2)");
500 let root = root.root();
501 let node = root.find("Some(1)").expect("should exist");
502 assert!(node.inside("Some($A)"));
503 }
504 #[test]
505 fn test_has() {
506 let root = Tsx.ast_grep("Some(Some(1)); Some(2)");
507 let root = root.root();
508 let node = root.find("Some($A)").expect("should exist");
509 assert!(node.has("Some(1)"));
510 }
511 #[test]
512 fn precedes() {
513 let root = Tsx.ast_grep("Some(Some(1)); Some(2);");
514 let root = root.root();
515 let node = root.find("Some($A);").expect("should exist");
516 assert!(node.precedes("Some(2);"));
517 }
518 #[test]
519 fn follows() {
520 let root = Tsx.ast_grep("Some(Some(1)); Some(2);");
521 let root = root.root();
522 let node = root.find("Some(2);").expect("should exist");
523 assert!(node.follows("Some(Some(1));"));
524 }
525
526 #[test]
527 fn test_field() {
528 let root = Tsx.ast_grep("class A{}");
529 let root = root.root();
530 let node = root.find("class $C {}").expect("should exist");
531 assert!(node.field("name").is_some());
532 assert!(node.field("none").is_none());
533 }
534 #[test]
535 fn test_child_by_field_id() {
536 let root = Tsx.ast_grep("class A{}");
537 let root = root.root();
538 let node = root.find("class $C {}").expect("should exist");
539 let id = Tsx.field_to_id("name").unwrap();
540 assert!(node.child_by_field_id(id).is_some());
541 assert!(node.child_by_field_id(id + 1).is_none());
542 }
543
544 #[test]
545 fn test_remove() {
546 let root = Tsx.ast_grep("Some(Some(1)); Some(2);");
547 let root = root.root();
548 let node = root.find("Some(2);").expect("should exist");
549 let edit = node.remove();
550 assert_eq!(edit.position, 15);
551 assert_eq!(edit.deleted_length, 8);
552 }
553
554 #[test]
555 fn test_ascii_pos() {
556 let root = Tsx.ast_grep("a");
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 }
564
565 #[test]
566 fn test_unicode_pos() {
567 let root = Tsx.ast_grep("🦀");
568 let root = root.root();
569 let node = root.find("$A").expect("should exist");
570 assert_eq!(node.start_pos().line(), 0);
571 assert_eq!(node.start_pos().column(&*node), 0);
572 assert_eq!(node.end_pos().line(), 0);
573 assert_eq!(node.end_pos().column(&*node), 1);
574 let root = Tsx.ast_grep("\n 🦀🦀");
575 let root = root.root();
576 let node = root.find("$A").expect("should exist");
577 assert_eq!(node.start_pos().line(), 1);
578 assert_eq!(node.start_pos().column(&*node), 2);
579 assert_eq!(node.end_pos().line(), 1);
580 assert_eq!(node.end_pos().column(&*node), 4);
581 }
582}