Test undo/redo at editor layer, including selection restoration
This commit is contained in:
parent
44cd0be068
commit
cdbcbdfe6d
5 changed files with 325 additions and 180 deletions
File diff suppressed because it is too large
Load diff
|
@ -1,5 +1,4 @@
|
||||||
mod anchor;
|
mod anchor;
|
||||||
mod selection;
|
|
||||||
|
|
||||||
pub use anchor::{Anchor, AnchorRangeExt};
|
pub use anchor::{Anchor, AnchorRangeExt};
|
||||||
use anyhow::Result;
|
use anyhow::Result;
|
||||||
|
@ -7,8 +6,8 @@ use clock::ReplicaId;
|
||||||
use collections::HashMap;
|
use collections::HashMap;
|
||||||
use gpui::{AppContext, Entity, ModelContext, ModelHandle, MutableAppContext, Task};
|
use gpui::{AppContext, Entity, ModelContext, ModelHandle, MutableAppContext, Task};
|
||||||
use language::{
|
use language::{
|
||||||
Buffer, BufferChunks, BufferSnapshot, Chunk, DiagnosticEntry, Event, File, FromAnchor,
|
Buffer, BufferChunks, BufferSnapshot, Chunk, DiagnosticEntry, Event, File, Language, Selection,
|
||||||
Language, Selection, ToOffset as _, ToPoint as _, TransactionId,
|
ToOffset as _, ToPoint as _, TransactionId,
|
||||||
};
|
};
|
||||||
use std::{
|
use std::{
|
||||||
cell::{Ref, RefCell},
|
cell::{Ref, RefCell},
|
||||||
|
@ -16,7 +15,7 @@ use std::{
|
||||||
iter::Peekable,
|
iter::Peekable,
|
||||||
ops::{Range, Sub},
|
ops::{Range, Sub},
|
||||||
sync::Arc,
|
sync::Arc,
|
||||||
time::SystemTime,
|
time::{Duration, Instant, SystemTime},
|
||||||
};
|
};
|
||||||
use sum_tree::{Bias, Cursor, SumTree};
|
use sum_tree::{Bias, Cursor, SumTree};
|
||||||
use text::{
|
use text::{
|
||||||
|
@ -40,11 +39,15 @@ pub struct MultiBuffer {
|
||||||
}
|
}
|
||||||
|
|
||||||
pub trait ToOffset: 'static {
|
pub trait ToOffset: 'static {
|
||||||
fn to_offset<'a>(&self, snapshot: &MultiBufferSnapshot) -> usize;
|
fn to_offset(&self, snapshot: &MultiBufferSnapshot) -> usize;
|
||||||
}
|
}
|
||||||
|
|
||||||
pub trait ToPoint: 'static {
|
pub trait ToPoint: 'static {
|
||||||
fn to_point<'a>(&self, snapshot: &MultiBufferSnapshot) -> Point;
|
fn to_point(&self, snapshot: &MultiBufferSnapshot) -> Point;
|
||||||
|
}
|
||||||
|
|
||||||
|
pub trait FromAnchor: 'static {
|
||||||
|
fn from_anchor(anchor: &Anchor, snapshot: &MultiBufferSnapshot) -> Self;
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
|
@ -130,6 +133,13 @@ impl MultiBuffer {
|
||||||
self.replica_id
|
self.replica_id
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn transaction_group_interval(&self, cx: &AppContext) -> Duration {
|
||||||
|
self.as_singleton()
|
||||||
|
.unwrap()
|
||||||
|
.read(cx)
|
||||||
|
.transaction_group_interval()
|
||||||
|
}
|
||||||
|
|
||||||
pub fn snapshot(&self, cx: &AppContext) -> MultiBufferSnapshot {
|
pub fn snapshot(&self, cx: &AppContext) -> MultiBufferSnapshot {
|
||||||
self.sync(cx);
|
self.sync(cx);
|
||||||
self.snapshot.borrow().clone()
|
self.snapshot.borrow().clone()
|
||||||
|
@ -200,10 +210,18 @@ impl MultiBuffer {
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn start_transaction(&mut self, cx: &mut ModelContext<Self>) -> Option<TransactionId> {
|
pub fn start_transaction(&mut self, cx: &mut ModelContext<Self>) -> Option<TransactionId> {
|
||||||
|
self.start_transaction_at(Instant::now(), cx)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub(crate) fn start_transaction_at(
|
||||||
|
&mut self,
|
||||||
|
now: Instant,
|
||||||
|
cx: &mut ModelContext<Self>,
|
||||||
|
) -> Option<TransactionId> {
|
||||||
// TODO
|
// TODO
|
||||||
self.as_singleton()
|
self.as_singleton()
|
||||||
.unwrap()
|
.unwrap()
|
||||||
.update(cx, |buffer, _| buffer.start_transaction())
|
.update(cx, |buffer, _| buffer.start_transaction_at(now))
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn end_transaction(&mut self, cx: &mut ModelContext<Self>) -> Option<TransactionId> {
|
pub fn end_transaction(&mut self, cx: &mut ModelContext<Self>) -> Option<TransactionId> {
|
||||||
|
@ -213,6 +231,17 @@ impl MultiBuffer {
|
||||||
.update(cx, |buffer, cx| buffer.end_transaction(cx))
|
.update(cx, |buffer, cx| buffer.end_transaction(cx))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub(crate) fn end_transaction_at(
|
||||||
|
&mut self,
|
||||||
|
now: Instant,
|
||||||
|
cx: &mut ModelContext<Self>,
|
||||||
|
) -> Option<TransactionId> {
|
||||||
|
// TODO
|
||||||
|
self.as_singleton()
|
||||||
|
.unwrap()
|
||||||
|
.update(cx, |buffer, cx| buffer.end_transaction_at(now, cx))
|
||||||
|
}
|
||||||
|
|
||||||
pub fn undo(&mut self, cx: &mut ModelContext<Self>) -> Option<TransactionId> {
|
pub fn undo(&mut self, cx: &mut ModelContext<Self>) -> Option<TransactionId> {
|
||||||
// TODO
|
// TODO
|
||||||
self.as_singleton()
|
self.as_singleton()
|
||||||
|
|
|
@ -1,42 +0,0 @@
|
||||||
use super::{Anchor, MultiBufferSnapshot};
|
|
||||||
use std::ops::Sub;
|
|
||||||
use text::{rope::TextDimension, Selection};
|
|
||||||
|
|
||||||
fn resolve_selection<'a, D>(
|
|
||||||
selection: &'a Selection<Anchor>,
|
|
||||||
snapshot: &'a MultiBufferSnapshot,
|
|
||||||
) -> Selection<D>
|
|
||||||
where
|
|
||||||
D: TextDimension + Ord + Sub<D, Output = D>,
|
|
||||||
{
|
|
||||||
Selection {
|
|
||||||
id: selection.id,
|
|
||||||
start: selection.start.summary::<D>(snapshot),
|
|
||||||
end: selection.end.summary::<D>(snapshot),
|
|
||||||
reversed: selection.reversed,
|
|
||||||
goal: selection.goal,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn resolve_selections<'a, D>(
|
|
||||||
selections: &'a [Selection<Anchor>],
|
|
||||||
snapshot: &'a MultiBufferSnapshot,
|
|
||||||
) -> impl 'a + Iterator<Item = Selection<D>>
|
|
||||||
where
|
|
||||||
D: TextDimension + Ord + Sub<D, Output = D>,
|
|
||||||
{
|
|
||||||
let mut summaries = snapshot
|
|
||||||
.summaries_for_anchors::<D, _>(
|
|
||||||
selections
|
|
||||||
.iter()
|
|
||||||
.flat_map(|selection| [&selection.start, &selection.end]),
|
|
||||||
)
|
|
||||||
.into_iter();
|
|
||||||
selections.iter().map(move |selection| Selection {
|
|
||||||
id: selection.id,
|
|
||||||
start: summaries.next().unwrap(),
|
|
||||||
end: summaries.next().unwrap(),
|
|
||||||
reversed: selection.reversed,
|
|
||||||
goal: selection.goal,
|
|
||||||
})
|
|
||||||
}
|
|
|
@ -31,7 +31,7 @@ use std::{
|
||||||
vec,
|
vec,
|
||||||
};
|
};
|
||||||
use sum_tree::TreeMap;
|
use sum_tree::TreeMap;
|
||||||
use text::{operation_queue::OperationQueue, rope::TextDimension};
|
use text::operation_queue::OperationQueue;
|
||||||
pub use text::{Buffer as TextBuffer, Operation as _, *};
|
pub use text::{Buffer as TextBuffer, Operation as _, *};
|
||||||
use theme::SyntaxTheme;
|
use theme::SyntaxTheme;
|
||||||
use tree_sitter::{InputEdit, Parser, QueryCursor, Tree};
|
use tree_sitter::{InputEdit, Parser, QueryCursor, Tree};
|
||||||
|
@ -1062,7 +1062,7 @@ impl Buffer {
|
||||||
self.start_transaction_at(Instant::now())
|
self.start_transaction_at(Instant::now())
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(crate) fn start_transaction_at(&mut self, now: Instant) -> Option<TransactionId> {
|
pub fn start_transaction_at(&mut self, now: Instant) -> Option<TransactionId> {
|
||||||
self.text.start_transaction_at(now)
|
self.text.start_transaction_at(now)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1070,7 +1070,7 @@ impl Buffer {
|
||||||
self.end_transaction_at(Instant::now(), cx)
|
self.end_transaction_at(Instant::now(), cx)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(crate) fn end_transaction_at(
|
pub fn end_transaction_at(
|
||||||
&mut self,
|
&mut self,
|
||||||
now: Instant,
|
now: Instant,
|
||||||
cx: &mut ModelContext<Self>,
|
cx: &mut ModelContext<Self>,
|
||||||
|
|
|
@ -511,6 +511,10 @@ impl Buffer {
|
||||||
self.deferred_ops.len()
|
self.deferred_ops.len()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn transaction_group_interval(&self) -> Duration {
|
||||||
|
self.history.group_interval
|
||||||
|
}
|
||||||
|
|
||||||
pub fn edit<R, I, S, T>(&mut self, ranges: R, new_text: T) -> EditOperation
|
pub fn edit<R, I, S, T>(&mut self, ranges: R, new_text: T) -> EditOperation
|
||||||
where
|
where
|
||||||
R: IntoIterator<IntoIter = I>,
|
R: IntoIterator<IntoIter = I>,
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue