use std::ops::Range;
pub(super) struct SelectionActiveSet<'a> {
ranges: &'a [Range<usize>],
blocks: &'a [(usize, usize, usize, usize)],
range_cursor: usize,
active_block: Vec<usize>,
block_next_idx: usize,
block_last_line: Option<usize>,
}
impl<'a> SelectionActiveSet<'a> {
pub(super) fn new(
ranges: &'a [Range<usize>],
blocks: &'a [(usize, usize, usize, usize)],
) -> Self {
Self {
ranges,
blocks,
range_cursor: 0,
active_block: Vec::new(),
block_next_idx: 0,
block_last_line: None,
}
}
pub(super) fn enter_line(&mut self, gutter_num: usize) {
if self.block_last_line == Some(gutter_num) {
return;
}
self.active_block
.retain(|&i| self.blocks[i].2 >= gutter_num);
while self.block_next_idx < self.blocks.len() {
let (start_line, _, _, _) = self.blocks[self.block_next_idx];
if start_line > gutter_num {
break;
}
if self.blocks[self.block_next_idx].2 >= gutter_num {
self.active_block.push(self.block_next_idx);
}
self.block_next_idx += 1;
}
self.block_last_line = Some(gutter_num);
}
pub(super) fn contains(&mut self, buffer_byte: Option<usize>, cell_byte_index: usize) -> bool {
let linear = buffer_byte.is_some_and(|bp| {
while self.range_cursor < self.ranges.len() && self.ranges[self.range_cursor].end <= bp
{
self.range_cursor += 1;
}
self.ranges[self.range_cursor..]
.iter()
.take_while(|r| r.start <= bp)
.any(|r| r.end > bp)
});
let block = self.active_block.iter().any(|&i| {
let (_, start_col, _, end_col) = self.blocks[i];
cell_byte_index >= start_col && cell_byte_index <= end_col
});
linear || block
}
}