use std::cmp::Ordering;
use std::collections::Bound;
use std::error::Error;
use std::fmt::{Debug, Display, Formatter};
use std::hash::{Hash, Hasher};
use std::iter::{once, FusedIterator, Once};
use std::ops::{BitAnd, BitOr, BitOrAssign, RangeBounds};
#[cfg(unix)]
use std::os::unix::io::AsRawFd;
#[cfg(windows)]
use std::os::windows::io::AsRawHandle;
use std::path::{Path, PathBuf};
use std::ptr::NonNull;
use std::str::Utf8Error;
use streaming_iterator::StreamingIterator;
use utf8_error_offset_by::Utf8ErrorOffsetBy;
mod utf8_error_offset_by;
#[derive(Clone, Debug)]
pub struct Tree {
tree: tree_sitter::Tree,
byte_text: Vec<u8>,
path: Option<PathBuf>,
}
#[derive(Clone, Copy)]
pub struct Node<'tree> {
node: tree_sitter::Node<'tree>,
tree: &'tree Tree,
}
#[derive(Clone, Copy)]
pub struct NodePtr {
node_data: TsNodePtr,
tree: NonNull<Tree>,
}
#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
#[repr(C)]
struct TsNodePtr {
context: [u32; 4usize],
id: *const (),
tree: *const (),
}
#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
#[repr(transparent)]
pub struct NodeId(usize);
#[derive(Clone)]
pub struct TreeCursor<'tree> {
cursor: tree_sitter::TreeCursor<'tree>,
tree: &'tree Tree,
child_depth: usize,
}
pub struct QueryCursor {
query_cursor: tree_sitter::QueryCursor,
}
pub struct QueryMatches<'query, 'tree> {
query_matches: tree_sitter::QueryMatches<'query, 'tree, &'tree Tree, &'tree str>,
current_match: Option<QueryMatch<'query, 'tree>>,
query: &'query Query,
tree: &'tree Tree,
}
pub struct QueryMatch<'query, 'tree> {
query_match: *const tree_sitter::QueryMatch<'query, 'tree>,
query: &'query Query,
tree: &'tree Tree,
}
pub struct QueryCaptures<'query, 'tree> {
query_captures: tree_sitter::QueryCaptures<'query, 'tree, &'tree Tree, &'tree str>,
query: &'query Query,
tree: &'tree Tree,
}
#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
pub struct QueryCapture<'query, 'tree> {
pub node: Node<'tree>,
pub index: usize,
pub name: &'query str,
}
#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, PartialOrd, Ord)]
pub struct PointRange {
pub start: Point,
pub end: Point,
}
#[derive(Debug, Default, Clone, Copy, PartialEq, Eq, Hash, PartialOrd, Ord)]
pub struct Point {
pub row: usize,
pub column: usize,
}
#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
pub struct Range {
pub start_byte: usize,
pub end_byte: usize,
pub start_point: Point,
pub end_point: Point,
}
#[repr(transparent)]
pub struct Parser(tree_sitter::Parser);
pub type Language = tree_sitter::Language;
pub type LanguageRef<'a> = tree_sitter::LanguageRef<'a>;
pub type LanguageError = tree_sitter::LanguageError;
pub type Query = tree_sitter::Query;
pub type QueryProperty = tree_sitter::QueryProperty;
pub type IncludedRangesError = tree_sitter::IncludedRangesError;
pub type InputEdit = tree_sitter::InputEdit;
#[derive(Debug)]
pub enum TreeParseError {
IO(std::io::Error),
ParsingFailed,
NotUtf8(Utf8Error),
}
#[derive(Clone, Copy, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)]
pub enum TraversalState {
Start,
Down,
Right,
Up,
End,
}
#[derive(Clone)]
pub struct PreorderTraversal<'tree> {
cursor: TreeCursor<'tree>,
last_state: TraversalState,
}
#[derive(Clone, Copy, Debug)]
pub struct TraversalItem<'tree> {
pub node: Node<'tree>,
pub field_name: Option<&'static str>,
pub last_state: TraversalState,
}
impl Parser {
#[inline]
pub fn new(language: &Language) -> Result<Self, LanguageError> {
let mut parser = tree_sitter::Parser::new();
parser.set_language(language)?;
Ok(Self(parser))
}
#[inline]
pub fn set_language(&mut self, language: &Language) -> Result<(), LanguageError> {
self.0.set_language(language)
}
#[inline]
pub fn set_included_ranges(&mut self, ranges: &[Range]) -> Result<(), IncludedRangesError> {
let ranges = ranges
.iter()
.copied()
.map(tree_sitter::Range::from)
.collect::<Vec<_>>();
self.0.set_included_ranges(&ranges)
}
#[inline]
pub fn parse_file(
&mut self,
path: &Path,
old_tree: Option<&Tree>,
) -> Result<Tree, TreeParseError> {
let byte_text = std::fs::read(path)?;
self.parse_bytes(byte_text, Some(path), old_tree)
}
#[inline]
pub fn parse_string(
&mut self,
text: String,
path: Option<&Path>,
old_tree: Option<&Tree>,
) -> Result<Tree, TreeParseError> {
self.parse_bytes(text.into_bytes(), path, old_tree)
}
#[inline]
pub fn parse_bytes(
&mut self,
byte_text: Vec<u8>,
path: Option<&Path>,
old_tree: Option<&Tree>,
) -> Result<Tree, TreeParseError> {
let tree = self
.0
.parse(&byte_text, old_tree.map(|t| &t.tree))
.ok_or(TreeParseError::ParsingFailed)?;
Ok(Tree::new(tree, byte_text, path.map(|p| p.to_path_buf()))?)
}
}
impl Tree {
#[inline]
fn new(
tree: tree_sitter::Tree,
byte_text: Vec<u8>,
path: Option<PathBuf>,
) -> Result<Self, Utf8Error> {
Self::validate_utf8(&tree, &byte_text)?;
Ok(Self {
tree,
byte_text,
path,
})
}
fn validate_utf8(tree: &tree_sitter::Tree, byte_text: &[u8]) -> Result<(), Utf8Error> {
let _ = std::str::from_utf8(byte_text)?;
let mut cursor = tree.walk();
let mut went_up = false;
while (!went_up && cursor.goto_first_child()) || cursor.goto_next_sibling() || {
went_up = true;
cursor.goto_parent()
} {
let node = cursor.node();
let range = node.byte_range();
let _ = std::str::from_utf8(&byte_text[range])
.map_err(|e| e.offset_by(node.start_byte()))?;
}
Ok(())
}
#[inline]
pub fn text(&self) -> &str {
unsafe { std::str::from_utf8_unchecked(&self.byte_text) }
}
#[inline]
pub fn path(&self) -> Option<&Path> {
self.path.as_deref()
}
#[inline]
pub fn root_node(&self) -> Node {
unsafe { Node::new(self.tree.root_node(), self) }
}
#[inline]
pub fn walk(&self) -> TreeCursor {
TreeCursor::new(self.tree.walk(), self, true)
}
#[inline]
pub fn included_ranges(&self) -> Vec<Range> {
self.tree
.included_ranges()
.into_iter()
.map(Range::from)
.collect()
}
#[inline]
pub fn changed_ranges(&self, other: &Tree) -> impl ExactSizeIterator<Item = Range> {
self.tree.changed_ranges(&other.tree).map(Range::from)
}
#[inline]
pub fn language(&self) -> LanguageRef<'_> {
self.tree.language()
}
#[inline]
pub fn print_dot_graph(
&self,
#[cfg(unix)] file: &impl AsRawFd,
#[cfg(windows)] file: &impl AsRawHandle,
) {
self.tree.print_dot_graph(file)
}
#[inline]
pub fn edit(&mut self, edit: &InputEdit) {
self.tree.edit(edit)
}
}
impl<'tree> tree_sitter::TextProvider<&'tree str> for &'tree Tree {
type I = Once<&'tree str>;
#[inline]
fn text(&mut self, node: tree_sitter::Node<'_>) -> Self::I {
once(unsafe { std::str::from_utf8_unchecked(&self.byte_text[node.byte_range()]) })
}
}
impl<'tree> Node<'tree> {
#[inline]
pub unsafe fn new(node: tree_sitter::Node<'tree>, tree: &'tree Tree) -> Self {
Self { node, tree }
}
#[inline]
pub fn id(&self) -> NodeId {
NodeId::of_ts(self.node)
}
#[inline]
pub fn kind(&self) -> &'static str {
self.node.kind()
}
#[inline]
pub fn is_named(&self) -> bool {
self.node.is_named()
}
#[inline]
pub fn is_missing(&self) -> bool {
self.node.is_missing()
}
#[inline]
pub fn is_extra(&self) -> bool {
self.node.is_extra()
}
#[inline]
pub fn is_error(&self) -> bool {
self.node.is_error()
}
#[inline]
pub fn has_error(&self) -> bool {
self.node.has_error()
}
#[inline]
pub fn has_changes(&self) -> bool {
self.node.has_changes()
}
#[inline]
pub fn edit(&mut self, edit: &InputEdit) {
self.node.edit(edit)
}
#[inline]
pub fn start_byte(&self) -> usize {
self.node.start_byte()
}
#[inline]
pub fn end_byte(&self) -> usize {
self.node.end_byte()
}
#[inline]
pub fn start_position(&self) -> Point {
Point::from(self.node.start_position())
}
#[inline]
pub fn end_position(&self) -> Point {
Point::from(self.node.end_position())
}
#[inline]
pub fn byte_range(&self) -> std::ops::Range<usize> {
self.node.byte_range()
}
#[inline]
pub fn position_range(&self) -> PointRange {
PointRange {
start: self.start_position(),
end: self.end_position(),
}
}
#[inline]
pub fn range(&self) -> Range {
Range::from(self.node.range())
}
#[inline]
fn byte_text(&self) -> &'tree [u8] {
&self.tree.byte_text[self.byte_range()]
}
#[inline]
pub fn text(&self) -> &'tree str {
unsafe { std::str::from_utf8_unchecked(self.byte_text()) }
}
#[inline]
pub fn path(&self) -> Option<&'tree Path> {
self.tree.path()
}
#[inline]
pub fn all_children<'a>(
&self,
cursor: &'a mut TreeCursor<'tree>,
) -> impl ExactSizeIterator<Item = Node<'tree>> + 'a {
let tree = self.tree;
self.node
.children(&mut cursor.cursor)
.map(move |node| unsafe { Node::new(node, tree) })
}
#[inline]
pub fn named_children<'a>(
&self,
cursor: &'a mut TreeCursor<'tree>,
) -> impl ExactSizeIterator<Item = Node<'tree>> + 'a {
let tree = self.tree;
self.node
.named_children(&mut cursor.cursor)
.map(move |node| unsafe { Node::new(node, tree) })
}
#[inline]
pub fn any_child_count(&self) -> usize {
self.node.child_count()
}
#[inline]
pub fn named_child_count(&self) -> usize {
self.node.named_child_count()
}
#[inline]
pub fn parent(&self) -> Option<Node<'tree>> {
self.node
.parent()
.map(|node| unsafe { Node::new(node, self.tree) })
}
#[inline]
pub fn next_any_sibling(&self) -> Option<Node<'tree>> {
self.node
.next_sibling()
.map(|node| unsafe { Node::new(node, self.tree) })
}
#[inline]
pub fn next_named_sibling(&self) -> Option<Node<'tree>> {
self.node
.next_named_sibling()
.map(|node| unsafe { Node::new(node, self.tree) })
}
#[inline]
pub fn prev_any_sibling(&self) -> Option<Node<'tree>> {
self.node
.prev_sibling()
.map(|node| unsafe { Node::new(node, self.tree) })
}
#[inline]
pub fn prev_named_sibling(&self) -> Option<Node<'tree>> {
self.node
.prev_named_sibling()
.map(|node| unsafe { Node::new(node, self.tree) })
}
#[inline]
pub fn any_child(&self, i: usize) -> Option<Node<'tree>> {
self.node
.child(i)
.map(|node| unsafe { Node::new(node, self.tree) })
}
#[inline]
pub fn named_child(&self, i: usize) -> Option<Node<'tree>> {
self.node
.named_child(i)
.map(|node| unsafe { Node::new(node, self.tree) })
}
#[inline]
pub fn last_any_child(&self) -> Option<Node<'tree>> {
self.node
.child(self.any_child_count().wrapping_sub(1))
.map(|node| unsafe { Node::new(node, self.tree) })
}
#[inline]
pub fn last_named_child(&self) -> Option<Node<'tree>> {
self.node
.named_child(self.named_child_count().wrapping_sub(1))
.map(|node| unsafe { Node::new(node, self.tree) })
}
#[inline]
pub fn child_of_kind(&self, kind: &str, cursor: &mut TreeCursor<'tree>) -> Option<Node<'tree>> {
self.node
.named_children(&mut cursor.cursor)
.find(|node| node.kind() == kind)
.map(|node| unsafe { Node::new(node, self.tree) })
}
#[inline]
pub fn children_of_kind<'a>(
&self,
kind: &'a str,
cursor: &'a mut TreeCursor<'tree>,
) -> impl Iterator<Item = Node<'tree>> + 'a {
self.node
.named_children(&mut cursor.cursor)
.filter(move |node| node.kind() == kind)
.map(|node| unsafe { Node::new(node, self.tree) })
}
#[inline]
pub fn child_by_field_name(&self, field_name: &str) -> Option<Node<'tree>> {
self.node
.child_by_field_name(field_name)
.map(|node| unsafe { Node::new(node, self.tree) })
}
#[inline]
pub fn children_by_field_name<'a>(
&self,
field_name: &str,
c: &'a mut TreeCursor<'tree>,
) -> impl Iterator<Item = Node<'tree>> + 'a {
self.node
.children_by_field_name(field_name, &mut c.cursor)
.map(|node| unsafe { Node::new(node, self.tree) })
}
#[inline]
pub fn field_name_for_child(&self, i: usize) -> Option<&'static str> {
self.node.field_name_for_child(i as u32)
}
#[inline]
pub fn field_name_for_named_child(&self, i: usize) -> Option<&'static str> {
self.node.field_name_for_named_child(i as u32)
}
pub fn field_name(&self, cursor: &mut TreeCursor<'tree>) -> Option<&'static str> {
self.parent().and_then(|parent| {
let i = parent
.all_children(cursor)
.position(|x| x == *self)
.expect("node not one of its parent's children");
parent.field_name_for_child(i)
})
}
#[inline]
pub fn walk(&self) -> TreeCursor<'tree> {
TreeCursor::new(self.node.walk(), self.tree, false)
}
#[inline]
pub fn to_sexp(&self) -> String {
self.node.to_sexp()
}
#[inline]
pub fn to_ptr(&self) -> NodePtr {
NodePtr {
node_data: TsNodePtr::from(self.node),
tree: NonNull::from(self.tree),
}
}
}
impl<'tree> PartialEq for Node<'tree> {
#[inline]
fn eq(&self, other: &Node<'tree>) -> bool {
self.id() == other.id()
}
}
impl<'tree> Eq for Node<'tree> {}
impl<'tree> PartialOrd for Node<'tree> {
#[inline]
fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
Some(self.cmp(other))
}
}
impl<'tree> Ord for Node<'tree> {
fn cmp(&self, other: &Self) -> Ordering {
if self.id() == other.id() {
Ordering::Equal
} else if std::ptr::eq(self.tree as *const _, other.tree as *const _) {
self.start_byte()
.cmp(&other.start_byte())
.then(self.end_byte().cmp(&other.end_byte()))
} else {
self.path()
.cmp(&other.path())
.then(self.id().0.cmp(&other.id().0))
}
}
}
impl<'tree> Hash for Node<'tree> {
#[inline]
fn hash<H: Hasher>(&self, state: &mut H) {
self.id().hash(state)
}
}
impl NodePtr {
#[inline]
pub unsafe fn to_node<'a>(self) -> Node<'a> {
Node {
node: self.node_data.to_node(),
tree: self.tree.as_ref(),
}
}
}
impl PartialEq for NodePtr {
#[inline]
fn eq(&self, other: &NodePtr) -> bool {
self.node_data == other.node_data
}
}
impl Eq for NodePtr {}
impl Hash for NodePtr {
#[inline]
fn hash<H: Hasher>(&self, state: &mut H) {
self.node_data.hash(state)
}
}
impl TsNodePtr {
#[inline]
pub unsafe fn to_node<'tree>(self) -> tree_sitter::Node<'tree> {
std::mem::transmute(self)
}
}
impl<'tree> From<tree_sitter::Node<'tree>> for TsNodePtr {
#[inline]
fn from(node: tree_sitter::Node) -> Self {
unsafe { std::mem::transmute::<tree_sitter::Node<'_>, TsNodePtr>(node) }
}
}
impl<'tree> TreeCursor<'tree> {
#[inline]
fn new(cursor: tree_sitter::TreeCursor<'tree>, tree: &'tree Tree, is_rooted: bool) -> Self {
Self {
cursor,
tree,
child_depth: match is_rooted {
false => 0,
true => 1,
},
}
}
#[inline]
pub fn node(&self) -> Node<'tree> {
unsafe { Node::new(self.cursor.node(), self.tree) }
}
pub fn field_name(&mut self) -> Option<&'static str> {
self.cursor.field_name().or_else(|| {
if self.child_depth > 0 {
None
} else {
match self.node().parent() {
None => None,
Some(parent) => {
let original_node = self.node();
self.reset(parent);
self.goto_first_child();
while self.node() != original_node {
self.goto_next_sibling();
}
self.cursor.field_name()
}
}
}
})
}
#[inline]
pub fn reset(&mut self, node: Node<'tree>) {
if self.cursor.node() != node.node {
self.cursor.reset(node.node);
self.child_depth = if node.tree.root_node() == node { 1 } else { 0 };
}
}
#[inline]
pub fn goto_first_child(&mut self) -> bool {
if self.cursor.goto_first_child() {
self.child_depth += 1;
true
} else {
false
}
}
#[inline]
pub fn goto_first_child_for_byte(&mut self, index: usize) -> Option<usize> {
self.cursor.goto_first_child_for_byte(index).map(|index| {
self.child_depth += 1;
index
})
}
#[inline]
pub fn goto_first_child_for_point(&mut self, point: Point) -> Option<usize> {
self.cursor
.goto_first_child_for_point(point.into())
.map(|index| {
self.child_depth += 1;
index
})
}
pub fn goto_next_sibling(&mut self) -> bool {
self.cursor.goto_next_sibling()
|| if self.child_depth > 0 {
false
} else {
match self.node().parent() {
None => false,
Some(parent) => {
let original_node = self.node();
self.reset(parent);
self.goto_first_child();
while self.node() != original_node {
self.goto_next_sibling();
}
self.goto_next_sibling()
}
}
}
}
pub fn goto_parent(&mut self) -> bool {
if self.cursor.goto_parent() {
debug_assert!(self.child_depth != 0);
self.child_depth -= 1;
true
} else {
if self.child_depth > 0 {
false
} else {
match self.node().parent() {
None => false,
Some(parent) => {
self.reset(parent);
true
}
}
}
}
}
pub fn goto_preorder(&mut self, last_state: TraversalState) -> TraversalState {
if !last_state.is_up() && self.goto_first_child() {
TraversalState::Down
} else if self.goto_next_sibling() {
TraversalState::Right
} else if self.goto_parent() {
TraversalState::Up
} else {
TraversalState::End
}
}
}
impl QueryCursor {
#[inline]
pub fn new() -> Self {
Self {
query_cursor: tree_sitter::QueryCursor::new(),
}
}
#[inline]
pub fn matches<'query, 'cursor: 'query, 'tree>(
&'cursor mut self,
query: &'query Query,
node: Node<'tree>,
) -> QueryMatches<'query, 'tree> {
QueryMatches {
query_matches: self.query_cursor.matches(&query, node.node, node.tree),
current_match: None,
tree: node.tree,
query,
}
}
#[inline]
pub fn captures<'query, 'cursor: 'query, 'tree>(
&'cursor mut self,
query: &'query Query,
node: Node<'tree>,
) -> QueryCaptures<'query, 'tree> {
QueryCaptures {
query_captures: self.query_cursor.captures(query, node.node, node.tree),
tree: node.tree,
query,
}
}
#[inline]
pub fn set_match_limit(&mut self, limit: u16) {
self.query_cursor.set_match_limit(limit as u32);
}
#[inline]
pub fn match_limit(&self) -> u16 {
self.query_cursor.match_limit() as u16
}
#[inline]
pub fn did_exceed_match_limit(&self) -> bool {
self.query_cursor.did_exceed_match_limit()
}
#[inline]
pub fn set_byte_range(&mut self, range: std::ops::Range<usize>) -> &mut Self {
self.query_cursor.set_byte_range(range);
self
}
#[inline]
pub fn set_point_range(&mut self, range: PointRange) -> &mut Self {
self.query_cursor.set_point_range(range.to_ts_point_range());
self
}
}
impl<'query, 'tree> QueryMatches<'query, 'tree> {
#[inline]
pub fn query(&self) -> &'query Query {
self.query
}
#[inline]
pub fn tree(&self) -> &'tree Tree {
self.tree
}
#[inline]
pub fn set_byte_range(&mut self, range: std::ops::Range<usize>) {
self.query_matches.set_byte_range(range);
}
#[inline]
pub fn set_point_range(&mut self, range: PointRange) {
self.query_matches
.set_point_range(range.to_ts_point_range());
}
#[inline]
pub fn as_inner(&self) -> &tree_sitter::QueryMatches<'query, 'tree, &'tree Tree, &'tree str> {
&self.query_matches
}
#[inline]
pub fn as_inner_mut(
&mut self,
) -> &mut tree_sitter::QueryMatches<'query, 'tree, &'tree Tree, &'tree str> {
&mut self.query_matches
}
#[inline]
pub fn into_inner(
self,
) -> (
tree_sitter::QueryMatches<'query, 'tree, &'tree Tree, &'tree str>,
&'query Query,
&'tree Tree,
) {
(self.query_matches, self.query, self.tree)
}
}
impl<'query, 'tree: 'query> StreamingIterator for QueryMatches<'query, 'tree> {
type Item = QueryMatch<'query, 'tree>;
#[inline]
fn advance(&mut self) {
self.query_matches.advance();
self.current_match = self.query_matches.get().map(|query_match| QueryMatch {
query_match: query_match as *const _,
query: self.query,
tree: self.tree,
});
}
#[inline]
fn get(&self) -> Option<&Self::Item> {
self.current_match.as_ref()
}
fn size_hint(&self) -> (usize, Option<usize>) {
self.query_matches.size_hint()
}
}
impl<'query, 'tree> QueryCaptures<'query, 'tree> {
#[inline]
pub fn query(&self) -> &'query Query {
self.query
}
#[inline]
pub fn tree(&self) -> &'tree Tree {
self.tree
}
#[inline]
pub fn set_byte_range(&mut self, range: std::ops::Range<usize>) {
self.query_captures.set_byte_range(range);
}
#[inline]
pub fn set_point_range(&mut self, range: PointRange) {
self.query_captures
.set_point_range(range.to_ts_point_range());
}
#[inline]
pub fn as_inner(&self) -> &tree_sitter::QueryCaptures<'query, 'tree, &'tree Tree, &'tree str> {
&self.query_captures
}
#[inline]
pub fn as_inner_mut(
&mut self,
) -> &mut tree_sitter::QueryCaptures<'query, 'tree, &'tree Tree, &'tree str> {
&mut self.query_captures
}
#[inline]
pub fn into_inner(
self,
) -> (
tree_sitter::QueryCaptures<'query, 'tree, &'tree Tree, &'tree str>,
&'query Query,
&'tree Tree,
) {
(self.query_captures, self.query, self.tree)
}
}
impl<'query, 'tree: 'query> Iterator for QueryCaptures<'query, 'tree> {
type Item = QueryCapture<'query, 'tree>;
#[inline]
fn next(&mut self) -> Option<Self::Item> {
self.query_captures.next().map(|(query_match, index)| {
QueryCapture::new(query_match.captures[*index], self.query, self.tree)
})
}
}
impl<'query, 'tree> QueryMatch<'query, 'tree> {
#[inline]
pub unsafe fn new(
query_match: &tree_sitter::QueryMatch<'query, 'tree>,
query: &'query Query,
tree: &'tree Tree,
) -> Self {
Self {
query_match: query_match as *const _,
query,
tree,
}
}
#[inline]
pub fn query(&self) -> &'query Query {
self.query
}
#[inline]
pub fn tree(&self) -> &'tree Tree {
self.tree
}
#[inline]
pub fn iter_captures(&self) -> impl Iterator<Item = QueryCapture<'query, 'tree>> {
self.as_inner()
.captures
.iter()
.map(|&query_capture| QueryCapture::new(query_capture, self.query, self.tree))
}
#[inline]
pub fn capture(&self, index: usize) -> Option<QueryCapture<'query, 'tree>> {
self.as_inner()
.captures
.get(index)
.map(|&query_capture| QueryCapture::new(query_capture, self.query, self.tree))
}
#[inline]
pub fn capture_named(&self, name: &str) -> Option<QueryCapture<'query, 'tree>> {
self.iter_captures().find(|capture| capture.name == name)
}
#[inline]
pub fn captures_named<'a>(
&'a self,
name: &'a str,
) -> impl Iterator<Item = QueryCapture<'query, 'tree>> + 'a {
self.iter_captures()
.filter(move |capture| capture.name == name)
}
#[inline]
pub fn capture_count(&self) -> usize {
self.as_inner().captures.len()
}
#[inline]
pub fn pattern_index(&self) -> usize {
self.as_inner().pattern_index
}
#[inline]
pub fn id(&self) -> u32 {
self.as_inner().id()
}
#[inline]
pub fn remove(&self) {
self.as_inner().remove()
}
#[inline]
pub fn nodes_for_capture_index(
&self,
capture_index: u32,
) -> impl Iterator<Item = Node<'tree>> + '_ {
self.as_inner()
.nodes_for_capture_index(capture_index)
.map(move |node| unsafe { Node::new(node, self.tree) })
}
#[inline]
pub fn as_inner(&self) -> &tree_sitter::QueryMatch<'query, 'tree> {
unsafe { &*self.query_match }
}
#[inline]
pub fn into_inner(
self,
) -> (
*const tree_sitter::QueryMatch<'query, 'tree>,
&'query Query,
&'tree Tree,
) {
(self.query_match, self.query, self.tree)
}
}
impl<'query, 'tree> QueryCapture<'query, 'tree> {
#[inline]
fn new(
query_capture: tree_sitter::QueryCapture<'tree>,
query: &'query Query,
tree: &'tree Tree,
) -> Self {
unsafe {
Self {
node: Node::new(query_capture.node, tree),
index: query_capture.index as usize,
name: &query.capture_names()[query_capture.index as usize],
}
}
}
}
impl From<tree_sitter::Point> for Point {
#[inline]
fn from(value: tree_sitter::Point) -> Self {
Self {
row: value.row,
column: value.column,
}
}
}
impl From<Point> for tree_sitter::Point {
#[inline]
fn from(value: Point) -> Self {
Self {
row: value.row,
column: value.column,
}
}
}
impl Display for Point {
#[inline]
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
write!(f, "{}:{}", self.row + 1, self.column + 1)
}
}
impl PointRange {
#[inline]
pub fn to_ops_range(self) -> std::ops::Range<Point> {
self.start..self.end
}
#[inline]
pub fn to_ts_point_range(self) -> std::ops::Range<tree_sitter::Point> {
self.start.into()..self.end.into()
}
}
impl From<std::ops::Range<Point>> for PointRange {
#[inline]
fn from(value: std::ops::Range<Point>) -> Self {
Self {
start: value.start,
end: value.end,
}
}
}
impl RangeBounds<Point> for PointRange {
fn start_bound(&self) -> Bound<&Point> {
Bound::Excluded(&self.start)
}
fn end_bound(&self) -> Bound<&Point> {
Bound::Excluded(&self.end)
}
}
impl Display for PointRange {
#[inline]
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
if self.start == self.end {
write!(f, "{}", self.start)
} else if self.start.row == self.end.row {
write!(f, "{}-{}", self.start, self.end.column + 1)
} else {
write!(f, "{}-{}", self.start, self.end)
}
}
}
impl From<tree_sitter::Range> for Range {
#[inline]
fn from(value: tree_sitter::Range) -> Self {
Self {
start_byte: value.start_byte,
end_byte: value.end_byte,
start_point: Point::from(value.start_point),
end_point: Point::from(value.end_point),
}
}
}
impl From<Range> for tree_sitter::Range {
#[inline]
fn from(value: Range) -> Self {
Self {
start_byte: value.start_byte,
end_byte: value.end_byte,
start_point: value.start_point.into(),
end_point: value.end_point.into(),
}
}
}
impl From<Range> for PointRange {
#[inline]
fn from(value: Range) -> Self {
Self {
start: value.start_point,
end: value.end_point,
}
}
}
impl BitOr for Range {
type Output = Range;
#[inline]
fn bitor(self, rhs: Self) -> Self::Output {
Range {
start_byte: self.start_byte.min(rhs.start_byte),
end_byte: self.end_byte.max(rhs.end_byte),
start_point: self.start_point.min(rhs.start_point),
end_point: self.end_point.max(rhs.end_point),
}
}
}
impl BitOrAssign for Range {
#[inline]
fn bitor_assign(&mut self, rhs: Self) {
*self = *self | rhs;
}
}
impl BitAnd for Range {
type Output = Option<Range>;
#[inline]
fn bitand(self, rhs: Self) -> Self::Output {
let start_byte = self.start_byte.max(rhs.start_byte);
let end_byte = self.end_byte.min(rhs.end_byte);
let start_point = self.start_point.max(rhs.start_point);
let end_point = self.end_point.min(rhs.end_point);
if start_byte <= end_byte && start_point <= end_point {
Some(Range {
start_byte,
end_byte,
start_point,
end_point,
})
} else {
None
}
}
}
impl Display for Range {
#[inline]
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
write!(f, "{}", PointRange::from(*self))
}
}
impl NodeId {
pub const INVALID: Self = Self(usize::MAX);
#[inline]
fn of_ts(node: tree_sitter::Node<'_>) -> Self {
NodeId(node.id())
}
}
impl From<u64> for NodeId {
#[inline]
fn from(value: u64) -> Self {
NodeId(value as usize)
}
}
impl Into<u64> for NodeId {
#[inline]
fn into(self) -> u64 {
self.0 as u64
}
}
impl Display for NodeId {
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
write!(f, "#{}", self.0)
}
}
impl Clone for TreeParseError {
#[inline]
fn clone(&self) -> Self {
match self {
TreeParseError::IO(e) => TreeParseError::IO(std::io::Error::from(e.kind())),
TreeParseError::ParsingFailed => TreeParseError::ParsingFailed,
TreeParseError::NotUtf8(e) => TreeParseError::NotUtf8(*e),
}
}
}
impl From<std::io::Error> for TreeParseError {
fn from(e: std::io::Error) -> Self {
TreeParseError::IO(e)
}
}
impl From<Utf8Error> for TreeParseError {
fn from(e: Utf8Error) -> Self {
TreeParseError::NotUtf8(e)
}
}
impl Display for TreeParseError {
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
match self {
TreeParseError::IO(e) => write!(f, "IO error: {}", e),
TreeParseError::ParsingFailed => write!(f, "Parsing failed"),
TreeParseError::NotUtf8(e) => write!(f, "Not UTF-8: {}", e),
}
}
}
impl Error for TreeParseError {
fn source(&self) -> Option<&(dyn Error + 'static)> {
match self {
TreeParseError::IO(e) => Some(e),
TreeParseError::ParsingFailed => None,
TreeParseError::NotUtf8(e) => Some(e),
}
}
}
impl TraversalState {
#[inline]
pub fn is_up(&self) -> bool {
match self {
TraversalState::Up => true,
_ => false,
}
}
#[inline]
pub fn is_end(&self) -> bool {
match self {
TraversalState::End => true,
_ => false,
}
}
}
impl<'tree> PreorderTraversal<'tree> {
#[inline]
pub fn with_cursor(cursor: TreeCursor<'tree>) -> Self {
Self {
cursor,
last_state: TraversalState::Start,
}
}
#[inline]
pub fn of_tree(tree: &'tree Tree) -> Self {
Self::with_cursor(tree.walk())
}
#[inline]
pub fn of_node(node: Node<'tree>) -> Self {
Self::with_cursor(node.walk())
}
#[inline]
pub fn peek(&mut self) -> TraversalItem<'tree> {
TraversalItem {
node: self.cursor.node(),
field_name: self.cursor.field_name(),
last_state: self.last_state,
}
}
#[inline]
pub fn goto_next(&mut self) -> bool {
if self.last_state.is_end() {
false
} else {
self.last_state = self.cursor.goto_preorder(self.last_state);
true
}
}
}
impl<'tree> Iterator for PreorderTraversal<'tree> {
type Item = TraversalItem<'tree>;
#[inline]
fn next(&mut self) -> Option<TraversalItem<'tree>> {
if self.last_state.is_end() {
return None;
}
let item = self.peek();
self.last_state = self.cursor.goto_preorder(self.last_state);
Some(item)
}
}
impl<'tree> FusedIterator for PreorderTraversal<'tree> {}
impl<'tree> Debug for Node<'tree> {
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
write!(f, "{:?}", self.node)
}
}
impl Debug for NodePtr {
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
write!(f, "{:?}", self.node_data)
}
}
impl<'query, 'tree> Debug for QueryMatch<'query, 'tree> {
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
write!(f, "{:?}", self.query_match)
}
}
impl<'tree> PartialEq for TraversalItem<'tree> {
fn eq(&self, other: &Self) -> bool {
if self.node == other.node {
debug_assert_eq!(
self.field_name, other.field_name,
"field_name must be the same if node is the same"
);
}
self.node == other.node && self.last_state == other.last_state
}
}
impl<'tree> Eq for TraversalItem<'tree> {}