pub mod intraline;
pub mod registry;
pub mod scope;
pub mod symbols;
use std::ops::Range;
use tree_sitter::Parser;
pub use registry::{HIGHLIGHT_NAMES, LangEntry, LanguageRegistry};
pub use scope::ScopeIndex;
pub use symbols::Ident;
pub(crate) const MAX_PARSE_BYTES: usize = 2_000_000;
pub(crate) fn parse(entry: &LangEntry, src: &str) -> Option<tree_sitter::Tree> {
let mut parser = Parser::new();
parser.set_language(&entry.language).ok()?;
parser.parse(src, None)
}
pub(crate) fn line_bounds(content: &str) -> Vec<(usize, usize)> {
let bytes = content.as_bytes();
let mut out = Vec::new();
let mut start = 0;
for (i, &b) in bytes.iter().enumerate() {
if b == b'\n' {
let end = if i > start && bytes.get(i - 1) == Some(&b'\r') {
i - 1
} else {
i
};
out.push((start, end));
start = i + 1;
}
}
if start < bytes.len() {
let end = if bytes.last() == Some(&b'\r') {
bytes.len() - 1
} else {
bytes.len()
};
out.push((start, end));
}
out
}
pub(crate) fn split_range_by_line(
bounds: &[(usize, usize)],
starts: &[usize],
range: &Range<usize>,
mut emit: impl FnMut(usize, Range<usize>),
) {
let mut li = match starts.binary_search(&range.start) {
Ok(i) => i,
Err(i) => i.saturating_sub(1),
};
while let Some(&(ls, le)) = bounds.get(li) {
if ls >= range.end {
break;
}
let s = range.start.max(ls);
let e = range.end.min(le);
if s < e {
emit(li, (s - ls)..(e - ls));
}
li += 1;
}
}