use unicode_segmentation::UnicodeSegmentation;
use unicode_width::UnicodeWidthStr;
use rdom_core::{Dom, Position};
use super::{InlineFragment, InlineLayout, inline_flow_for_text, inline_flow_layout};
use crate::ext::TuiExt;
pub fn cell_of_position(dom: &Dom<TuiExt>, pos: Position) -> Option<(u16, u16)> {
let flow = inline_flow_for_text(dom, pos.node)?;
let (layout, content) = inline_flow_layout(dom, flow)?;
if fragment_for_position(layout, pos).is_none() {
let text = dom.node(pos.node).node_value()?;
let (line_idx, col) = phantom_line_and_column(text, pos.offset)?;
let x = (content.x + col as i32).max(0) as u16;
let y = (content.y + line_idx as i32).max(0) as u16;
return Some((x, y));
}
let (line_idx, fragment) = fragment_for_position(layout, pos)?;
let offset_in_frag = pos.offset.saturating_sub(fragment.source_byte_offset);
let cell_in_frag = cells_before_byte(&fragment.text, offset_in_frag);
let x = (content.x + fragment.x as i32 + cell_in_frag as i32).max(0) as u16;
let y = (content.y + line_idx as i32).max(0) as u16;
Some((x, y))
}
fn phantom_line_and_column(text: &str, offset: usize) -> Option<(usize, u16)> {
if offset > text.len() {
return None;
}
let prefix = &text[..offset];
let line_idx = prefix.matches('\n').count();
let last_break = prefix.rfind('\n').map(|p| p + 1).unwrap_or(0);
let col_text = &prefix[last_break..];
let col = UnicodeWidthStr::width(col_text) as u16;
Some((line_idx, col))
}
fn fragment_for_position(layout: &InlineLayout, pos: Position) -> Option<(usize, &InlineFragment)> {
for (line_idx, line) in layout.lines.iter().enumerate() {
for fragment in &line.fragments {
if fragment.text_node != pos.node {
continue;
}
let frag_end = fragment.source_byte_offset + fragment.text.len();
if fragment.source_byte_offset <= pos.offset && pos.offset <= frag_end {
return Some((line_idx, fragment));
}
}
}
None
}
pub(crate) fn cells_before_byte(text: &str, target: usize) -> u16 {
let mut cells: u16 = 0;
for (idx, g) in text.grapheme_indices(true) {
if idx >= target {
return cells;
}
cells = cells.saturating_add(UnicodeWidthStr::width(g) as u16);
}
cells
}