use crate::clock::Clock;
use crate::marks::OldMarkData;
use crate::op_set::{Op, OpSetData};
use crate::op_tree::{LastInsert, OpTreeNode};
use crate::query::{Index, QueryResult};
use crate::types::{SmallHashMap, Key, ListEncoding, OpId, OpType};
use crate::ObjType;
use std::collections::HashMap;
#[derive(Debug, Clone, Default, PartialEq)]
pub(crate) struct RichTextQueryState<'a> {
map: SmallHashMap<OpId, &'a OldMarkData>,
block: Option<OpId>,
}
impl<'a> RichTextQueryState<'a> {
pub(crate) fn process(&mut self, op: Op<'a>, clock: Option<&Clock>) {
if !(clock.map(|c| c.covers(op.id())).unwrap_or(true)) {
return;
}
match op.action() {
OpType::MarkBegin(_, data) => {
self.map.insert(*op.id(), data);
}
OpType::MarkEnd(_) => {
self.map.remove(&op.id().prev());
}
OpType::Make(ObjType::Map) => {
self.block = Some(*op.id());
}
_ => {}
}
}
pub(crate) fn iter(&self) -> impl Iterator<Item = (&OpId, &&OldMarkData)> {
self.map.iter()
}
pub(crate) fn insert(&mut self, op: OpId, data: &'a OldMarkData) {
self.map.insert(op, data);
}
pub(crate) fn remove(&mut self, op: &OpId) {
self.map.remove(op);
}
}
#[derive(Debug, Clone, PartialEq)]
pub(crate) struct ListState {
encoding: ListEncoding,
last_seen: Option<Key>,
last_width: usize,
never_seen_puts: bool,
target: usize,
index: usize,
pos: usize,
}
impl ListState {
pub(crate) fn new(encoding: ListEncoding, target: usize) -> Self {
ListState {
encoding,
target,
last_seen: None,
last_width: 0,
index: 0,
pos: 0,
never_seen_puts: true,
}
}
pub(crate) fn was_last_seen(&self, key: Key) -> bool {
self.last_seen == Some(key)
}
pub(crate) fn check_if_node_is_clean(&mut self, index: &Index) {
self.never_seen_puts &= index.has_never_seen_puts();
}
pub(crate) fn process_node<'a>(
&mut self,
node: &'a OpTreeNode,
index: &'a Index,
osd: &OpSetData,
marks: Option<&mut RichTextQueryState<'a>>,
) -> QueryResult {
if self.encoding == ListEncoding::List {
self.process_list_node(node, index, osd, marks)
} else if self.never_seen_puts {
self.process_text_node(node, index, marks)
} else {
QueryResult::Descend
}
}
fn process_marks<'a>(&mut self, index: &'a Index, marks: Option<&mut RichTextQueryState<'a>>) {
if let Some(marks) = marks {
for (id, data) in index.mark_begin.iter() {
marks.insert(*id, data);
}
for id in index.mark_end.iter() {
marks.remove(&id.prev());
}
}
}
fn process_text_node<'a>(
&mut self,
node: &'a OpTreeNode,
index: &'a Index,
marks: Option<&mut RichTextQueryState<'a>>,
) -> QueryResult {
let num_vis = index.visible_len(self.encoding);
if self.index + num_vis >= self.target {
return QueryResult::Descend;
}
self.index += num_vis;
self.pos += node.len();
self.process_marks(index, marks);
QueryResult::Next
}
fn process_list_node<'a>(
&mut self,
node: &'a OpTreeNode,
index: &'a Index,
osd: &OpSetData,
marks: Option<&mut RichTextQueryState<'a>>,
) -> QueryResult {
let mut num_vis = index.visible.len();
if let Some(last_seen) = self.last_seen {
if index.has_visible(&last_seen) {
num_vis -= 1;
}
}
if self.index + num_vis >= self.target {
return QueryResult::Descend;
}
self.index += num_vis;
self.pos += node.len();
let last_elemid = node.last().as_op(osd).elemid_or_key();
if index.has_visible(&last_elemid) {
self.last_seen = Some(last_elemid);
} else if self.last_seen.is_some() && Some(last_elemid) != self.last_seen {
self.last_seen = None;
}
self.process_marks(index, marks);
QueryResult::Next
}
pub(crate) fn process_op(&mut self, op: Op<'_>, current: Key, visible: bool) {
if visible {
if self.never_seen_puts {
self.last_width = op.width(self.encoding);
self.index += self.last_width;
} else {
let current_width = op.width(self.encoding);
if self.last_seen != Some(current) {
self.last_width = current_width;
self.index += self.last_width;
self.last_seen = Some(current);
} else if current_width != self.last_width {
self.index = self.index + current_width - self.last_width;
self.last_width = current_width;
}
}
}
self.pos += 1;
}
pub(crate) fn target(&self) -> usize {
self.target
}
pub(crate) fn pos(&self) -> usize {
self.pos
}
pub(crate) fn index(&self) -> usize {
self.index
}
pub(crate) fn last_index(&self) -> usize {
self.index - self.last_width
}
pub(crate) fn done(&self) -> bool {
self.index >= self.target
}
pub(crate) fn seek(&mut self, last: &LastInsert) {
self.last_width = last.width;
self.index = last.index + last.width;
self.pos = last.pos + 1;
}
}