use tree_sitter::{Point, Tree};
use super::engine::{byte_to_char_col, char_to_byte_col};
pub(super) fn matching(
source: &str,
tree: &Tree,
row: usize,
col_chars: usize,
) -> Option<(usize, usize)> {
let line = source.lines().nth(row)?;
let byte_col = char_to_byte_col(source, row, col_chars);
let ch_byte_len = line
.get(byte_col..)
.and_then(|s| s.chars().next())
.map(char::len_utf8)?;
let start = Point {
row,
column: byte_col,
};
let end = Point {
row,
column: byte_col + ch_byte_len,
};
let node = tree.root_node().descendant_for_point_range(start, end)?;
let (target, want_last) = match node.kind() {
"(" => (")", true),
"[" => ("]", true),
"{" => ("}", true),
")" => ("(", false),
"]" => ("[", false),
"}" => ("{", false),
_ => return None,
};
let parent = node.parent()?;
let mut found: Option<tree_sitter::Node> = None;
let mut walk = parent.walk();
for child in parent.children(&mut walk) {
if child.kind() == target {
found = Some(child);
if !want_last {
break;
}
}
}
let m = found?;
let pos = m.start_position();
Some((pos.row, byte_to_char_col(source, pos.row, pos.column)))
}