use std::cmp::Ordering;
use std::collections::Bound;
use std::error::Error;
use std::fmt::{Debug, Display, Formatter};
use std::path::{Path, PathBuf};
use std::iter::{FusedIterator, once, Once};
use streaming_iterator::{StreamingIterator, StreamingIteratorMut};
use std::str::Utf8Error;
use std::hash::{Hash, Hasher};
use std::ops::{BitAnd, BitOr, BitOrAssign, RangeBounds};
#[cfg(unix)]
use std::os::fd::AsRawFd;
#[cfg(windows)]
use std::os::fd::AsRawHandle;
use std::ptr::NonNull;
use utf8_error_offset_by::Utf8ErrorOffsetBy;
mod utf8_error_offset_by;
mod define_custom_wrapper;
#[derive(Debug)]
pub struct Tree<Custom = ()> {
tree: tree_sitter::Tree,
byte_text: Vec<u8>,
path: Option<PathBuf>,
pub custom: Custom
}
pub struct Node<'tree, Custom = ()> {
node: tree_sitter::Node<'tree>,
tree: &'tree Tree<Custom>,
}
pub struct NodePtr<Custom = ()> {
node_data: NodeData,
tree: NonNull<Tree<Custom>>
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
#[repr(C)]
struct NodeData {
context: [u32; 4usize],
id: *const (),
tree: *const (),
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
#[repr(transparent)]
pub struct NodeId(usize);
pub struct TreeCursor<'tree, Custom = ()> {
cursor: tree_sitter::TreeCursor<'tree>,
tree: &'tree Tree<Custom>,
child_depth: usize,
}
pub struct QueryCursor {
query_cursor: tree_sitter::QueryCursor
}
pub struct QueryMatches<'query, 'tree: 'query, Custom = ()> {
query_matches: tree_sitter::QueryMatches<'query, 'tree, &'query Tree<Custom>, &'query str>,
current_match: Option<QueryMatch<'query, 'tree, Custom>>,
tree: &'tree Tree<Custom>,
query: &'query Query
}
pub struct QueryMatch<'query, 'tree, Custom = ()> {
query_match: tree_sitter::QueryMatch<'query, 'tree>,
tree: &'tree Tree<Custom>,
query: &'query Query
}
pub struct QueryCaptures<'query, 'tree, Custom = ()> {
query_captures: tree_sitter::QueryCaptures<'query, 'tree, &'query Tree<Custom>, &'query str>,
tree: &'tree Tree<Custom>,
query: &'query Query
}
pub struct QueryCapture<'query, 'tree, Custom = ()> {
pub node: Node<'tree, Custom>,
pub index: usize,
pub name: &'query str,
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, PartialOrd, Ord)]
pub struct PointRange {
pub start: Point,
pub end: Point,
}
#[derive(Debug, Default, Clone, Copy, PartialEq, Eq, Hash, PartialOrd, Ord)]
#[repr(transparent)]
pub struct Point(tree_sitter::Point);
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
#[repr(transparent)]
pub struct Range(tree_sitter::Range);
#[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)
}
pub struct SubTree<Custom = ()> {
pub text: String,
pub range: Range,
pub path: Option<PathBuf>,
pub root: Option<NodePtr<Custom>>,
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
pub enum TraversalState {
Start,
Down,
Right,
Up,
End
}
pub struct PreorderTraversal<'tree, Custom = ()> {
cursor: TreeCursor<'tree, Custom>,
last_state: TraversalState
}
pub struct TraversalItem<'tree, Custom = ()> {
pub node: Node<'tree, Custom>,
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> {
self.0.set_included_ranges(Range::slice_as_ts(ranges))
}
#[inline]
pub fn parse_file<Custom>(
&mut self,
path: &Path,
old_tree: Option<&Tree<Custom>>,
custom: Custom
) -> Result<Tree<Custom>, TreeParseError> {
let byte_text = std::fs::read(path)?;
self.parse_bytes(byte_text, Some(path), old_tree, custom)
}
#[inline]
pub fn parse_string<Custom>(
&mut self,
text: String,
path: Option<impl AsRef<Path>>,
old_tree: Option<&Tree<Custom>>,
custom: Custom
) -> Result<Tree<Custom>, TreeParseError> {
self.parse_bytes(text.into_bytes(), path, old_tree, custom)
}
#[inline]
pub fn parse_bytes<Custom>(
&mut self,
byte_text: Vec<u8>,
path: Option<impl AsRef<Path>>,
old_tree: Option<&Tree<Custom>>,
custom: Custom
) -> Result<Tree<Custom>, 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.as_ref().to_path_buf()), custom)?)
}
}
impl<Custom> Tree<Custom> {
#[inline]
fn new(
tree: tree_sitter::Tree,
byte_text: Vec<u8>,
path: Option<PathBuf>,
custom: Custom
) -> Result<Self, Utf8Error> {
Self::validate_utf8(&tree, &byte_text)?;
Ok(Self { tree, byte_text, path, custom })
}
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<'_, Custom> {
unsafe { Node::new(self.tree.root_node(), self) }
}
#[inline]
pub fn walk(&self) -> TreeCursor<'_, Custom> {
TreeCursor::new(self.tree.walk(), self, true)
}
#[inline]
pub fn included_ranges(&self) -> Vec<Range> {
Range::vec_from_ts(self.tree.included_ranges())
}
#[inline]
pub fn changed_ranges(&self, other: &Tree) -> impl ExactSizeIterator<Item=Range> {
self.tree.changed_ranges(&other.tree).map(Range)
}
#[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, Custom> tree_sitter::TextProvider<&'tree str> for &'tree Tree<Custom> {
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, Custom> Node<'tree, Custom> {
#[inline]
pub unsafe fn new(node: tree_sitter::Node<'tree>, tree: &'tree Tree<Custom>) -> 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(self.node.start_position())
}
#[inline]
pub fn end_position(&self) -> Point {
Point(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(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 custom(&self) -> &'tree Custom {
&self.tree.custom
}
#[inline]
pub fn all_children<'a>(&self, cursor: &'a mut TreeCursor<'tree, Custom>) -> impl ExactSizeIterator<Item = Node<'tree, Custom>> + '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, Custom>) -> impl ExactSizeIterator<Item = Node<'tree, Custom>> + '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, Custom>> {
self.node.parent().map(|node| unsafe { Node::new(node, self.tree) })
}
#[inline]
pub fn next_any_sibling(&self) -> Option<Node<'tree, Custom>> {
self.node.next_sibling().map(|node| unsafe { Node::new(node, self.tree) })
}
#[inline]
pub fn next_named_sibling(&self) -> Option<Node<'tree, Custom>> {
self.node.next_named_sibling().map(|node| unsafe { Node::new(node, self.tree) })
}
#[inline]
pub fn prev_any_sibling(&self) -> Option<Node<'tree, Custom>> {
self.node.prev_sibling().map(|node| unsafe { Node::new(node, self.tree) })
}
#[inline]
pub fn prev_named_sibling(&self) -> Option<Node<'tree, Custom>> {
self.node.prev_named_sibling().map(|node| unsafe { Node::new(node, self.tree) })
}
#[inline]
pub fn any_child(&self, i: usize) -> Option<Node<'tree, Custom>> {
self.node.child(i).map(|node| unsafe { Node::new(node, self.tree) })
}
#[inline]
pub fn named_child(&self, i: usize) -> Option<Node<'tree, Custom>> {
self.node.named_child(i).map(|node| unsafe { Node::new(node, self.tree) })
}
#[inline]
pub fn last_any_child(&self) -> Option<Node<'tree, Custom>> {
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, Custom>> {
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, Custom>
) -> Option<Node<'tree, Custom>> {
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, Custom>
) -> impl Iterator<Item = Node<'tree, Custom>> + '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, Custom>> {
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, Custom>
) -> impl Iterator<Item = Node<'tree, Custom>> + '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)
}
pub fn field_name(&self, cursor: &mut TreeCursor<'tree, Custom>) -> 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, Custom> {
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<Custom> {
NodePtr {
node_data: NodeData::from(self.node),
tree: NonNull::from(self.tree),
}
}
#[inline]
pub fn to_subtree(&self) -> SubTree<Custom> {
SubTree {
text: self.text().to_string(),
range: self.range(),
path: self.path().map(|p| p.to_path_buf()),
root: Some(self.to_ptr()),
}
}
}
impl<'tree, Custom> PartialEq for Node<'tree, Custom> {
#[inline]
fn eq(&self, other: &Node<'tree, Custom>) -> bool {
self.id() == other.id()
}
}
impl<'tree, Custom> Eq for Node<'tree, Custom> {}
impl<'tree, Custom> PartialOrd for Node<'tree, Custom> {
#[inline]
fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
Some(self.cmp(other))
}
}
impl<'tree, Custom> Ord for Node<'tree, Custom> {
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, Custom> Hash for Node<'tree, Custom> {
#[inline]
fn hash<H: Hasher>(&self, state: &mut H) {
self.id().hash(state)
}
}
impl<Custom> NodePtr<Custom> {
#[inline]
pub unsafe fn to_node<'a>(self) -> Node<'a, Custom> {
Node {
node: self.node_data.to_node(),
tree: self.tree.as_ref(),
}
}
#[inline]
pub fn cast_custom<NewCustom>(self) -> NodePtr<NewCustom> {
unsafe { std::mem::transmute(self) }
}
}
impl<Custom> PartialEq for NodePtr<Custom> {
#[inline]
fn eq(&self, other: &NodePtr<Custom>) -> bool {
self.node_data == other.node_data
}
}
impl<Custom> Eq for NodePtr<Custom> {}
impl<Custom> Hash for NodePtr<Custom> {
#[inline]
fn hash<H: Hasher>(&self, state: &mut H) {
self.node_data.hash(state)
}
}
impl NodeData {
#[inline]
pub unsafe fn to_node<'tree>(self) -> tree_sitter::Node<'tree> {
std::mem::transmute(self)
}
}
impl<'tree> From<tree_sitter::Node<'tree>> for NodeData {
#[inline]
fn from(node: tree_sitter::Node) -> Self {
unsafe { std::mem::transmute::<tree_sitter::Node<'_>, NodeData>(node) }
}
}
impl<'tree, Custom> TreeCursor<'tree, Custom> {
#[inline]
fn new(cursor: tree_sitter::TreeCursor<'tree>, tree: &'tree Tree<Custom>, is_rooted: bool) -> Self {
Self {
cursor,
tree,
child_depth: match is_rooted {
false => 0,
true => 1
}
}
}
#[inline]
pub fn node(&self) -> Node<'tree, Custom> {
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.goto(parent);
self.goto_first_child();
while self.node() != original_node {
self.goto_next_sibling();
}
self.cursor.field_name()
}
}
})
}
#[inline]
pub fn goto(&mut self, node: Node<'tree, Custom>) {
if self.cursor.node() != node.node {
self.cursor.reset(node.node);
self.child_depth = 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.0).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.goto(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.goto(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, 'tree: 'query, Custom>(
&'query mut self,
query: &'query Query,
node: Node<'tree, Custom>
) -> QueryMatches<'query, 'tree, Custom> {
QueryMatches {
query_matches: self.query_cursor.matches(&query, node.node, node.tree),
current_match: None,
tree: node.tree,
query
}
}
#[inline]
pub fn captures<'query, 'tree: 'query, Custom>(
&'query mut self,
query: &'query Query,
node: Node<'tree, Custom>
) -> QueryCaptures<'query, 'tree, Custom> {
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: 'query, Custom> QueryMatches<'query, 'tree, Custom> {
#[inline]
pub fn as_inner(&self) -> &tree_sitter::QueryMatches<'query, 'tree, &'query Tree<Custom>, &'query str> {
&self.query_matches
}
#[inline]
pub fn as_inner_mut(&mut self) -> &mut tree_sitter::QueryMatches<'query, 'tree, &'query Tree<Custom>, &'query str> {
&mut self.query_matches
}
#[inline]
pub fn into_inner(self) -> (tree_sitter::QueryMatches<'query, 'tree, &'query Tree<Custom>, &'query str>, &'query Query, &'tree Tree<Custom>) {
(self.query_matches, self.query, self.tree)
}
}
impl<'query, 'tree: 'query, Custom> StreamingIterator for QueryMatches<'query, 'tree, Custom> {
type Item = QueryMatch<'query, 'tree, Custom>;
#[inline]
fn advance(&mut self) {
self.current_match = self.query_matches.next().map(|query_match| QueryMatch {
query_match,
tree: self.tree,
query: self.query
});
}
#[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: 'query, Custom> StreamingIteratorMut for QueryMatches<'query, 'tree, Custom> {
fn get_mut(&mut self) -> Option<&mut Self::Item> {
self.current_match.as_mut()
}
}
impl<'query, 'tree: 'query, Custom> QueryCaptures<'query, 'tree, Custom> {
#[inline]
pub fn as_inner(&self) -> &tree_sitter::QueryCaptures<'query, 'tree, &'query Tree<Custom>, &'query str> {
&self.query_captures
}
#[inline]
pub fn as_inner_mut(&mut self) -> &mut tree_sitter::QueryCaptures<'query, 'tree, &'query Tree<Custom>, &'query str> {
&mut self.query_captures
}
#[inline]
pub fn into_inner(self) -> (tree_sitter::QueryCaptures<'query, 'tree, &'query Tree<Custom>, &'query str>, &'query Query, &'tree Tree<Custom>) {
(self.query_captures, self.query, self.tree)
}
}
impl<'query, 'tree: 'query, Custom> Iterator for QueryCaptures<'query, 'tree, Custom> {
type Item = QueryCapture<'query, 'tree, Custom>;
#[inline]
fn next(&mut self) -> Option<Self::Item> {
self.query_captures.next().map(|(query_match, index)|
QueryCapture::new(query_match.captures[index], self.tree, self.query))
}
}
impl<'query, 'tree, Custom> QueryMatch<'query, 'tree, Custom> {
#[inline]
pub fn iter_captures(&self) -> impl Iterator<Item = QueryCapture<'query, 'tree, Custom>> {
self.query_match.captures.iter().map(|&query_capture|
QueryCapture::new(query_capture, self.tree, self.query))
}
#[inline]
pub fn capture(&self, index: usize) -> Option<QueryCapture<'query, 'tree, Custom>> {
self.query_match.captures.get(index).map(|&query_capture|
QueryCapture::new(query_capture, self.tree, self.query))
}
#[inline]
pub fn capture_named(&self, name: &str) -> Option<QueryCapture<'query, 'tree, Custom>> {
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, Custom>> + 'a {
self.iter_captures().filter(move |capture| capture.name == name)
}
#[inline]
pub fn capture_count(&self) -> usize {
self.query_match.captures.len()
}
#[inline]
pub fn pattern_index(&self) -> usize {
self.query_match.pattern_index
}
#[inline]
pub fn id(&self) -> u32 {
self.query_match.id()
}
#[inline]
pub fn remove(self) {
self.query_match.remove()
}
#[inline]
pub fn nodes_for_capture_index(&self, capture_index: u32) -> impl Iterator<Item = Node<'tree, Custom>> + '_ {
self.query_match
.nodes_for_capture_index(capture_index)
.map(move |node| unsafe { Node::new(node, self.tree) })
}
}
impl<'query, 'tree, Custom> QueryCapture<'query, 'tree, Custom> {
#[inline]
fn new(query_capture: tree_sitter::QueryCapture<'tree>, tree: &'tree Tree<Custom>, query: &'query Query) -> 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 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.0..self.end.0
}
}
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 {
write!(f, "{}-{}", self.start, self.end)
}
}
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 Point {
#[inline]
pub fn new(row: usize, column: usize) -> Self {
Self(tree_sitter::Point { row, column })
}
#[inline]
pub fn row(&self) -> usize {
self.0.row
}
#[inline]
pub fn column(&self) -> usize {
self.0.column
}
}
impl Display for Point {
#[inline]
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
write!(f, "{}:{}", self.0.row + 1, self.0.column + 1)
}
}
impl Into<tree_sitter::Point> for Point {
#[inline]
fn into(self) -> tree_sitter::Point {
self.0
}
}
impl Range {
#[inline]
fn vec_from_ts(range: Vec<tree_sitter::Range>) -> Vec<Self> {
unsafe { std::mem::transmute(range) }
}
#[inline]
fn slice_as_ts(ranges: &[Self]) -> &[tree_sitter::Range] {
unsafe { std::mem::transmute(ranges) }
}
#[inline]
pub fn new(start_byte: usize, end_byte: usize, start_point: Point, end_point: Point) -> Self {
Self(tree_sitter::Range {
start_byte,
end_byte,
start_point: start_point.0,
end_point: end_point.0
})
}
#[inline]
pub fn start_byte(&self) -> usize {
self.0.start_byte
}
#[inline]
pub fn end_byte(&self) -> usize {
self.0.end_byte
}
#[inline]
pub fn start_point(&self) -> Point {
Point(self.0.start_point)
}
#[inline]
pub fn end_point(&self) -> Point {
Point(self.0.end_point)
}
}
impl BitOr for Range {
type Output = Range;
#[inline]
fn bitor(self, rhs: Self) -> Self::Output {
Range::new(
self.start_byte().min(rhs.start_byte()),
self.end_byte().max(rhs.end_byte()),
self.start_point().min(rhs.start_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::new(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, "{}-{}", self.start_point(), self.end_point())
}
}
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<Custom> PartialEq for SubTree<Custom> {
#[inline]
fn eq(&self, other: &SubTree<Custom>) -> bool {
self.text == other.text &&
self.range == other.range
}
}
impl<Custom> Eq for SubTree<Custom> {}
impl<Custom> Display for SubTree<Custom> {
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
write!(f, "{}", self.text)
}
}
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, Custom> PreorderTraversal<'tree, Custom> {
#[inline]
pub fn with_cursor(cursor: TreeCursor<'tree, Custom>) -> Self {
Self {
cursor,
last_state: TraversalState::Start,
}
}
#[inline]
pub fn of_tree(tree: &'tree Tree<Custom>) -> Self {
Self::with_cursor(tree.walk())
}
#[inline]
pub fn of_node(node: Node<'tree, Custom>) -> Self {
Self::with_cursor(node.walk())
}
#[inline]
pub fn peek(&mut self) -> TraversalItem<'tree, Custom> {
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, Custom> Iterator for PreorderTraversal<'tree, Custom> {
type Item = TraversalItem<'tree, Custom>;
#[inline]
fn next(&mut self) -> Option<TraversalItem<'tree, Custom>> {
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, Custom> FusedIterator for PreorderTraversal<'tree, Custom> {}
impl<'tree, Custom> Debug for Node<'tree, Custom> {
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
write!(f, "{:?}", self.node)
}
}
impl<Custom> Debug for NodePtr<Custom> {
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
write!(f, "{:?}", self.node_data)
}
}
impl<'query, 'tree, Custom> Debug for QueryMatch<'query, 'tree, Custom> {
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
write!(f, "{:?}", self.query_match)
}
}
impl<'tree, Custom> PartialEq for TraversalItem<'tree, Custom> {
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, Custom> Eq for TraversalItem<'tree, Custom> {}
impl<'tree, Custom> Clone for Node<'tree, Custom> {
fn clone(&self) -> Self {
Self {
node: self.node,
tree: self.tree
}
}
}
impl<'tree, Custom> Copy for Node<'tree, Custom> {}
impl<Custom> Clone for NodePtr<Custom> {
fn clone(&self) -> Self {
Self {
node_data: self.node_data,
tree: self.tree
}
}
}
impl<Custom> Copy for NodePtr<Custom> {}
impl<'tree, Custom> Clone for TreeCursor<'tree, Custom> {
fn clone(&self) -> Self {
Self {
cursor: self.cursor.clone(),
tree: self.tree,
child_depth: self.child_depth
}
}
}
impl<'query, 'tree, Custom> Debug for QueryCapture<'query, 'tree, Custom> {
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
f.debug_struct("QueryCapture")
.field("node", &self.node)
.field("index", &self.index)
.field("name", &self.name)
.finish()
}
}
impl<'query, 'tree, Custom> Clone for QueryCapture<'query, 'tree, Custom> {
fn clone(&self) -> Self {
Self {
node: self.node,
index: self.index,
name: self.name
}
}
}
impl<'query, 'tree, Custom> Copy for QueryCapture<'query, 'tree, Custom> {}
impl<Custom> Debug for SubTree<Custom> {
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
f.debug_struct("SubTree")
.field("text", &self.text)
.field("range", &self.range)
.field("path", &self.path)
.finish()
}
}
impl<Custom> Clone for SubTree<Custom> {
fn clone(&self) -> Self {
Self {
text: self.text.clone(),
range: self.range,
path: self.path.clone(),
root: self.root
}
}
}
impl<'tree, Custom> Clone for PreorderTraversal<'tree, Custom> {
fn clone(&self) -> Self {
Self {
cursor: self.cursor.clone(),
last_state: self.last_state
}
}
}
impl<'tree, Custom> Debug for TraversalItem<'tree, Custom> {
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
f.debug_struct("TraversalItem")
.field("node", &self.node)
.field("field_name", &self.field_name)
.field("last_state", &self.last_state)
.finish()
}
}
impl<'tree, Custom> Clone for TraversalItem<'tree, Custom> {
fn clone(&self) -> Self {
Self {
node: self.node,
field_name: self.field_name,
last_state: self.last_state
}
}
}
impl<'tree, Custom> Copy for TraversalItem<'tree, Custom> {}
impl<'tree, Custom> Hash for TraversalItem<'tree, Custom> {
fn hash<H: Hasher>(&self, state: &mut H) {
self.node.hash(state);
self.last_state.hash(state);
}
}