Add misssing docs to rust binding

This commit is contained in:
Max Brunsfeld 2019-11-08 12:29:26 -08:00
parent a7824cf59d
commit d68dfa78b2
3 changed files with 280 additions and 58 deletions

View file

@ -157,7 +157,7 @@ extern "C" {
pub fn ts_parser_language(self_: *const TSParser) -> *const TSLanguage;
}
extern "C" {
#[doc = " Set the spans of text that the parser should include when parsing."]
#[doc = " Set the ranges of text that the parser should include when parsing."]
#[doc = ""]
#[doc = " By default, the parser will always include entire documents. This function"]
#[doc = " allows you to parse only a *portion* of a document but still return a syntax"]
@ -252,13 +252,15 @@ extern "C" {
#[doc = " by default, it will resume where it left off on the next call to"]
#[doc = " `ts_parser_parse` or other parsing functions. If you don\'t want to resume,"]
#[doc = " and instead intend to use this parser to parse some other document, you must"]
#[doc = " call this `ts_parser_reset` first."]
#[doc = " call `ts_parser_reset` first."]
pub fn ts_parser_reset(self_: *mut TSParser);
}
extern "C" {
#[doc = " Set the maximum duration in microseconds that parsing should be allowed to"]
#[doc = " take before halting. If parsing takes longer than this, it will halt early,"]
#[doc = " returning NULL. See `ts_parser_parse` for more information."]
#[doc = " take before halting."]
#[doc = ""]
#[doc = " If parsing takes longer than this, it will halt early, returning NULL."]
#[doc = " See `ts_parser_parse` for more information."]
pub fn ts_parser_set_timeout_micros(self_: *mut TSParser, timeout: u64);
}
extern "C" {
@ -266,10 +268,11 @@ extern "C" {
pub fn ts_parser_timeout_micros(self_: *const TSParser) -> u64;
}
extern "C" {
#[doc = " Set the parser\'s current cancellation flag pointer. If a non-null pointer is"]
#[doc = " assigned, then the parser will periodically read from this pointer during"]
#[doc = " parsing. If it reads a non-zero value, it will halt early, returning NULL."]
#[doc = " See `ts_parser_parse` for more information."]
#[doc = " Set the parser\'s current cancellation flag pointer."]
#[doc = ""]
#[doc = " If a non-null pointer is assigned, then the parser will periodically read"]
#[doc = " from this pointer during parsing. If it reads a non-zero value, it will"]
#[doc = " halt early, returning NULL. See `ts_parser_parse` for more information."]
pub fn ts_parser_set_cancellation_flag(self_: *mut TSParser, flag: *const usize);
}
extern "C" {
@ -523,7 +526,7 @@ extern "C" {
pub fn ts_tree_cursor_delete(arg1: *mut TSTreeCursor);
}
extern "C" {
#[doc = " Re-initialize a tree cursor to start at a different ndoe."]
#[doc = " Re-initialize a tree cursor to start at a different node."]
pub fn ts_tree_cursor_reset(arg1: *mut TSTreeCursor, arg2: TSNode);
}
extern "C" {
@ -561,14 +564,14 @@ extern "C" {
pub fn ts_tree_cursor_goto_next_sibling(arg1: *mut TSTreeCursor) -> bool;
}
extern "C" {
#[doc = " Move the cursor to the first schild of its current node."]
#[doc = " Move the cursor to the first child of its current node."]
#[doc = ""]
#[doc = " This returns `true` if the cursor successfully moved, and returns `false`"]
#[doc = " if there were no children."]
pub fn ts_tree_cursor_goto_first_child(arg1: *mut TSTreeCursor) -> bool;
}
extern "C" {
#[doc = " Move the cursor to the first schild of its current node that extends beyond"]
#[doc = " Move the cursor to the first child of its current node that extends beyond"]
#[doc = " the given byte offset."]
#[doc = ""]
#[doc = " This returns the index of the child node if one was found, and returns -1"]

View file

@ -17,32 +17,41 @@ use std::ptr::NonNull;
use std::sync::atomic::AtomicUsize;
use std::{char, fmt, ptr, slice, str, u16};
/// The latest ABI version that is supported by the current version of the
/// library.
///
/// When Languages are generated by the Tree-sitter CLI, they are
/// assigned an ABI version number that corresponds to the current CLI version.
/// The Tree-sitter library is generally backwards-compatible with languages
/// generated using older CLI versions, but is not forwards-compatible.
pub const LANGUAGE_VERSION: usize = ffi::TREE_SITTER_LANGUAGE_VERSION;
/// The earliest ABI version that is supported by the current version of the
/// library.
pub const MIN_COMPATIBLE_LANGUAGE_VERSION: usize = ffi::TREE_SITTER_MIN_COMPATIBLE_LANGUAGE_VERSION;
pub const PARSER_HEADER: &'static str = include_str!("../include/tree_sitter/parser.h");
/// An opaque object that defines how to parse a particular language. The code for each
/// `Language` is generated by the Tree-sitter CLI.
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
#[repr(transparent)]
pub struct Language(*const ffi::TSLanguage);
#[derive(Debug, PartialEq, Eq)]
pub struct LanguageError {
version: usize,
}
#[derive(Debug, PartialEq, Eq)]
pub enum LogType {
Parse,
Lex,
}
type Logger<'a> = Box<dyn FnMut(LogType, &str) + 'a>;
/// A tree that represents the syntactic structure of a source code file.
pub struct Tree(NonNull<ffi::TSTree>);
/// A position in a multi-line text document, in terms of rows and columns.
///
/// Rows and columns are zero-based.
#[derive(Clone, Copy, Debug, PartialEq, Eq, PartialOrd, Ord)]
pub struct Point {
pub row: usize,
pub column: usize,
}
/// A range of positions in a multi-line text document, both in terms of bytes and of
/// rows and columns.
#[derive(Clone, Copy, Debug, PartialEq, Eq, PartialOrd, Ord)]
pub struct Range {
pub start_byte: usize,
@ -51,6 +60,7 @@ pub struct Range {
pub end_point: Point,
}
/// A summary of a change to a text document.
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
pub struct InputEdit {
pub start_byte: usize,
@ -61,30 +71,28 @@ pub struct InputEdit {
pub new_end_position: Point,
}
/// A single node within a syntax `Tree`.
#[derive(Clone, Copy)]
#[repr(transparent)]
pub struct Node<'a>(ffi::TSNode, PhantomData<&'a ()>);
/// A stateful object that this is used to produce a `Tree` based on some source code.
pub struct Parser(NonNull<ffi::TSParser>);
pub struct Tree(NonNull<ffi::TSTree>);
/// A type of log message.
#[derive(Debug, PartialEq, Eq)]
pub enum LogType {
Parse,
Lex,
}
/// A callback that receives log messages during parser.
type Logger<'a> = Box<dyn FnMut(LogType, &str) + 'a>;
/// A stateful object for walking a syntax `Tree` efficiently.
pub struct TreeCursor<'a>(ffi::TSTreeCursor, PhantomData<&'a ()>);
#[derive(Debug)]
enum TextPredicate {
CaptureEqString(u32, String),
CaptureEqCapture(u32, u32),
CaptureMatchString(u32, regex::bytes::Regex),
}
#[derive(Debug, PartialEq, Eq)]
pub struct QueryProperty {
pub key: Box<str>,
pub value: Option<Box<str>>,
pub capture_id: Option<usize>,
}
/// A set of patterns that match nodes in a syntax tree.
#[derive(Debug)]
pub struct Query {
ptr: NonNull<ffi::TSQuery>,
@ -94,8 +102,18 @@ pub struct Query {
property_predicates: Vec<Box<[(QueryProperty, bool)]>>,
}
/// A stateful object for executing a `Query` on a syntax `Tree`.
pub struct QueryCursor(NonNull<ffi::TSQueryCursor>);
/// A key-value pair associated with a particular pattern in a `Query`.
#[derive(Debug, PartialEq, Eq)]
pub struct QueryProperty {
pub key: Box<str>,
pub value: Option<Box<str>>,
pub capture_id: Option<usize>,
}
/// A match of a `Query` to a particular set of `Node`s.
pub struct QueryMatch<'a> {
pub pattern_index: usize,
pub captures: &'a [QueryCapture<'a>],
@ -103,12 +121,14 @@ pub struct QueryMatch<'a> {
cursor: *mut ffi::TSQueryCursor,
}
/// A sequence of `QueryCapture`s within a `QueryMatch`.
pub struct QueryCaptures<'a, T: AsRef<[u8]>> {
ptr: *mut ffi::TSQueryCursor,
query: &'a Query,
text_callback: Box<dyn FnMut(Node<'a>) -> T + 'a>,
}
/// A particular `Node` that has been captured with a particular name within a `Query`.
#[derive(Clone, Copy)]
#[repr(C)]
pub struct QueryCapture<'a> {
@ -116,6 +136,13 @@ pub struct QueryCapture<'a> {
pub index: u32,
}
/// An error that occurred when trying to assign an incompatible `Language` to a `Parser`.
#[derive(Debug, PartialEq, Eq)]
pub struct LanguageError {
version: usize,
}
/// An error that occurred when trying to create a `Query`.
#[derive(Debug, PartialEq, Eq)]
pub enum QueryError {
Syntax(usize, String),
@ -125,35 +152,51 @@ pub enum QueryError {
Predicate(String),
}
#[derive(Debug)]
enum TextPredicate {
CaptureEqString(u32, String),
CaptureEqCapture(u32, u32),
CaptureMatchString(u32, regex::bytes::Regex),
}
impl Language {
/// Get the ABI version number that indicates which version of the Tree-sitter CLI
/// that was used to generate this `Language`.
pub fn version(&self) -> usize {
unsafe { ffi::ts_language_version(self.0) as usize }
}
/// Get the number of distinct node types in this language.
pub fn node_kind_count(&self) -> usize {
unsafe { ffi::ts_language_symbol_count(self.0) as usize }
}
/// Get the name of the node kind for the given numerical id.
pub fn node_kind_for_id(&self, id: u16) -> &'static str {
unsafe { CStr::from_ptr(ffi::ts_language_symbol_name(self.0, id)) }
.to_str()
.unwrap()
}
/// Check if the node type for the given numerical id is named (as opposed
/// to an anonymous node type).
pub fn node_kind_is_named(&self, id: u16) -> bool {
unsafe { ffi::ts_language_symbol_type(self.0, id) == ffi::TSSymbolType_TSSymbolTypeRegular }
}
/// Get the number of distinct field names in this language.
pub fn field_count(&self) -> usize {
unsafe { ffi::ts_language_field_count(self.0) as usize }
}
/// Get the field names for the given numerical id.
pub fn field_name_for_id(&self, field_id: u16) -> &'static str {
unsafe { CStr::from_ptr(ffi::ts_language_field_name_for_id(self.0, field_id)) }
.to_str()
.unwrap()
}
/// Get the numerical id for the given field name.
pub fn field_id_for_name(&self, field_name: impl AsRef<[u8]>) -> Option<u16> {
let field_name = field_name.as_ref();
let id = unsafe {
@ -176,9 +219,7 @@ impl fmt::Display for LanguageError {
write!(
f,
"Incompatible language version {}. Expected minimum {}, maximum {}",
self.version,
ffi::TREE_SITTER_MIN_COMPATIBLE_LANGUAGE_VERSION,
ffi::TREE_SITTER_LANGUAGE_VERSION
self.version, MIN_COMPATIBLE_LANGUAGE_VERSION, LANGUAGE_VERSION,
)
}
}
@ -198,13 +239,11 @@ impl Parser {
/// assigned. True means assignment succeeded. False means there was a version
/// mismatch: the language was generated with an incompatible version of the
/// Tree-sitter CLI. Check the language's version using `ts_language_version`
/// and compare it to this library's `TREE_SITTER_LANGUAGE_VERSION` and
/// `TREE_SITTER_MIN_COMPATIBLE_LANGUAGE_VERSION` constants.
/// and compare it to this library's `LANGUAGE_VERSION` and
/// `MIN_COMPATIBLE_LANGUAGE_VERSION` constants.
pub fn set_language(&mut self, language: Language) -> Result<(), LanguageError> {
let version = language.version();
if version < ffi::TREE_SITTER_MIN_COMPATIBLE_LANGUAGE_VERSION
|| version > ffi::TREE_SITTER_LANGUAGE_VERSION
{
if version < MIN_COMPATIBLE_LANGUAGE_VERSION || version > LANGUAGE_VERSION {
Err(LanguageError { version })
} else {
unsafe {
@ -214,6 +253,7 @@ impl Parser {
}
}
/// Get the parser's current language.
pub fn language(&self) -> Option<Language> {
let ptr = unsafe { ffi::ts_parser_language(self.0.as_ptr()) };
if ptr.is_null() {
@ -223,11 +263,13 @@ impl Parser {
}
}
/// Get the parser's current logger.
pub fn logger(&self) -> Option<&Logger> {
let logger = unsafe { ffi::ts_parser_logger(self.0.as_ptr()) };
unsafe { (logger.payload as *mut Logger).as_ref() }
}
/// Set the logging callback that a parser should use during parsing.
pub fn set_logger(&mut self, logger: Option<Logger>) {
let prev_logger = unsafe { ffi::ts_parser_logger(self.0.as_ptr()) };
if !prev_logger.payload.is_null() {
@ -270,12 +312,17 @@ impl Parser {
unsafe { ffi::ts_parser_set_logger(self.0.as_ptr(), c_logger) };
}
/// Set the destination to which the parser should write debugging graphs
/// during parsing. The graphs are formatted in the DOT language. You may want
/// to pipe these graphs directly to a `dot(1)` process in order to generate
/// SVG output.
#[cfg(unix)]
pub fn print_dot_graphs(&mut self, file: &impl AsRawFd) {
let fd = file.as_raw_fd();
unsafe { ffi::ts_parser_print_dot_graphs(self.0.as_ptr(), ffi::dup(fd)) }
}
/// Stop the parser from printing debugging graphs while parsing.
pub fn stop_printing_dot_graphs(&mut self) {
unsafe { ffi::ts_parser_print_dot_graphs(self.0.as_ptr(), -1) }
}
@ -429,18 +476,38 @@ impl Parser {
}
}
/// Instruct the parser to start the next parse from the beginning.
///
/// If the parser previously failed because of a timeout or a cancellation, then
/// by default, it will resume where it left off on the next call to `parse` or
/// other parsing functions. If you don't want to resume, and instead intend to
/// use this parser to parse some other document, you must call `reset` first.
pub fn reset(&mut self) {
unsafe { ffi::ts_parser_reset(self.0.as_ptr()) }
}
/// Get the duration in microseconds that parsing is allowed to take.
///
/// This is set via [set_timeout_micros].
pub fn timeout_micros(&self) -> u64 {
unsafe { ffi::ts_parser_timeout_micros(self.0.as_ptr()) }
}
/// Set the maximum duration in microseconds that parsing should be allowed to
/// take before halting.
///
/// If parsing takes longer than this, it will halt early, returning `None`.
/// See `parse` for more information.
pub fn set_timeout_micros(&mut self, timeout_micros: u64) {
unsafe { ffi::ts_parser_set_timeout_micros(self.0.as_ptr(), timeout_micros) }
}
/// Set the ranges of text that the parser should include when parsing.
///
/// By default, the parser will always include entire documents. This function
/// allows you to parse only a *portion* of a document but still return a syntax
/// tree whose ranges match up with the document as a whole. You can also pass
/// multiple disjoint ranges.
pub fn set_included_ranges(&mut self, ranges: &[Range]) {
let ts_ranges: Vec<ffi::TSRange> =
ranges.iter().cloned().map(|range| range.into()).collect();
@ -453,10 +520,16 @@ impl Parser {
};
}
/// Get the parser's current cancellation flag pointer.
pub unsafe fn cancellation_flag(&self) -> Option<&AtomicUsize> {
(ffi::ts_parser_cancellation_flag(self.0.as_ptr()) as *const AtomicUsize).as_ref()
}
/// Set the parser's current cancellation flag pointer.
///
/// If a pointer is assigned, then the parser will periodically read from
/// this pointer during parsing. If it reads a non-zero value, it will
/// halt early, returning `None`. See [parse] for more information.
pub unsafe fn set_cancellation_flag(&self, flag: Option<&AtomicUsize>) {
if let Some(flag) = flag {
ffi::ts_parser_set_cancellation_flag(
@ -478,23 +551,38 @@ impl Drop for Parser {
}
impl Tree {
/// Get the root node of the syntax tree.
pub fn root_node(&self) -> Node {
Node::new(unsafe { ffi::ts_tree_root_node(self.0.as_ptr()) }).unwrap()
}
/// Get the language that was used to parse the syntax tree.
pub fn language(&self) -> Language {
Language(unsafe { ffi::ts_tree_language(self.0.as_ptr()) })
}
/// Edit the syntax tree to keep it in sync with source code that has been
/// edited.
///
/// You must describe the edit both in terms of byte offsets and in terms of
/// row/column coordinates.
pub fn edit(&mut self, edit: &InputEdit) {
let edit = edit.into();
unsafe { ffi::ts_tree_edit(self.0.as_ptr(), &edit) };
}
/// Create a new [TreeCursor] starting from the root of the tree.
pub fn walk(&self) -> TreeCursor {
self.root_node().walk()
}
/// Compare this old edited syntax tree to a new syntax tree representing the same
/// document, returning a sequence of ranges whose syntactic structure has changed.
///
/// For this to work correctly, this syntax tree must have been edited such that its
/// ranges match up to the new tree. Generally, you'll want to call this method right
/// after calling one of the [Parser::parse] functions. Call it on the old tree that
/// was passed to parse, and pass the new tree that was returned from `parse`.
pub fn changed_ranges(&self, other: &Tree) -> impl ExactSizeIterator<Item = Range> {
let mut count = 0;
unsafe {
@ -535,52 +623,78 @@ impl<'tree> Node<'tree> {
}
}
/// Get this node's type as a numerical id.
pub fn kind_id(&self) -> u16 {
unsafe { ffi::ts_node_symbol(self.0) }
}
/// Get this node's type as a string.
pub fn kind(&self) -> &'static str {
unsafe { CStr::from_ptr(ffi::ts_node_type(self.0)) }
.to_str()
.unwrap()
}
/// Check if this node is *named*.
///
/// Named nodes correspond to named rules in the grammar, whereas *anonymous* nodes
/// correspond to string literals in the grammar.
pub fn is_named(&self) -> bool {
unsafe { ffi::ts_node_is_named(self.0) }
}
/// Check if this node is *extra*.
///
/// Extra nodes represent things like comments, which are not required the grammar,
/// but can appear anywhere.
pub fn is_extra(&self) -> bool {
unsafe { ffi::ts_node_is_extra(self.0) }
}
/// Check if this node has been edited.
pub fn has_changes(&self) -> bool {
unsafe { ffi::ts_node_has_changes(self.0) }
}
/// Check if this node represents a syntax error or contains any syntax errors anywhere
/// within it.
pub fn has_error(&self) -> bool {
unsafe { ffi::ts_node_has_error(self.0) }
}
/// Check if this node represents a syntax error.
///
/// Syntax errors represent parts of the code that could not be incorporated into a
/// valid syntax tree.
pub fn is_error(&self) -> bool {
self.kind_id() == u16::MAX
}
/// Check if this node is *missing*.
///
/// Missing nodes are inserted by the parser in order to recover from certain kinds of
/// syntax errors.
pub fn is_missing(&self) -> bool {
unsafe { ffi::ts_node_is_missing(self.0) }
}
/// Get the byte offsets where this node starts.
pub fn start_byte(&self) -> usize {
unsafe { ffi::ts_node_start_byte(self.0) as usize }
}
/// Get the byte offsets where this node end.
pub fn end_byte(&self) -> usize {
unsafe { ffi::ts_node_end_byte(self.0) as usize }
}
/// Get the byte range of source code that this node represents.
pub fn byte_range(&self) -> std::ops::Range<usize> {
self.start_byte()..self.end_byte()
}
/// Get the range of source code that this node represents, both in terms of raw bytes
/// and of row/column coordinates.
pub fn range(&self) -> Range {
Range {
start_byte: self.start_byte(),
@ -590,20 +704,29 @@ impl<'tree> Node<'tree> {
}
}
/// Get this node's start position in terms of rows and columns.
pub fn start_position(&self) -> Point {
let result = unsafe { ffi::ts_node_start_point(self.0) };
result.into()
}
/// Get this node's end position in terms of rows and columns.
pub fn end_position(&self) -> Point {
let result = unsafe { ffi::ts_node_end_point(self.0) };
result.into()
}
/// Get the node's child at the given index, where zero represents the first
/// child.
pub fn child(&self, i: usize) -> Option<Self> {
Self::new(unsafe { ffi::ts_node_child(self.0, i as u32) })
}
/// Get the first child with the given field name.
///
/// To access the node's children and their field names more efficiently, create
/// a [TreeCursor] using [Node::walk]. Then, while walking the tree, access each
/// node's field id using [TreeCursor::field_name] or [TreeCursor::field_id].
pub fn child_by_field_name(&self, field_name: impl AsRef<[u8]>) -> Option<Self> {
let field_name = field_name.as_ref();
Self::new(unsafe {
@ -615,10 +738,15 @@ impl<'tree> Node<'tree> {
})
}
/// Get this node's child with the given numerical field id.
///
/// See also [child_by_field_name]. You can convert a field name to an id using
/// [Language::field_id_for_name].
pub fn child_by_field_id(&self, field_id: u16) -> Option<Self> {
Self::new(unsafe { ffi::ts_node_child_by_field_id(self.0, field_id) })
}
/// Get this node's number of children.
pub fn child_count(&self) -> usize {
unsafe { ffi::ts_node_child_count(self.0) as usize }
}
@ -630,52 +758,67 @@ impl<'tree> Node<'tree> {
.map(move |i| me.child(i).unwrap())
}
/// Get this node's *named* child at the given index.
///
/// See also [Node.is_named].
pub fn named_child<'a>(&'a self, i: usize) -> Option<Self> {
Self::new(unsafe { ffi::ts_node_named_child(self.0, i as u32) })
}
/// Get this node's number of *named* children.
///
/// See also [Node.is_named].
pub fn named_child_count(&self) -> usize {
unsafe { ffi::ts_node_named_child_count(self.0) as usize }
}
/// Get this node's immediate parent.
pub fn parent(&self) -> Option<Self> {
Self::new(unsafe { ffi::ts_node_parent(self.0) })
}
/// Get this node's next sibling.
pub fn next_sibling(&self) -> Option<Self> {
Self::new(unsafe { ffi::ts_node_next_sibling(self.0) })
}
/// Get this node's previous sibling.
pub fn prev_sibling(&self) -> Option<Self> {
Self::new(unsafe { ffi::ts_node_prev_sibling(self.0) })
}
/// Get this node's next named sibling.
pub fn next_named_sibling(&self) -> Option<Self> {
Self::new(unsafe { ffi::ts_node_next_named_sibling(self.0) })
}
/// Get this node's previous named sibling.
pub fn prev_named_sibling(&self) -> Option<Self> {
Self::new(unsafe { ffi::ts_node_prev_named_sibling(self.0) })
}
/// Get the smallest node within this node that spans the given range.
pub fn descendant_for_byte_range(&self, start: usize, end: usize) -> Option<Self> {
Self::new(unsafe {
ffi::ts_node_descendant_for_byte_range(self.0, start as u32, end as u32)
})
}
/// Get the smallest named node within this node that spans the given range.
pub fn named_descendant_for_byte_range(&self, start: usize, end: usize) -> Option<Self> {
Self::new(unsafe {
ffi::ts_node_named_descendant_for_byte_range(self.0, start as u32, end as u32)
})
}
/// Get the smallest node within this node that spans the given range.
pub fn descendant_for_point_range(&self, start: Point, end: Point) -> Option<Self> {
Self::new(unsafe {
ffi::ts_node_descendant_for_point_range(self.0, start.into(), end.into())
})
}
/// Get the smallest named node within this node that spans the given range.
pub fn named_descendant_for_point_range(&self, start: Point, end: Point) -> Option<Self> {
Self::new(unsafe {
ffi::ts_node_named_descendant_for_point_range(self.0, start.into(), end.into())
@ -700,10 +843,18 @@ impl<'tree> Node<'tree> {
&source.as_ref()[self.start_byte()..self.end_byte()]
}
/// Create a new [TreeCursor] starting from this node.
pub fn walk(&self) -> TreeCursor<'tree> {
TreeCursor(unsafe { ffi::ts_tree_cursor_new(self.0) }, PhantomData)
}
/// Edit this node to keep it in-sync with source code that has been edited.
///
/// This function is only rarely needed. When you edit a syntax tree with the
/// [Tree::edit] method, all of the nodes that you retrieve from the tree
/// afterward will already reflect the edit. You only need to use [Node::edit]
/// when you have a specific [Node] instance that you want to keep and continue
/// to use after an edit.
pub fn edit(&mut self, edit: &InputEdit) {
let edit = edit.into();
unsafe { ffi::ts_node_edit(&mut self.0 as *mut ffi::TSNode, &edit) }
@ -729,6 +880,7 @@ impl<'a> fmt::Debug for Node<'a> {
}
impl<'a> TreeCursor<'a> {
/// Get the tree cursor's current [Node].
pub fn node(&self) -> Node<'a> {
Node(
unsafe { ffi::ts_tree_cursor_current_node(&self.0) },
@ -736,6 +888,9 @@ impl<'a> TreeCursor<'a> {
)
}
/// Get the numerical field id of this tree cursor's current node.
///
/// See also [field_name].
pub fn field_id(&self) -> Option<u16> {
unsafe {
let id = ffi::ts_tree_cursor_current_field_id(&self.0);
@ -747,6 +902,7 @@ impl<'a> TreeCursor<'a> {
}
}
/// Get the field name of this tree cursor's current node.
pub fn field_name(&self) -> Option<&str> {
unsafe {
let ptr = ffi::ts_tree_cursor_current_field_name(&self.0);
@ -758,19 +914,36 @@ impl<'a> TreeCursor<'a> {
}
}
/// Move this cursor to the first child of its current node.
///
/// This returns `true` if the cursor successfully moved, and returns `false`
/// if there were no children.
pub fn goto_first_child(&mut self) -> bool {
return unsafe { ffi::ts_tree_cursor_goto_first_child(&mut self.0) };
}
/// Move this cursor to the parent of its current node.
///
/// This returns `true` if the cursor successfully moved, and returns `false`
/// if there was no parent node (the cursor was already on the root node).
pub fn goto_parent(&mut self) -> bool {
return unsafe { ffi::ts_tree_cursor_goto_parent(&mut self.0) };
}
/// Move this cursor to the next sibling of its current node.
///
/// This returns `true` if the cursor successfully moved, and returns `false`
/// if there was no next sibling node.
pub fn goto_next_sibling(&mut self) -> bool {
return unsafe { ffi::ts_tree_cursor_goto_next_sibling(&mut self.0) };
}
pub fn goto_first_child_for_index(&mut self, index: usize) -> Option<usize> {
/// Move this cursor to the first child of its current node that extends beyond
/// the given byte offset.
///
/// This returns the index of the child node if one was found, and returns `None`
/// if no such child was found.
pub fn goto_first_child_for_byte(&mut self, index: usize) -> Option<usize> {
let result =
unsafe { ffi::ts_tree_cursor_goto_first_child_for_byte(&mut self.0, index as u32) };
if result < 0 {
@ -780,6 +953,7 @@ impl<'a> TreeCursor<'a> {
}
}
/// Re-initialize this tree cursor to start at a different node.
pub fn reset(&mut self, node: Node<'a>) {
unsafe { ffi::ts_tree_cursor_reset(&mut self.0, node.0) };
}
@ -792,6 +966,11 @@ impl<'a> Drop for TreeCursor<'a> {
}
impl Query {
/// Create a new query from a string containing one or more S-expression
/// patterns.
///
///The query is associated with a particular language, and can only be run
/// on syntax nodes parsed with that language.
pub fn new(language: Language, source: &str) -> Result<Self, QueryError> {
let mut error_offset = 0u32;
let mut error_type: ffi::TSQueryError = 0;
@ -1007,6 +1186,7 @@ impl Query {
Ok(result)
}
/// Get the byte offset where the given pattern starts in the query's source.
pub fn start_byte_for_pattern(&self, pattern_index: usize) -> usize {
if pattern_index >= self.text_predicates.len() {
panic!(
@ -1020,22 +1200,30 @@ impl Query {
}
}
/// Get the number of patterns in the query.
pub fn pattern_count(&self) -> usize {
unsafe { ffi::ts_query_pattern_count(self.ptr.as_ptr()) as usize }
}
/// Get the names of the captures used in the query.
pub fn capture_names(&self) -> &[String] {
&self.capture_names
}
/// Get the properties that are checked for the given pattern index.
pub fn property_predicates(&self, index: usize) -> &[(QueryProperty, bool)] {
&self.property_predicates[index]
}
/// Get the properties that are set for the given pattern index.
pub fn property_settings(&self, index: usize) -> &[QueryProperty] {
&self.property_settings[index]
}
/// Disable a certain capture within a query.
///
/// This prevents the capture from being returned in matches, and also avoids any
/// resource usage associated with recording the capture.
pub fn disable_capture(&mut self, name: &str) {
unsafe {
ffi::ts_query_disable_capture(
@ -1099,10 +1287,23 @@ impl Query {
}
impl QueryCursor {
/// Create a new cursor for executing a given query.
///
/// The cursor stores the state that is needed to iteratively search
/// for matches.
/// 1. Call [matches] to iterate over all of the *matches* in the order that they were
/// found. Each match contains the index of the pattern that matched, and a list of
/// captures. Because multiple patterns can match the same set of nodes, one match
/// may contain captures that appear *before* some of the captures from a previous
/// match.
/// 2. Call `captures` to iterate over all of the individual *captures* in the order that
/// they appear. This is useful if don't care about which pattern matched, and just want
/// a single, ordered sequence of captures.
pub fn new() -> Self {
QueryCursor(unsafe { NonNull::new_unchecked(ffi::ts_query_cursor_new()) })
}
/// Iterate through the matches of a given query.
pub fn matches<'a>(
&mut self,
query: &'a Query,
@ -1126,6 +1327,7 @@ impl QueryCursor {
})
}
/// Iterate through the captures of a given query.
pub fn captures<'a, T: AsRef<[u8]>>(
&mut self,
query: &'a Query,
@ -1141,6 +1343,7 @@ impl QueryCursor {
}
}
/// Set the range in which the query will be executed, in terms of byte offsets.
pub fn set_byte_range(&mut self, start: usize, end: usize) -> &mut Self {
unsafe {
ffi::ts_query_cursor_set_byte_range(self.0.as_ptr(), start as u32, end as u32);
@ -1148,6 +1351,7 @@ impl QueryCursor {
self
}
/// Set the range in which the query will be executed, in terms of rows and columns.
pub fn set_point_range(&mut self, start: Point, end: Point) -> &mut Self {
unsafe {
ffi::ts_query_cursor_set_point_range(self.0.as_ptr(), start.into(), end.into());

View file

@ -14,7 +14,19 @@ extern "C" {
/* Section - ABI Versioning */
/****************************/
/**
* The latest ABI version that is supported by the current version of the
* library. When Languages are generated by the Tree-sitter CLI, they are
* assigned an ABI version number that corresponds to the current CLI version.
* The Tree-sitter library is generally backwards-compatible with languages
* generated using older CLI versions, but is not forwards-compatible.
*/
#define TREE_SITTER_LANGUAGE_VERSION 11
/**
* The earliest ABI version that is supported by the current version of the
* library.
*/
#define TREE_SITTER_MIN_COMPATIBLE_LANGUAGE_VERSION 9
/*******************/
@ -152,7 +164,7 @@ bool ts_parser_set_language(TSParser *self, const TSLanguage *language);
const TSLanguage *ts_parser_language(const TSParser *self);
/**
* Set the spans of text that the parser should include when parsing.
* Set the ranges of text that the parser should include when parsing.
*
* By default, the parser will always include entire documents. This function
* allows you to parse only a *portion* of a document but still return a syntax
@ -259,14 +271,16 @@ TSTree *ts_parser_parse_string_encoding(
* by default, it will resume where it left off on the next call to
* `ts_parser_parse` or other parsing functions. If you don't want to resume,
* and instead intend to use this parser to parse some other document, you must
* call this `ts_parser_reset` first.
* call `ts_parser_reset` first.
*/
void ts_parser_reset(TSParser *self);
/**
* Set the maximum duration in microseconds that parsing should be allowed to
* take before halting. If parsing takes longer than this, it will halt early,
* returning NULL. See `ts_parser_parse` for more information.
* take before halting.
*
* If parsing takes longer than this, it will halt early, returning NULL.
* See `ts_parser_parse` for more information.
*/
void ts_parser_set_timeout_micros(TSParser *self, uint64_t timeout);
@ -276,10 +290,11 @@ void ts_parser_set_timeout_micros(TSParser *self, uint64_t timeout);
uint64_t ts_parser_timeout_micros(const TSParser *self);
/**
* Set the parser's current cancellation flag pointer. If a non-null pointer is
* assigned, then the parser will periodically read from this pointer during
* parsing. If it reads a non-zero value, it will halt early, returning NULL.
* See `ts_parser_parse` for more information.
* Set the parser's current cancellation flag pointer.
*
* If a non-null pointer is assigned, then the parser will periodically read
* from this pointer during parsing. If it reads a non-zero value, it will
* halt early, returning NULL. See `ts_parser_parse` for more information.
*/
void ts_parser_set_cancellation_flag(TSParser *self, const size_t *flag);
@ -575,7 +590,7 @@ TSTreeCursor ts_tree_cursor_new(TSNode);
void ts_tree_cursor_delete(TSTreeCursor *);
/**
* Re-initialize a tree cursor to start at a different ndoe.
* Re-initialize a tree cursor to start at a different node.
*/
void ts_tree_cursor_reset(TSTreeCursor *, TSNode);
@ -617,7 +632,7 @@ bool ts_tree_cursor_goto_parent(TSTreeCursor *);
bool ts_tree_cursor_goto_next_sibling(TSTreeCursor *);
/**
* Move the cursor to the first schild of its current node.
* Move the cursor to the first child of its current node.
*
* This returns `true` if the cursor successfully moved, and returns `false`
* if there were no children.
@ -625,7 +640,7 @@ bool ts_tree_cursor_goto_next_sibling(TSTreeCursor *);
bool ts_tree_cursor_goto_first_child(TSTreeCursor *);
/**
* Move the cursor to the first schild of its current node that extends beyond
* Move the cursor to the first child of its current node that extends beyond
* the given byte offset.
*
* This returns the index of the child node if one was found, and returns -1