3193 lines · 104.6 KB · Rust
RawDownload
mod anchor;pub mod locator;#[cfg(any(test, feature = "test-support"))]pub mod network;pub mod operation_queue;mod patch;mod selection;pub mod subscription;#[cfg(test)]mod tests;mod undo_map; pub use anchor::*;use anyhow::{Context as _, Result};use clock::LOCAL_BRANCH_REPLICA_ID;pub use clock::ReplicaId;use collections::{HashMap, HashSet};use locator::Locator;use operation_queue::OperationQueue;pub use patch::Patch;use postage::{oneshot, prelude::*}; use regex::Regex;pub use rope::*;pub use selection::*;use std::{    borrow::Cow,    cmp::{self, Ordering, Reverse},    fmt::Display,    future::Future,    iter::Iterator,    num::NonZeroU64,    ops::{self, Deref, Range, Sub},    str,    sync::{Arc, LazyLock},    time::{Duration, Instant},};pub use subscription::*;pub use sum_tree::Bias;use sum_tree::{FilterCursor, SumTree, TreeMap, TreeSet};use undo_map::UndoMap; #[cfg(any(test, feature = "test-support"))]use util::RandomCharIter; static LINE_SEPARATORS_REGEX: LazyLock<Regex> =    LazyLock::new(|| Regex::new(r"\r\n|\r").expect("Failed to create LINE_SEPARATORS_REGEX")); pub type TransactionId = clock::Lamport; pub struct Buffer {    snapshot: BufferSnapshot,    history: History,    deferred_ops: OperationQueue<Operation>,    deferred_replicas: HashSet<ReplicaId>,    pub lamport_clock: clock::Lamport,    subscriptions: Topic,    edit_id_resolvers: HashMap<clock::Lamport, Vec<oneshot::Sender<()>>>,    wait_for_version_txs: Vec<(clock::Global, oneshot::Sender<()>)>,} #[repr(transparent)]#[derive(Clone, Copy, Debug, Hash, PartialEq, PartialOrd, Ord, Eq)]pub struct BufferId(NonZeroU64); impl Display for BufferId {    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {        write!(f, "{}", self.0)    }} impl From<NonZeroU64> for BufferId {    fn from(id: NonZeroU64) -> Self {        BufferId(id)    }} impl BufferId {    /// Returns Err if `id` is outside of BufferId domain.    pub fn new(id: u64) -> anyhow::Result<Self> {        let id = NonZeroU64::new(id).context("Buffer id cannot be 0.")?;        Ok(Self(id))    }     /// Increments this buffer id, returning the old value.    /// So that's a post-increment operator in disguise.    pub fn next(&mut self) -> Self {        let old = *self;        self.0 = self.0.saturating_add(1);        old    }     pub fn to_proto(self) -> u64 {        self.into()    }} impl From<BufferId> for u64 {    fn from(id: BufferId) -> Self {        id.0.get()    }} #[derive(Clone)]pub struct BufferSnapshot {    replica_id: ReplicaId,    remote_id: BufferId,    visible_text: Rope,    deleted_text: Rope,    line_ending: LineEnding,    undo_map: UndoMap,    fragments: SumTree<Fragment>,    insertions: SumTree<InsertionFragment>,    insertion_slices: TreeSet<InsertionSlice>,    pub version: clock::Global,} #[derive(Clone, Debug)]pub struct HistoryEntry {    transaction: Transaction,    first_edit_at: Instant,    last_edit_at: Instant,    suppress_grouping: bool,} #[derive(Clone, Debug)]pub struct Transaction {    pub id: TransactionId,    pub edit_ids: Vec<clock::Lamport>,    pub start: clock::Global,} impl Transaction {    pub fn merge_in(&mut self, other: Transaction) {        self.edit_ids.extend(other.edit_ids);    }} impl HistoryEntry {    pub fn transaction_id(&self) -> TransactionId {        self.transaction.id    }} struct History {    base_text: Rope,    operations: TreeMap<clock::Lamport, Operation>,    undo_stack: Vec<HistoryEntry>,    redo_stack: Vec<HistoryEntry>,    transaction_depth: usize,    group_interval: Duration,} #[derive(Clone, Debug, Eq, PartialEq)]struct InsertionSlice {    edit_id: clock::Lamport,    insertion_id: clock::Lamport,    range: Range<usize>,} impl Ord for InsertionSlice {    fn cmp(&self, other: &Self) -> Ordering {        self.edit_id            .cmp(&other.edit_id)            .then_with(|| self.insertion_id.cmp(&other.insertion_id))            .then_with(|| self.range.start.cmp(&other.range.start))            .then_with(|| self.range.end.cmp(&other.range.end))    }} impl PartialOrd for InsertionSlice {    fn partial_cmp(&self, other: &Self) -> Option<Ordering> {        Some(self.cmp(other))    }} impl InsertionSlice {    fn from_fragment(edit_id: clock::Lamport, fragment: &Fragment) -> Self {        Self {            edit_id,            insertion_id: fragment.timestamp,            range: fragment.insertion_offset..fragment.insertion_offset + fragment.len,        }    }} impl History {    pub fn new(base_text: Rope) -> Self {        Self {            base_text,            operations: Default::default(),            undo_stack: Vec::new(),            redo_stack: Vec::new(),            transaction_depth: 0,            // Don't group transactions in tests unless we opt in, because it's a footgun.            #[cfg(any(test, feature = "test-support"))]            group_interval: Duration::ZERO,            #[cfg(not(any(test, feature = "test-support")))]            group_interval: Duration::from_millis(300),        }    }     fn push(&mut self, op: Operation) {        self.operations.insert(op.timestamp(), op);    }     fn start_transaction(        &mut self,        start: clock::Global,        now: Instant,        clock: &mut clock::Lamport,    ) -> Option<TransactionId> {        self.transaction_depth += 1;        if self.transaction_depth == 1 {            let id = clock.tick();            self.undo_stack.push(HistoryEntry {                transaction: Transaction {                    id,                    start,                    edit_ids: Default::default(),                },                first_edit_at: now,                last_edit_at: now,                suppress_grouping: false,            });            Some(id)        } else {            None        }    }     fn end_transaction(&mut self, now: Instant) -> Option<&HistoryEntry> {        assert_ne!(self.transaction_depth, 0);        self.transaction_depth -= 1;        if self.transaction_depth == 0 {            if self                .undo_stack                .last()                .unwrap()                .transaction                .edit_ids                .is_empty()            {                self.undo_stack.pop();                None            } else {                self.redo_stack.clear();                let entry = self.undo_stack.last_mut().unwrap();                entry.last_edit_at = now;                Some(entry)            }        } else {            None        }    }     fn group(&mut self) -> Option<TransactionId> {        let mut count = 0;        let mut entries = self.undo_stack.iter();        if let Some(mut entry) = entries.next_back() {            while let Some(prev_entry) = entries.next_back() {                if !prev_entry.suppress_grouping                    && entry.first_edit_at - prev_entry.last_edit_at < self.group_interval                {                    entry = prev_entry;                    count += 1;                } else {                    break;                }            }        }        self.group_trailing(count)    }     fn group_until(&mut self, transaction_id: TransactionId) {        let mut count = 0;        for entry in self.undo_stack.iter().rev() {            if entry.transaction_id() == transaction_id {                self.group_trailing(count);                break;            } else if entry.suppress_grouping {                break;            } else {                count += 1;            }        }    }     fn group_trailing(&mut self, n: usize) -> Option<TransactionId> {        let new_len = self.undo_stack.len() - n;        let (entries_to_keep, entries_to_merge) = self.undo_stack.split_at_mut(new_len);        if let Some(last_entry) = entries_to_keep.last_mut() {            for entry in &*entries_to_merge {                for edit_id in &entry.transaction.edit_ids {                    last_entry.transaction.edit_ids.push(*edit_id);                }            }             if let Some(entry) = entries_to_merge.last_mut() {                last_entry.last_edit_at = entry.last_edit_at;            }        }         self.undo_stack.truncate(new_len);        self.undo_stack.last().map(|e| e.transaction.id)    }     fn finalize_last_transaction(&mut self) -> Option<&Transaction> {        self.undo_stack.last_mut().map(|entry| {            entry.suppress_grouping = true;            &entry.transaction        })    }     fn push_transaction(&mut self, transaction: Transaction, now: Instant) {        assert_eq!(self.transaction_depth, 0);        self.undo_stack.push(HistoryEntry {            transaction,            first_edit_at: now,            last_edit_at: now,            suppress_grouping: false,        });        self.redo_stack.clear();    }     fn push_undo(&mut self, op_id: clock::Lamport) {        assert_ne!(self.transaction_depth, 0);        if let Some(Operation::Edit(_)) = self.operations.get(&op_id) {            let last_transaction = self.undo_stack.last_mut().unwrap();            last_transaction.transaction.edit_ids.push(op_id);        }    }     fn pop_undo(&mut self) -> Option<&HistoryEntry> {        assert_eq!(self.transaction_depth, 0);        if let Some(entry) = self.undo_stack.pop() {            self.redo_stack.push(entry);            self.redo_stack.last()        } else {            None        }    }     fn remove_from_undo(&mut self, transaction_id: TransactionId) -> Option<&HistoryEntry> {        assert_eq!(self.transaction_depth, 0);         let entry_ix = self            .undo_stack            .iter()            .rposition(|entry| entry.transaction.id == transaction_id)?;        let entry = self.undo_stack.remove(entry_ix);        self.redo_stack.push(entry);        self.redo_stack.last()    }     fn remove_from_undo_until(&mut self, transaction_id: TransactionId) -> &[HistoryEntry] {        assert_eq!(self.transaction_depth, 0);         let redo_stack_start_len = self.redo_stack.len();        if let Some(entry_ix) = self            .undo_stack            .iter()            .rposition(|entry| entry.transaction.id == transaction_id)        {            self.redo_stack                .extend(self.undo_stack.drain(entry_ix..).rev());        }        &self.redo_stack[redo_stack_start_len..]    }     fn forget(&mut self, transaction_id: TransactionId) -> Option<Transaction> {        assert_eq!(self.transaction_depth, 0);        if let Some(entry_ix) = self            .undo_stack            .iter()            .rposition(|entry| entry.transaction.id == transaction_id)        {            Some(self.undo_stack.remove(entry_ix).transaction)        } else if let Some(entry_ix) = self            .redo_stack            .iter()            .rposition(|entry| entry.transaction.id == transaction_id)        {            Some(self.redo_stack.remove(entry_ix).transaction)        } else {            None        }    }     fn transaction(&self, transaction_id: TransactionId) -> Option<&Transaction> {        let entry = self            .undo_stack            .iter()            .rfind(|entry| entry.transaction.id == transaction_id)            .or_else(|| {                self.redo_stack                    .iter()                    .rfind(|entry| entry.transaction.id == transaction_id)            })?;        Some(&entry.transaction)    }     fn transaction_mut(&mut self, transaction_id: TransactionId) -> Option<&mut Transaction> {        let entry = self            .undo_stack            .iter_mut()            .rfind(|entry| entry.transaction.id == transaction_id)            .or_else(|| {                self.redo_stack                    .iter_mut()                    .rfind(|entry| entry.transaction.id == transaction_id)            })?;        Some(&mut entry.transaction)    }     fn merge_transactions(&mut self, transaction: TransactionId, destination: TransactionId) {        if let Some(transaction) = self.forget(transaction) {            if let Some(destination) = self.transaction_mut(destination) {                destination.edit_ids.extend(transaction.edit_ids);            }        }    }     fn pop_redo(&mut self) -> Option<&HistoryEntry> {        assert_eq!(self.transaction_depth, 0);        if let Some(entry) = self.redo_stack.pop() {            self.undo_stack.push(entry);            self.undo_stack.last()        } else {            None        }    }     fn remove_from_redo(&mut self, transaction_id: TransactionId) -> &[HistoryEntry] {        assert_eq!(self.transaction_depth, 0);         let undo_stack_start_len = self.undo_stack.len();        if let Some(entry_ix) = self            .redo_stack            .iter()            .rposition(|entry| entry.transaction.id == transaction_id)        {            self.undo_stack                .extend(self.redo_stack.drain(entry_ix..).rev());        }        &self.undo_stack[undo_stack_start_len..]    }} struct Edits<'a, D: TextDimension, F: FnMut(&FragmentSummary) -> bool> {    visible_cursor: rope::Cursor<'a>,    deleted_cursor: rope::Cursor<'a>,    fragments_cursor: Option<FilterCursor<'a, F, Fragment, FragmentTextSummary>>,    undos: &'a UndoMap,    since: &'a clock::Global,    old_end: D,    new_end: D,    range: Range<(&'a Locator, usize)>,    buffer_id: BufferId,} #[derive(Clone, Debug, Default, Eq, PartialEq)]pub struct Edit<D> {    pub old: Range<D>,    pub new: Range<D>,} impl<D> Edit<D>where    D: Sub<D, Output = D> + PartialEq + Copy,{    pub fn old_len(&self) -> D {        self.old.end - self.old.start    }     pub fn new_len(&self) -> D {        self.new.end - self.new.start    }     pub fn is_empty(&self) -> bool {        self.old.start == self.old.end && self.new.start == self.new.end    }} impl<D1, D2> Edit<(D1, D2)> {    pub fn flatten(self) -> (Edit<D1>, Edit<D2>) {        (            Edit {                old: self.old.start.0..self.old.end.0,                new: self.new.start.0..self.new.end.0,            },            Edit {                old: self.old.start.1..self.old.end.1,                new: self.new.start.1..self.new.end.1,            },        )    }} #[derive(Eq, PartialEq, Clone, Debug)]

Lines 1–500 of 3193.