use anyhow::Result;
use tree_sitter::{Language, Query, QueryCursor, StreamingIterator, Tree};
use super::engine::byte_to_char_col;
pub struct HighlightQuery {
query: Query,
capture_names: Vec<String>,
}
impl HighlightQuery {
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 captures_in_rows(
&self,
source: &str,
tree: &Tree,
start_row: usize,
end_row: usize,
) -> Vec<Capture> {
let mut cursor = QueryCursor::new();
let mut matches = cursor.matches(&self.query, tree.root_node(), source.as_bytes());
let mut out = Vec::new();
while let Some(m) = matches.next() {
for cap in m.captures {
let node = cap.node;
let start = node.start_position();
let end = node.end_position();
if end.row < start_row || start.row > end_row {
continue;
}
let name = self
.capture_names
.get(cap.index as usize)
.cloned()
.unwrap_or_default();
out.push(Capture {
start_row: start.row,
start_col: byte_to_char_col(source, start.row, start.column),
end_row: end.row,
end_col: byte_to_char_col(source, end.row, end.column),
name,
});
}
}
out
}
}
#[derive(Debug, Clone)]
pub struct Capture {
pub start_row: usize,
pub start_col: usize,
pub end_row: usize,
pub end_col: usize,
pub name: String,
}