use crate::view::overlay::Overlay;
use std::ops::Range;
pub(super) struct OverlayActiveSet<'a> {
overlays: &'a [(Overlay, Range<usize>)],
position_index: &'a [usize],
active: Vec<(usize, usize, &'a Overlay)>,
active_refs: Vec<&'a Overlay>,
next_pos: usize,
last_bp: Option<usize>,
row_touched: Vec<usize>,
}
impl<'a> OverlayActiveSet<'a> {
pub(super) fn new(
overlays: &'a [(Overlay, Range<usize>)],
position_index: &'a [usize],
) -> Self {
Self {
overlays,
position_index,
active: Vec::new(),
active_refs: Vec::new(),
next_pos: 0,
last_bp: None,
row_touched: Vec::new(),
}
}
pub(super) fn enter_row(&mut self, wrap_continuation: bool) {
self.row_touched.clear();
if wrap_continuation {
self.row_touched
.extend(self.active.iter().map(|(_, idx, _)| *idx));
}
}
pub(super) fn advance_to(&mut self, bp: usize) {
if self.last_bp == Some(bp) {
return;
}
let mut dirty = false;
if self.active.iter().any(|(end, _, _)| *end <= bp) {
self.active.retain(|(end, _, _)| *end > bp);
dirty = true;
}
while self.next_pos < self.position_index.len() {
let idx = self.position_index[self.next_pos];
let (overlay, range) = &self.overlays[idx];
if range.start > bp {
break;
}
if range.end > bp {
let pri = overlay.priority;
let pos = self
.active
.iter()
.position(|(_, _, o)| o.priority > pri)
.unwrap_or(self.active.len());
self.active.insert(pos, (range.end, idx, overlay));
dirty = true;
if !self.row_touched.contains(&idx) {
self.row_touched.push(idx);
}
}
self.next_pos += 1;
}
if dirty {
self.active_refs.clear();
self.active_refs
.extend(self.active.iter().map(|(_, _, o)| *o));
}
self.last_bp = Some(bp);
}
pub(super) fn at_cursor(&self) -> &[&'a Overlay] {
&self.active_refs
}
pub(super) fn fill_overlay(&self) -> Option<&'a Overlay> {
self.row_touched
.iter()
.map(|&idx| &self.overlays[idx].0)
.filter(|o| o.extend_to_line_end)
.max_by_key(|o| o.priority)
}
}