546 lines · 18.5 KB · Rust
RawDownload
use gpui::{App, Context, Entity};use language::{self, Buffer, BufferEditSource, TransactionId};use std::{    collections::HashMap,    ops::Range,    time::{Duration, Instant},};use sum_tree::Bias;use text::BufferId; use crate::{Anchor, BufferState, MultiBufferOffset}; use super::{Event, MultiBuffer}; #[derive(Clone)]pub(super) struct History {    next_transaction_id: TransactionId,    undo_stack: Vec<Transaction>,    redo_stack: Vec<Transaction>,    transaction_depth: usize,    group_interval: Duration,} impl Default for History {    fn default() -> Self {        History {            next_transaction_id: clock::Lamport::MIN,            undo_stack: Vec::new(),            redo_stack: Vec::new(),            transaction_depth: 0,            group_interval: Duration::from_millis(300),        }    }} #[derive(Clone)]struct Transaction {    id: TransactionId,    buffer_transactions: HashMap<BufferId, text::TransactionId>,    first_edit_at: Instant,    last_edit_at: Instant,    suppress_grouping: bool,} impl History {    fn start_transaction(&mut self, now: Instant) -> Option<TransactionId> {        self.transaction_depth += 1;        if self.transaction_depth == 1 {            let id = self.next_transaction_id.tick();            self.undo_stack.push(Transaction {                id,                buffer_transactions: Default::default(),                first_edit_at: now,                last_edit_at: now,                suppress_grouping: false,            });            Some(id)        } else {            None        }    }     fn end_transaction(        &mut self,        now: Instant,        buffer_transactions: HashMap<BufferId, text::TransactionId>,    ) -> bool {        assert_ne!(self.transaction_depth, 0);        self.transaction_depth -= 1;        if self.transaction_depth == 0 {            if buffer_transactions.is_empty() {                self.undo_stack.pop();                false            } else {                self.redo_stack.clear();                let transaction = self.undo_stack.last_mut().unwrap();                transaction.last_edit_at = now;                for (buffer_id, transaction_id) in buffer_transactions {                    transaction                        .buffer_transactions                        .entry(buffer_id)                        .or_insert(transaction_id);                }                true            }        } else {            false        }    }     fn push_transaction<'a, T>(        &mut self,        buffer_transactions: T,        now: Instant,        cx: &Context<MultiBuffer>,    ) where        T: IntoIterator<Item = (&'a Entity<Buffer>, &'a language::Transaction)>,    {        assert_eq!(self.transaction_depth, 0);        let transaction = Transaction {            id: self.next_transaction_id.tick(),            buffer_transactions: buffer_transactions                .into_iter()                .map(|(buffer, transaction)| (buffer.read(cx).remote_id(), transaction.id))                .collect(),            first_edit_at: now,            last_edit_at: now,            suppress_grouping: false,        };        if !transaction.buffer_transactions.is_empty() {            self.undo_stack.push(transaction);            self.redo_stack.clear();        }    }     fn finalize_last_transaction(&mut self) {        if let Some(transaction) = self.undo_stack.last_mut() {            transaction.suppress_grouping = true;        }    }     fn forget(&mut self, transaction_id: TransactionId) -> Option<Transaction> {        if let Some(ix) = self            .undo_stack            .iter()            .rposition(|transaction| transaction.id == transaction_id)        {            Some(self.undo_stack.remove(ix))        } else if let Some(ix) = self            .redo_stack            .iter()            .rposition(|transaction| transaction.id == transaction_id)        {            Some(self.redo_stack.remove(ix))        } else {            None        }    }     fn transaction(&self, transaction_id: TransactionId) -> Option<&Transaction> {        self.undo_stack            .iter()            .find(|transaction| transaction.id == transaction_id)            .or_else(|| {                self.redo_stack                    .iter()                    .find(|transaction| transaction.id == transaction_id)            })    }     fn transaction_mut(&mut self, transaction_id: TransactionId) -> Option<&mut Transaction> {        self.undo_stack            .iter_mut()            .find(|transaction| transaction.id == transaction_id)            .or_else(|| {                self.redo_stack                    .iter_mut()                    .find(|transaction| transaction.id == transaction_id)            })    }     fn pop_undo(&mut self) -> Option<&mut Transaction> {        assert_eq!(self.transaction_depth, 0);        if let Some(transaction) = self.undo_stack.pop() {            self.redo_stack.push(transaction);            self.redo_stack.last_mut()        } else {            None        }    }     fn pop_redo(&mut self) -> Option<&mut Transaction> {        assert_eq!(self.transaction_depth, 0);        if let Some(transaction) = self.redo_stack.pop() {            self.undo_stack.push(transaction);            self.undo_stack.last_mut()        } else {            None        }    }     fn remove_from_undo(&mut self, transaction_id: TransactionId) -> Option<&Transaction> {        let ix = self            .undo_stack            .iter()            .rposition(|transaction| transaction.id == transaction_id)?;        let transaction = self.undo_stack.remove(ix);        self.redo_stack.push(transaction);        self.redo_stack.last()    }     fn group(&mut self) -> Option<TransactionId> {        let mut count = 0;        let mut transactions = self.undo_stack.iter();        if let Some(mut transaction) = transactions.next_back() {            while let Some(prev_transaction) = transactions.next_back() {                if !prev_transaction.suppress_grouping                    && transaction.first_edit_at - prev_transaction.last_edit_at                        <= self.group_interval                {                    transaction = prev_transaction;                    count += 1;                } else {                    break;                }            }        }        self.group_trailing(count)    }     fn group_until(&mut self, transaction_id: TransactionId) {        let mut count = 0;        for transaction in self.undo_stack.iter().rev() {            if transaction.id == transaction_id {                self.group_trailing(count);                break;            } else if transaction.suppress_grouping {                break;            } else {                count += 1;            }        }    }     fn group_trailing(&mut self, n: usize) -> Option<TransactionId> {        let new_len = self.undo_stack.len() - n;        let (transactions_to_keep, transactions_to_merge) = self.undo_stack.split_at_mut(new_len);        if let Some(last_transaction) = transactions_to_keep.last_mut() {            if let Some(transaction) = transactions_to_merge.last() {                last_transaction.last_edit_at = transaction.last_edit_at;            }            for to_merge in transactions_to_merge {                for (buffer_id, transaction_id) in &to_merge.buffer_transactions {                    last_transaction                        .buffer_transactions                        .entry(*buffer_id)                        .or_insert(*transaction_id);                }            }        }         self.undo_stack.truncate(new_len);        self.undo_stack.last().map(|t| t.id)    }     pub(super) fn transaction_depth(&self) -> usize {        self.transaction_depth    }     pub fn set_group_interval(&mut self, group_interval: Duration) {        self.group_interval = group_interval;    }} impl MultiBuffer {    pub fn start_transaction(&mut self, cx: &mut Context<Self>) -> Option<TransactionId> {        self.start_transaction_at(Instant::now(), cx)    }     pub fn start_transaction_at(        &mut self,        now: Instant,        cx: &mut Context<Self>,    ) -> Option<TransactionId> {        if let Some(buffer) = self.as_singleton() {            return buffer.update(cx, |buffer, _| buffer.start_transaction_at(now));        }         for BufferState { buffer, .. } in self.buffers.values() {            buffer.update(cx, |buffer, _| buffer.start_transaction_at(now));        }        self.history.start_transaction(now)    }     pub fn last_transaction_id(&self, cx: &App) -> Option<TransactionId> {        if let Some(buffer) = self.as_singleton() {            buffer                .read(cx)                .peek_undo_stack()                .map(|history_entry| history_entry.transaction_id())        } else {            let last_transaction = self.history.undo_stack.last()?;            Some(last_transaction.id)        }    }     pub fn end_transaction(&mut self, cx: &mut Context<Self>) -> Option<TransactionId> {        self.end_transaction_at(Instant::now(), cx)    }     pub fn end_transaction_with_source(        &mut self,        source: BufferEditSource,        cx: &mut Context<Self>,    ) -> Option<TransactionId> {        let now = Instant::now();        if let Some(buffer) = self.as_singleton() {            return buffer.update(cx, |buffer, cx| {                buffer.end_transaction_with_source(source, cx)            });        }         let mut buffer_transactions = HashMap::default();        for BufferState { buffer, .. } in self.buffers.values() {            if let Some(transaction_id) = buffer.update(cx, |buffer, cx| {                buffer.end_transaction_with_source(source, cx)            }) {                buffer_transactions.insert(buffer.read(cx).remote_id(), transaction_id);            }        }         if self.history.end_transaction(now, buffer_transactions) {            let transaction_id = self.history.group().unwrap();            Some(transaction_id)        } else {            None        }    }     pub fn end_transaction_at(        &mut self,        now: Instant,        cx: &mut Context<Self>,    ) -> Option<TransactionId> {        if let Some(buffer) = self.as_singleton() {            return buffer.update(cx, |buffer, cx| buffer.end_transaction_at(now, cx));        }         let mut buffer_transactions = HashMap::default();        for BufferState { buffer, .. } in self.buffers.values() {            if let Some(transaction_id) =                buffer.update(cx, |buffer, cx| buffer.end_transaction_at(now, cx))            {                buffer_transactions.insert(buffer.read(cx).remote_id(), transaction_id);            }        }         if self.history.end_transaction(now, buffer_transactions) {            let transaction_id = self.history.group().unwrap();            Some(transaction_id)        } else {            None        }    }     pub fn edited_ranges_for_transaction(        &self,        transaction_id: TransactionId,        cx: &App,    ) -> Vec<Range<MultiBufferOffset>> {        let Some(transaction) = self.history.transaction(transaction_id) else {            return Vec::new();        };         let snapshot = self.read(cx);        let mut buffer_anchors = Vec::new();         for (buffer_id, buffer_transaction) in &transaction.buffer_transactions {            let Some(buffer) = self.buffer(*buffer_id) else {                continue;            };            let Some(excerpt) = snapshot.first_excerpt_for_buffer(*buffer_id) else {                continue;            };            let buffer_snapshot = buffer.read(cx).snapshot();             for range in buffer                .read(cx)                .edited_ranges_for_transaction_id::<usize>(*buffer_transaction)            {                buffer_anchors.push(Anchor::in_buffer(                    excerpt.path_key_index,                    buffer_snapshot.anchor_at(range.start, Bias::Left),                ));                buffer_anchors.push(Anchor::in_buffer(                    excerpt.path_key_index,                    buffer_snapshot.anchor_at(range.end, Bias::Right),                ));            }        }        buffer_anchors.sort_unstable_by(|a, b| a.cmp(b, &snapshot));         snapshot            .summaries_for_anchors(buffer_anchors.iter())            .as_chunks::<2>()            .0            .iter()            .map(|&[s, e]| s..e)            .collect::<Vec<_>>()    }     pub fn merge_transactions(        &mut self,        transaction: TransactionId,        destination: TransactionId,        cx: &mut Context<Self>,    ) {        if let Some(buffer) = self.as_singleton() {            buffer.update(cx, |buffer, _| {                buffer.merge_transactions(transaction, destination)            });        } else if let Some(transaction) = self.history.forget(transaction)            && let Some(destination) = self.history.transaction_mut(destination)        {            for (buffer_id, buffer_transaction_id) in transaction.buffer_transactions {                if let Some(destination_buffer_transaction_id) =                    destination.buffer_transactions.get(&buffer_id)                {                    if let Some(state) = self.buffers.get(&buffer_id) {                        state.buffer.update(cx, |buffer, _| {                            buffer.merge_transactions(                                buffer_transaction_id,                                *destination_buffer_transaction_id,                            )                        });                    }                } else {                    destination                        .buffer_transactions                        .insert(buffer_id, buffer_transaction_id);                }            }        }    }     pub fn finalize_last_transaction(&mut self, cx: &mut Context<Self>) {        self.history.finalize_last_transaction();        for BufferState { buffer, .. } in self.buffers.values() {            buffer.update(cx, |buffer, _| {                buffer.finalize_last_transaction();            });        }    }     pub fn push_transaction<'a, T>(&mut self, buffer_transactions: T, cx: &Context<Self>)    where        T: IntoIterator<Item = (&'a Entity<Buffer>, &'a language::Transaction)>,    {        self.history            .push_transaction(buffer_transactions, Instant::now(), cx);        self.history.finalize_last_transaction();    }     pub fn group_until_transaction(        &mut self,        transaction_id: TransactionId,        cx: &mut Context<Self>,    ) {        if let Some(buffer) = self.as_singleton() {            buffer.update(cx, |buffer, _| {                buffer.group_until_transaction(transaction_id)            });        } else {            self.history.group_until(transaction_id);        }    }    pub fn undo(&mut self, cx: &mut Context<Self>) -> Option<TransactionId> {        let mut transaction_id = None;        if let Some(buffer) = self.as_singleton() {            transaction_id = buffer.update(cx, |buffer, cx| buffer.undo(cx));        } else {            while let Some(transaction) = self.history.pop_undo() {                let mut undone = false;                for (buffer_id, buffer_transaction_id) in &mut transaction.buffer_transactions {                    if let Some(BufferState { buffer, .. }) = self.buffers.get(buffer_id) {                        undone |= buffer.update(cx, |buffer, cx| {                            let undo_to = *buffer_transaction_id;                            if let Some(entry) = buffer.peek_undo_stack() {                                *buffer_transaction_id = entry.transaction_id();                            }                            buffer.undo_to_transaction(undo_to, cx)                        });                    }                }                 if undone {                    transaction_id = Some(transaction.id);                    break;                }            }        }         if let Some(transaction_id) = transaction_id {            cx.emit(Event::TransactionUndone { transaction_id });        }         transaction_id    }     pub fn redo(&mut self, cx: &mut Context<Self>) -> Option<TransactionId> {        if let Some(buffer) = self.as_singleton() {            return buffer.update(cx, |buffer, cx| buffer.redo(cx));        }         while let Some(transaction) = self.history.pop_redo() {            let mut redone = false;            for (buffer_id, buffer_transaction_id) in transaction.buffer_transactions.iter_mut() {                if let Some(BufferState { buffer, .. }) = self.buffers.get(buffer_id) {                    redone |= buffer.update(cx, |buffer, cx| {                        let redo_to = *buffer_transaction_id;

Lines 1–500 of 546.