Class: TreeSitter::Node
- Inherits:
-
Object
- Object
- TreeSitter::Node
- Includes:
- Enumerable
- Defined in:
- lib/tree_sitter/node.rb
Overview
Node is a wrapper around a tree-sitter node.
Instance Method Summary collapse
-
#[](*keys) ⇒ Node | Array<Node>
Access node’s named children.
-
#brk(out, vertical) ⇒ Object
Break helper.
-
#each {|child| ... } ⇒ Object
Iterate over a node’s children.
-
#each_field {|name, child| ... } ⇒ Object
Iterate over a node’s children assigned to a field.
-
#each_named {|child| ... } ⇒ Object
Iterate over a node’s named children.
-
#fetch(*keys) ⇒ Object
Access node’s named children.
- #field?(field) ⇒ Boolean
-
#fields ⇒ Array<Symbol>
The node’s named fields.
-
#sexpr(indent: 2, width: 120, source: nil, vertical: nil) ⇒ String
Pretty-prints the node’s sexp.
-
#to_a ⇒ Array<TreeSitter::Node>
All the node’s children.
Dynamic Method Handling
This class handles dynamic methods through the method_missing method
#method_missing(method_name, *_args, &_block) ⇒ Object (private)
Allows access to child_by_field_name without using [].
75 76 77 78 79 80 81 |
# File 'lib/tree_sitter/node.rb', line 75 def method_missing(method_name, *_args, &_block) if fields.include?(method_name) child_by_field_name(method_name.to_s) else super end end |
Instance Method Details
#[](*keys) ⇒ Node | Array<Node>
Access node’s named children.
It’s similar to #fetch, but differs in input type, return values, and the internal implementation.
Both of these methods exist for separate use cases, but also because sometime tree-sitter does some monkey business and having both separate implementations can help.
Comparison with #fetch:
[] | fetch
------------------------------+----------------------
input types Integer, String, Symbol | Array<String, Symbol>
Array<Integer, String, Symbol>|
------------------------------+----------------------
returns 1-to-1 correspondance with | unique nodes
input |
------------------------------+----------------------
uses named_child | field_name_for_child
child_by_field_name | via each_node
------------------------------+----------------------
52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 |
# File 'lib/tree_sitter/node.rb', line 52 def [](*keys) case keys.length when 0 then raise ArgumentError, "#{self.class.name}##{__method__} requires a key." when 1 case k = keys.first when Integer then named_child(k) when String, Symbol raise IndexError, "Cannot find field #{k.to_sym}. Available: #{fields.to_a}" unless fields.include?(k.to_sym) child_by_field_name(k.to_s) else raise ArgumentError, <<~ERR #{self.class.name}##{__method__} accepts Integer and returns named child at given index, or a (String | Symbol) and returns the child by given field name. ERR end else keys.map { |key| self[key] } end end |
#brk(out, vertical) ⇒ Object
Break helper
!@visibility private
248 249 250 251 252 253 254 |
# File 'lib/tree_sitter/node.rb', line 248 def brk(out, vertical) if vertical out.break else out.breakable end end |
#each {|child| ... } ⇒ Object
Iterate over a node’s children.
92 93 94 95 96 97 98 |
# File 'lib/tree_sitter/node.rb', line 92 def each(&_block) return enum_for __method__ if !block_given? (0...child_count).each do |i| yield child(i) end end |
#each_field {|name, child| ... } ⇒ Object
Iterate over a node’s children assigned to a field.
104 105 106 107 108 109 110 111 112 113 |
# File 'lib/tree_sitter/node.rb', line 104 def each_field return enum_for __method__ if !block_given? each.with_index do |c, i| f = field_name_for_child(i) next if f.nil? || f.empty? yield f, c end end |
#each_named {|child| ... } ⇒ Object
Iterate over a node’s named children
118 119 120 121 122 123 124 |
# File 'lib/tree_sitter/node.rb', line 118 def each_named return enum_for __method__ if !block_given? (0...(named_child_count)).each do |i| yield named_child(i) end end |
#fetch(*keys) ⇒ Object
Access node’s named children.
It’s similar to #[], but differs in input type, return values, and the internal implementation.
Both of these methods exist for separate use cases, but also because sometime tree-sitter does some monkey business and having both separate implementations can help.
Comparison with #fetch:
[] | fetch
------------------------------+----------------------
input types Integer, String, Symbol | String, Symbol
Array<Integer, String, Symbol>| Array<String, Symbol>
------------------------------+----------------------
returns 1-to-1 correspondance with | unique nodes
input |
------------------------------+----------------------
uses named_child | field_name_for_child
child_by_field_name | via each_node
------------------------------+----------------------
See #[].
155 156 157 158 159 160 161 162 163 164 165 |
# File 'lib/tree_sitter/node.rb', line 155 def fetch(*keys) keys = keys.map(&:to_s) key_set = keys.to_set fields = {} each_field do |f, _c| fields[f] = self[f] if key_set.delete(f) break if key_set.empty? end fields.values_at(*keys) end |
#field?(field) ⇒ Boolean
22 23 24 |
# File 'lib/tree_sitter/node.rb', line 22 def field?(field) fields.include?(field.to_sym) end |
#fields ⇒ Array<Symbol>
Returns the node’s named fields.
9 10 11 12 13 14 15 16 17 18 19 |
# File 'lib/tree_sitter/node.rb', line 9 def fields return @fields if @fields @fields = Set.new child_count.times do |i| name = field_name_for_child(i) @fields << name.to_sym if name end @fields.to_a end |
#sexpr(indent: 2, width: 120, source: nil, vertical: nil) ⇒ String
Pretty-prints the node’s sexp.
The default call to to_s or to_string calls tree-sitter’s ‘ts_node_string`. It’s displayed on a single line, so reading a rich node becomes tiresome.
This provides a better sexpr where you can control the “screen” width to decide when to break.
192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 |
# File 'lib/tree_sitter/node.rb', line 192 def sexpr(indent: 2, width: 120, source: nil, vertical: nil) res = sexpr_recur( indent: indent, width: width, source: source, vertical: !source.nil? || !!vertical, ).output return res if source.nil? max_width = 0 res .lines .map { |line| extracted = line.scan(LINE_ANNOTATION).flatten.first || '' base = line.gsub(LINE_ANNOTATION, '').rstrip max_width = [max_width, base.length].max [base, extracted] } .map { |base, extracted| ("%-#{max_width}s | %s" % [base, extracted]).rstrip } .join("\n") end |
#to_a ⇒ Array<TreeSitter::Node>
Returns all the node’s children.
127 128 129 |
# File 'lib/tree_sitter/node.rb', line 127 def to_a each.to_a end |