From d68dfa78b2b394d5ad95ebba4cf9ed59d8a224d3 Mon Sep 17 00:00:00 2001 From: Max Brunsfeld Date: Fri, 8 Nov 2019 12:29:26 -0800 Subject: [PATCH] Add misssing docs to rust binding --- lib/binding_rust/bindings.rs | 25 +-- lib/binding_rust/lib.rs | 276 +++++++++++++++++++++++++++++----- lib/include/tree_sitter/api.h | 37 +++-- 3 files changed, 280 insertions(+), 58 deletions(-) diff --git a/lib/binding_rust/bindings.rs b/lib/binding_rust/bindings.rs index 31d5d544..e3d2a300 100644 --- a/lib/binding_rust/bindings.rs +++ b/lib/binding_rust/bindings.rs @@ -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"] diff --git a/lib/binding_rust/lib.rs b/lib/binding_rust/lib.rs index 10ef51e4..5b598912 100644 --- a/lib/binding_rust/lib.rs +++ b/lib/binding_rust/lib.rs @@ -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; +/// A tree that represents the syntactic structure of a source code file. +pub struct Tree(NonNull); +/// 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); -pub struct Tree(NonNull); +/// 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; + +/// 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, - pub value: Option>, - pub capture_id: Option, -} - +/// A set of patterns that match nodes in a syntax tree. #[derive(Debug)] pub struct Query { ptr: NonNull, @@ -94,8 +102,18 @@ pub struct Query { property_predicates: Vec>, } +/// A stateful object for executing a `Query` on a syntax `Tree`. pub struct QueryCursor(NonNull); +/// A key-value pair associated with a particular pattern in a `Query`. +#[derive(Debug, PartialEq, Eq)] +pub struct QueryProperty { + pub key: Box, + pub value: Option>, + pub capture_id: Option, +} + +/// 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) -> 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 { 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 { 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) { 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 = 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 { 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 { 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::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 { 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::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::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::new(unsafe { ffi::ts_node_parent(self.0) }) } + /// Get this node's next sibling. pub fn next_sibling(&self) -> Option { Self::new(unsafe { ffi::ts_node_next_sibling(self.0) }) } + /// Get this node's previous sibling. pub fn prev_sibling(&self) -> Option { 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::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::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::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::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::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::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 { 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 { + /// 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 { 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 { 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()); diff --git a/lib/include/tree_sitter/api.h b/lib/include/tree_sitter/api.h index ad351168..2a23c201 100644 --- a/lib/include/tree_sitter/api.h +++ b/lib/include/tree_sitter/api.h @@ -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