Class: TreeStand::Tree

Inherits:
Object
  • Object
show all
Defined in:
lib/tree_stand/tree.rb

Overview

Wrapper around a TreeSitter tree.

This class exposes a convient API for working with the tree. There are dangers in using this class. The tree is mutable and the document can be changed. This class does not protect against that.

Some of the moetods on this class edit and re-parse the document updating the tree. Because the document is re-parsed, the tree will be different. Which means all outstanding nodes & ranges will be invalid.

Methods that edit the document are suffixed with !, e.g. #edit!.

It's often the case that you will want perfrom multiple edits. One such pattern is to call #query & #edit on all matches in a loop. It's important to keep the destructive nature of #edit in mind and re-issue the query after each edit.

Another thing to keep in mind is that edits done later in the document will likely not affect the ranges that occur earlier in the document. This can be a convient property that could allow you to apply edits in a reverse order. This is not always possible and depends on the edits you make, beware that the tree will be different after each edit and this approach may cause bugs.

Instance Attribute Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(parser, tree, document) ⇒ Tree

This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.

Returns a new instance of Tree.



33
34
35
36
37
# File 'lib/tree_stand/tree.rb', line 33

def initialize(parser, tree, document)
  @parser = parser
  @ts_tree = tree
  @document = document
end

Instance Attribute Details

#documentString (readonly)

Returns:

  • (String)


26
27
28
# File 'lib/tree_stand/tree.rb', line 26

def document
  @document
end

#parserTreeStand::Parser (readonly)

Returns:



30
31
32
# File 'lib/tree_stand/tree.rb', line 30

def parser
  @parser
end

#ts_treeTreeSitter::Tree (readonly)

Returns:

  • (TreeSitter::Tree)


28
29
30
# File 'lib/tree_stand/tree.rb', line 28

def ts_tree
  @ts_tree
end

Instance Method Details

#delete!(range) ⇒ void

This method returns an undefined value.

This method deletes the section of the document specified by range Then it will reparse the document and update the tree!

Parameters:



70
71
72
73
74
75
# File 'lib/tree_stand/tree.rb', line 70

def delete!(range)
  new_document = +""
  new_document << @document[0...range.start_byte]
  new_document << @document[range.end_byte..-1]
  replace_with_new_doc(new_document)
end

#edit!(range, replacement) ⇒ void

This method returns an undefined value.

This method replaces the section of the document specified by range and replaces it with the provided text. Then it will reparse the document and update the tree!

Parameters:



58
59
60
61
62
63
64
# File 'lib/tree_stand/tree.rb', line 58

def edit!(range, replacement)
  new_document = +""
  new_document << @document[0...range.start_byte]
  new_document << replacement
  new_document << @document[range.end_byte..-1]
  replace_with_new_doc(new_document)
end

#query(query_string) ⇒ Array<TreeStand::Match>

Note:

This is a convenience method that calls Node#query on #root_node.

TreeSitter uses a TreeSitter::Cursor to iterate over matches by calling curser#next_match repeatedly until it returns nil.

This method does all of that for you and collects all of the matches into an array.

Examples:

# This will return a match for each identifier nodes in the tree.
tree_matches = tree.query(<<~QUERY)
  (identifier) @identifier
QUERY

# It is equivalent to:
tree.root_node.query(<<~QUERY)
  (identifier) @identifier
QUERY

Parameters:

  • query_string (String)

Returns:

See Also:



48
49
50
# File 'lib/tree_stand/tree.rb', line 48

def query(query_string)
  root_node.query(query_string)
end

#root_nodeTreeStand::Node

Returns:



40
41
42
# File 'lib/tree_stand/tree.rb', line 40

def root_node
  TreeStand::Node.new(self, @ts_tree.root_node)
end