use anyhow::Result;
use tree_sitter::{Language, Query, QueryCursor, StreamingIterator, Tree};
pub struct IndentQuery {
query: Query,
capture_names: Vec<String>,
}
impl IndentQuery {
pub(super) fn compile(language: &Language, src: &str) -> Result<Self> {
let query = Query::new(language, src)?;
let capture_names = query
.capture_names()
.iter()
.map(|s| s.to_string())
.collect();
Ok(Self {
query,
capture_names,
})
}
pub(super) fn begins_at(&self, source: &str, tree: &Tree, row: usize) -> bool {
let mut cursor = QueryCursor::new();
let mut matches = cursor.matches(&self.query, tree.root_node(), source.as_bytes());
while let Some(m) = matches.next() {
for cap in m.captures {
let name = self
.capture_names
.get(cap.index as usize)
.map(String::as_str)
.unwrap_or("");
if name != "indent.begin" {
continue;
}
let node = cap.node;
let start_row = node.start_position().row;
let end_row = node.end_position().row;
if start_row != row {
continue;
}
if end_row > row {
return true;
}
if let Some(body) = node.child_by_field_name("body")
&& body.start_byte() == body.end_byte()
{
return true;
}
}
}
false
}
pub(super) fn scopes_in_rows(
&self,
source: &str,
tree: &Tree,
start_row: usize,
end_row: usize,
) -> Vec<(usize, usize)> {
let mut out = Vec::new();
let mut cursor = QueryCursor::new();
let mut matches = cursor.matches(&self.query, tree.root_node(), source.as_bytes());
while let Some(m) = matches.next() {
for cap in m.captures {
let name = self
.capture_names
.get(cap.index as usize)
.map(String::as_str)
.unwrap_or("");
if name != "indent.begin" {
continue;
}
let node = cap.node;
let s = node.start_position().row;
let e = node.end_position().row;
if e <= s {
continue;
}
if e < start_row || s > end_row {
continue;
}
out.push((s, e));
}
}
out
}
}