extend cursor with generic metric

This commit is contained in:
appflowy 2021-08-12 13:57:41 +08:00
parent 1ec4655d1b
commit bc7da582a3
7 changed files with 152 additions and 42 deletions

View File

@ -47,6 +47,8 @@ impl Document {
pub fn format(&mut self, interval: Interval, attribute: Attribute) -> Result<(), OTError> { pub fn format(&mut self, interval: Interval, attribute: Attribute) -> Result<(), OTError> {
log::debug!("format with {} at {}", attribute, interval); log::debug!("format with {} at {}", attribute, interval);
// let format_delta = self.view.format(&self.delta, attribute, interval)?;
self.update_with_attribute(attribute, interval) self.update_with_attribute(attribute, interval)
} }

View File

@ -1,13 +1,43 @@
use crate::{ use crate::{
client::view::FormatExt, client::view::FormatExt,
core::{Attribute, Delta, Interval}, core::{Attribute, AttributeScope, Attributes, Delta, DeltaBuilder, DeltaIter, Interval},
}; };
pub struct FormatLinkAtCaretPositionExt {} pub struct FormatLinkAtCaretPositionExt {}
impl FormatExt for FormatLinkAtCaretPositionExt { impl FormatExt for FormatLinkAtCaretPositionExt {
fn apply(&self, delta: &Delta, interval: Interval, attribute: &Attribute) -> Option<Delta> { fn apply(&self, delta: &Delta, interval: Interval, attribute: &Attribute) -> Option<Delta> {
unimplemented!() let mut iter = DeltaIter::new(delta);
iter.seek(interval.start);
let (before, after) = (iter.next(), iter.next());
let mut start = interval.start;
let mut retain = 0;
if let Some(before) = before {
if before.contain_attribute(attribute) {
start -= before.length();
retain += before.length();
}
}
if let Some(after) = after {
if after.contain_attribute(attribute) {
if retain != 0 {
retain += after.length();
}
}
}
if retain == 0 {
return None;
}
Some(
DeltaBuilder::new()
.retain(start, Attributes::default())
.retain(retain, (attribute.clone()).into())
.build(),
)
} }
} }
@ -15,7 +45,17 @@ pub struct ResolveLineFormatExt {}
impl FormatExt for ResolveLineFormatExt { impl FormatExt for ResolveLineFormatExt {
fn apply(&self, delta: &Delta, interval: Interval, attribute: &Attribute) -> Option<Delta> { fn apply(&self, delta: &Delta, interval: Interval, attribute: &Attribute) -> Option<Delta> {
unimplemented!() if attribute.scope != AttributeScope::Block {
return None;
}
let mut new_delta = Delta::new();
new_delta.retain(interval.start, Attributes::default());
let mut iter = DeltaIter::new(delta);
iter.seek(interval.start);
None
} }
} }

View File

@ -44,7 +44,7 @@ impl InsertExt for ResetLineFormatOnNewLineExt {
} }
let mut iter = DeltaIter::new(delta); let mut iter = DeltaIter::new(delta);
iter.seek_to(index); iter.seek(index);
let maybe_next_op = iter.next(); let maybe_next_op = iter.next();
if maybe_next_op.is_none() { if maybe_next_op.is_none() {
return None; return None;

View File

@ -71,7 +71,7 @@ pub enum AttributeKey {
UnChecked, UnChecked,
} }
#[derive(Debug)] #[derive(Debug, PartialEq, Eq, Clone)]
pub enum AttributeScope { pub enum AttributeScope {
Inline, Inline,
Block, Block,
@ -79,7 +79,7 @@ pub enum AttributeScope {
Ignore, Ignore,
} }
#[derive(Debug)] #[derive(Debug, Clone)]
pub struct Attribute { pub struct Attribute {
pub key: AttributeKey, pub key: AttributeKey,
pub value: String, pub value: String,
@ -93,6 +93,14 @@ impl fmt::Display for Attribute {
} }
} }
impl std::convert::Into<Attributes> for Attribute {
fn into(self) -> Attributes {
let mut attributes = Attributes::new();
attributes.add(self);
attributes
}
}
pub struct AttrsBuilder { pub struct AttrsBuilder {
inner: Attributes, inner: Attributes,
} }

View File

@ -8,8 +8,9 @@ pub struct Cursor<'a> {
delta: &'a Delta, delta: &'a Delta,
interval: Interval, interval: Interval,
iterator: Iter<'a, Operation>, iterator: Iter<'a, Operation>,
offset: usize, char_index: usize,
offset_op: Option<&'a Operation>, op_index: usize,
current_op: Option<&'a Operation>,
} }
impl<'a> Cursor<'a> { impl<'a> Cursor<'a> {
@ -18,29 +19,31 @@ impl<'a> Cursor<'a> {
delta, delta,
interval, interval,
iterator: delta.ops.iter(), iterator: delta.ops.iter(),
offset: 0, char_index: 0,
offset_op: None, op_index: 0,
current_op: None,
}; };
cursor cursor
} }
pub fn next_op(&mut self) -> Option<Operation> { pub fn next_op(&mut self) -> Option<Operation> {
let mut next_op = self.offset_op.take(); let mut next_op = self.current_op.take();
if next_op.is_none() { if next_op.is_none() {
next_op = self.iterator.next(); next_op = self.iterator.next();
} }
let mut find_op = None; let mut find_op = None;
while find_op.is_none() && next_op.is_some() { while find_op.is_none() && next_op.is_some() {
self.op_index += 1;
let op = next_op.unwrap(); let op = next_op.unwrap();
if self.offset < self.interval.start { if self.char_index < self.interval.start {
let intersect = let intersect = Interval::new(self.char_index, self.char_index + op.length())
Interval::new(self.offset, self.offset + op.length()).intersect(self.interval); .intersect(self.interval);
if intersect.is_empty() { if intersect.is_empty() {
self.offset += op.length(); self.char_index += op.length();
} else { } else {
if let Some(new_op) = op.shrink(intersect.translate_neg(self.offset)) { if let Some(new_op) = op.shrink(intersect.translate_neg(self.char_index)) {
// shrink the op to fit the intersect range // shrink the op to fit the intersect range
// ┌──────────────┐ // ┌──────────────┐
// │ 1 2 3 4 5 6 │ // │ 1 2 3 4 5 6 │
@ -50,11 +53,11 @@ impl<'a> Cursor<'a> {
// op = "45" // op = "45"
find_op = Some(new_op); find_op = Some(new_op);
} }
self.offset = intersect.end; self.char_index = intersect.end;
} }
} else { } else {
// the interval passed in the shrink function is base on the op not the delta. // the interval passed in the shrink function is base on the op not the delta.
if let Some(new_op) = op.shrink(self.interval.translate_neg(self.offset)) { if let Some(new_op) = op.shrink(self.interval.translate_neg(self.char_index)) {
find_op = Some(new_op); find_op = Some(new_op);
} }
// for example: extract the ops from three insert ops with interval [2,5). the // for example: extract the ops from three insert ops with interval [2,5). the
@ -67,43 +70,96 @@ impl<'a> Cursor<'a> {
// └──────┘ └─▲────┘ └───▲──┘ // └──────┘ └─▲────┘ └───▲──┘
// │ [2, 5) │ // │ [2, 5) │
// //
self.offset += min(self.interval.size(), op.length()); self.char_index += min(self.interval.size(), op.length());
} }
match find_op { match find_op {
None => next_op = self.iterator.next(), None => next_op = self.iterator.next(),
Some(_) => self.interval.start = self.offset, Some(_) => self.interval.start = self.char_index,
} }
} }
find_op find_op
} }
pub fn seek_to(&mut self, index: usize) -> Result<(), OTError> { pub fn seek<M: Metric>(&mut self, index: usize) -> Result<(), OTError> {
if self.offset > index { self.current_op = M::seek(self, index)?;
let msg = format!( Ok(())
"{} should be greater than current offset: {}", }
index, self.offset }
);
return Err(ErrorBuilder::new(OTErrorCode::IncompatibleLength)
.msg(&msg)
.build());
}
let mut offset = 0; pub trait Metric {
while let Some(op) = self.iterator.next() { fn seek<'a, 'b>(
if offset != 0 { cursor: &'b mut Cursor<'a>,
self.offset = offset; index: usize,
) -> Result<Option<&'a Operation>, OTError>;
}
pub struct OpMetric {}
impl Metric for OpMetric {
fn seek<'a, 'b>(
cursor: &'b mut Cursor<'a>,
index: usize,
) -> Result<Option<&'a Operation>, OTError> {
let _ = check_bound(cursor.op_index, index)?;
let mut offset = cursor.op_index;
let mut op_at_index = None;
while let Some(op) = cursor.iterator.next() {
if offset != cursor.op_index {
cursor.char_index += op.length();
cursor.op_index = offset;
} }
offset += op.length(); offset += 1;
self.offset_op = Some(op); op_at_index = Some(op);
if offset >= index { if offset >= index {
break; break;
} }
} }
Ok(()) Ok(op_at_index)
} }
} }
pub struct CharMetric {}
impl Metric for CharMetric {
fn seek<'a, 'b>(
cursor: &'b mut Cursor<'a>,
index: usize,
) -> Result<Option<&'a Operation>, OTError> {
let _ = check_bound(cursor.char_index, index)?;
let mut offset = cursor.char_index;
let mut op_at_index = None;
while let Some(op) = cursor.iterator.next() {
if offset != cursor.char_index {
cursor.char_index = offset;
cursor.op_index += 1;
}
offset += op.length();
op_at_index = Some(op);
if offset >= index {
break;
}
}
Ok(op_at_index)
}
}
fn check_bound(current: usize, target: usize) -> Result<(), OTError> {
if current > target {
let msg = format!("{} should be greater than current: {}", target, current);
return Err(ErrorBuilder::new(OTErrorCode::IncompatibleLength)
.msg(&msg)
.build());
}
Ok(())
}

View File

@ -23,8 +23,8 @@ impl<'a> DeltaIter<'a> {
pub fn ops(&mut self) -> Vec<Operation> { self.collect::<Vec<_>>() } pub fn ops(&mut self) -> Vec<Operation> { self.collect::<Vec<_>>() }
pub fn seek_to(&mut self, n_char: usize) -> Result<(), OTError> { pub fn seek(&mut self, n_char: usize) -> Result<(), OTError> {
let _ = self.cursor.seek_to(n_char)?; let _ = self.cursor.seek::<CharMetric>(n_char)?;
Ok(()) Ok(())
} }
} }
@ -102,7 +102,7 @@ impl<'a> Iterator for AttributesIter<'a> {
pub(crate) fn attributes_at_index(delta: &Delta, index: usize) -> Attributes { pub(crate) fn attributes_at_index(delta: &Delta, index: usize) -> Attributes {
let mut iter = AttributesIter::new(delta); let mut iter = AttributesIter::new(delta);
iter.seek_to(index); iter.seek(index);
match iter.next() { match iter.next() {
// None => Attributes::Follow, // None => Attributes::Follow,
None => Attributes::new(), None => Attributes::new(),

View File

@ -1,4 +1,4 @@
use crate::core::{Attributes, Builder, Interval}; use crate::core::{Attribute, Attributes, Builder, Interval};
use bytecount::num_chars; use bytecount::num_chars;
use serde::__private::Formatter; use serde::__private::Formatter;
use std::{ use std::{
@ -48,6 +48,10 @@ impl Operation {
pub fn has_attribute(&self) -> bool { !self.get_attributes().is_empty() } pub fn has_attribute(&self) -> bool { !self.get_attributes().is_empty() }
pub fn contain_attribute(&self, attribute: &Attribute) -> bool {
self.get_attributes().contains_key(&attribute.key)
}
pub fn length(&self) -> usize { pub fn length(&self) -> usize {
match self { match self {
Operation::Delete(n) => *n, Operation::Delete(n) => *n,