mirror of
https://github.com/zed-industries/zed.git
synced 2025-01-12 21:32:40 +00:00
Introduce transactional edits and allow snapshotting of selections
This commit is contained in:
parent
40bfdd38ae
commit
ab14b99a73
2 changed files with 203 additions and 44 deletions
|
@ -66,7 +66,8 @@ pub struct Buffer {
|
||||||
last_edit: time::Local,
|
last_edit: time::Local,
|
||||||
undo_map: UndoMap,
|
undo_map: UndoMap,
|
||||||
history: History,
|
history: History,
|
||||||
selections: HashMap<SelectionSetId, Vec<Selection>>,
|
pending_transaction: Option<PendingTransaction>,
|
||||||
|
selections: HashMap<SelectionSetId, Arc<[Selection]>>,
|
||||||
pub selections_last_update: SelectionsVersion,
|
pub selections_last_update: SelectionsVersion,
|
||||||
deferred_ops: OperationQueue<Operation>,
|
deferred_ops: OperationQueue<Operation>,
|
||||||
deferred_replicas: HashSet<ReplicaId>,
|
deferred_replicas: HashSet<ReplicaId>,
|
||||||
|
@ -80,8 +81,22 @@ pub struct Snapshot {
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Clone)]
|
#[derive(Clone)]
|
||||||
struct EditGroup {
|
struct SelectionSetSnapshot {
|
||||||
|
set_id: SelectionSetId,
|
||||||
|
before_transaction: Arc<[Selection]>,
|
||||||
|
after_transaction: Arc<[Selection]>,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Clone)]
|
||||||
|
struct PendingTransaction {
|
||||||
|
start: time::Global,
|
||||||
|
buffer_was_dirty: bool,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Clone)]
|
||||||
|
struct Transaction {
|
||||||
edits: Vec<time::Local>,
|
edits: Vec<time::Local>,
|
||||||
|
selections: Option<SelectionSetSnapshot>,
|
||||||
last_edit_at: Instant,
|
last_edit_at: Instant,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -89,8 +104,9 @@ struct EditGroup {
|
||||||
pub struct History {
|
pub struct History {
|
||||||
pub base_text: Arc<str>,
|
pub base_text: Arc<str>,
|
||||||
ops: HashMap<time::Local, EditOperation>,
|
ops: HashMap<time::Local, EditOperation>,
|
||||||
undo_stack: Vec<EditGroup>,
|
undo_stack: Vec<Transaction>,
|
||||||
redo_stack: Vec<EditGroup>,
|
redo_stack: Vec<Transaction>,
|
||||||
|
transaction_depth: usize,
|
||||||
group_interval: Duration,
|
group_interval: Duration,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -101,6 +117,7 @@ impl History {
|
||||||
ops: Default::default(),
|
ops: Default::default(),
|
||||||
undo_stack: Vec::new(),
|
undo_stack: Vec::new(),
|
||||||
redo_stack: Vec::new(),
|
redo_stack: Vec::new(),
|
||||||
|
transaction_depth: 0,
|
||||||
group_interval: UNDO_GROUP_INTERVAL,
|
group_interval: UNDO_GROUP_INTERVAL,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -109,37 +126,85 @@ impl History {
|
||||||
self.ops.insert(op.id, op);
|
self.ops.insert(op.id, op);
|
||||||
}
|
}
|
||||||
|
|
||||||
fn push_undo(&mut self, edit_id: time::Local, now: Instant) {
|
fn start_transaction(
|
||||||
if let Some(edit_group) = self.undo_stack.last_mut() {
|
&mut self,
|
||||||
if now - edit_group.last_edit_at <= self.group_interval {
|
selections: Option<(SelectionSetId, Arc<[Selection]>)>,
|
||||||
edit_group.edits.push(edit_id);
|
now: Instant,
|
||||||
edit_group.last_edit_at = now;
|
) -> bool {
|
||||||
|
self.transaction_depth += 1;
|
||||||
|
if self.transaction_depth == 1 {
|
||||||
|
if let Some(transaction) = self.undo_stack.last_mut() {
|
||||||
|
if now - transaction.last_edit_at <= self.group_interval {
|
||||||
|
transaction.last_edit_at = now;
|
||||||
|
} else {
|
||||||
|
self.undo_stack.push(Transaction {
|
||||||
|
edits: Vec::new(),
|
||||||
|
selections: selections.map(|(set_id, selections)| SelectionSetSnapshot {
|
||||||
|
set_id,
|
||||||
|
before_transaction: selections.clone(),
|
||||||
|
after_transaction: selections,
|
||||||
|
}),
|
||||||
|
last_edit_at: now,
|
||||||
|
});
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
self.undo_stack.push(EditGroup {
|
self.undo_stack.push(Transaction {
|
||||||
edits: vec![edit_id],
|
edits: Vec::new(),
|
||||||
|
selections: selections.map(|(set_id, selections)| SelectionSetSnapshot {
|
||||||
|
set_id,
|
||||||
|
before_transaction: selections.clone(),
|
||||||
|
after_transaction: selections,
|
||||||
|
}),
|
||||||
last_edit_at: now,
|
last_edit_at: now,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
true
|
||||||
} else {
|
} else {
|
||||||
self.undo_stack.push(EditGroup {
|
false
|
||||||
edits: vec![edit_id],
|
|
||||||
last_edit_at: now,
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn pop_undo(&mut self) -> Option<&EditGroup> {
|
fn end_transaction(
|
||||||
if let Some(edit_group) = self.undo_stack.pop() {
|
&mut self,
|
||||||
self.redo_stack.push(edit_group);
|
selections: Option<(SelectionSetId, Arc<[Selection]>)>,
|
||||||
|
now: Instant,
|
||||||
|
) -> bool {
|
||||||
|
assert_ne!(self.transaction_depth, 0);
|
||||||
|
self.transaction_depth -= 1;
|
||||||
|
if self.transaction_depth == 0 {
|
||||||
|
let transaction = self.undo_stack.last_mut().unwrap();
|
||||||
|
if let Some((set_id, selections)) = selections {
|
||||||
|
if let Some(transaction_selections) = &mut transaction.selections {
|
||||||
|
assert_eq!(set_id, transaction_selections.set_id);
|
||||||
|
transaction_selections.after_transaction = selections;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
transaction.last_edit_at = now;
|
||||||
|
true
|
||||||
|
} else {
|
||||||
|
false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn push_undo(&mut self, edit_id: time::Local) {
|
||||||
|
assert_ne!(self.transaction_depth, 0);
|
||||||
|
self.undo_stack.last_mut().unwrap().edits.push(edit_id);
|
||||||
|
}
|
||||||
|
|
||||||
|
fn pop_undo(&mut self) -> Option<&Transaction> {
|
||||||
|
assert_eq!(self.transaction_depth, 0);
|
||||||
|
if let Some(transaction) = self.undo_stack.pop() {
|
||||||
|
self.redo_stack.push(transaction);
|
||||||
self.redo_stack.last()
|
self.redo_stack.last()
|
||||||
} else {
|
} else {
|
||||||
None
|
None
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn pop_redo(&mut self) -> Option<&EditGroup> {
|
fn pop_redo(&mut self) -> Option<&Transaction> {
|
||||||
if let Some(edit_group) = self.redo_stack.pop() {
|
assert_eq!(self.transaction_depth, 0);
|
||||||
self.undo_stack.push(edit_group);
|
if let Some(transaction) = self.redo_stack.pop() {
|
||||||
|
self.undo_stack.push(transaction);
|
||||||
self.undo_stack.last()
|
self.undo_stack.last()
|
||||||
} else {
|
} else {
|
||||||
None
|
None
|
||||||
|
@ -274,7 +339,7 @@ pub enum Operation {
|
||||||
},
|
},
|
||||||
UpdateSelections {
|
UpdateSelections {
|
||||||
set_id: SelectionSetId,
|
set_id: SelectionSetId,
|
||||||
selections: Option<Vec<Selection>>,
|
selections: Option<Arc<[Selection]>>,
|
||||||
lamport_timestamp: time::Lamport,
|
lamport_timestamp: time::Lamport,
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
@ -364,6 +429,7 @@ impl Buffer {
|
||||||
last_edit: time::Local::default(),
|
last_edit: time::Local::default(),
|
||||||
undo_map: Default::default(),
|
undo_map: Default::default(),
|
||||||
history,
|
history,
|
||||||
|
pending_transaction: None,
|
||||||
selections: HashMap::default(),
|
selections: HashMap::default(),
|
||||||
selections_last_update: 0,
|
selections_last_update: 0,
|
||||||
deferred_ops: OperationQueue::new(),
|
deferred_ops: OperationQueue::new(),
|
||||||
|
@ -545,6 +611,68 @@ impl Buffer {
|
||||||
self.deferred_ops.len()
|
self.deferred_ops.len()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn start_transaction(&mut self, set_id: Option<SelectionSetId>) -> Result<()> {
|
||||||
|
self.start_transaction_at(set_id, Instant::now())
|
||||||
|
}
|
||||||
|
|
||||||
|
fn start_transaction_at(&mut self, set_id: Option<SelectionSetId>, now: Instant) -> Result<()> {
|
||||||
|
let selections = if let Some(set_id) = set_id {
|
||||||
|
let selections = self
|
||||||
|
.selections
|
||||||
|
.get(&set_id)
|
||||||
|
.ok_or_else(|| anyhow!("invalid selection set {:?}", set_id))?;
|
||||||
|
Some((set_id, selections.clone()))
|
||||||
|
} else {
|
||||||
|
None
|
||||||
|
};
|
||||||
|
if self.history.start_transaction(selections, now) {
|
||||||
|
self.pending_transaction = Some(PendingTransaction {
|
||||||
|
start: self.version.clone(),
|
||||||
|
buffer_was_dirty: self.is_dirty(),
|
||||||
|
});
|
||||||
|
}
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn end_transaction(
|
||||||
|
&mut self,
|
||||||
|
set_id: Option<SelectionSetId>,
|
||||||
|
ctx: Option<&mut ModelContext<Self>>,
|
||||||
|
) -> Result<()> {
|
||||||
|
self.end_transaction_at(set_id, Instant::now(), ctx)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn end_transaction_at(
|
||||||
|
&mut self,
|
||||||
|
set_id: Option<SelectionSetId>,
|
||||||
|
now: Instant,
|
||||||
|
ctx: Option<&mut ModelContext<Self>>,
|
||||||
|
) -> Result<()> {
|
||||||
|
let selections = if let Some(set_id) = set_id {
|
||||||
|
let selections = self
|
||||||
|
.selections
|
||||||
|
.get(&set_id)
|
||||||
|
.ok_or_else(|| anyhow!("invalid selection set {:?}", set_id))?;
|
||||||
|
Some((set_id, selections.clone()))
|
||||||
|
} else {
|
||||||
|
None
|
||||||
|
};
|
||||||
|
|
||||||
|
if self.history.end_transaction(selections, now) {
|
||||||
|
if let Some(ctx) = ctx {
|
||||||
|
ctx.notify();
|
||||||
|
|
||||||
|
let transaction = self.pending_transaction.take().unwrap();
|
||||||
|
let changes = self.edits_since(transaction.start).collect::<Vec<_>>();
|
||||||
|
if !changes.is_empty() {
|
||||||
|
self.did_edit(changes, transaction.buffer_was_dirty, ctx);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
pub fn edit<I, S, T>(
|
pub fn edit<I, S, T>(
|
||||||
&mut self,
|
&mut self,
|
||||||
old_ranges: I,
|
old_ranges: I,
|
||||||
|
@ -571,6 +699,8 @@ impl Buffer {
|
||||||
S: ToOffset,
|
S: ToOffset,
|
||||||
T: Into<Text>,
|
T: Into<Text>,
|
||||||
{
|
{
|
||||||
|
self.start_transaction_at(None, now)?;
|
||||||
|
|
||||||
let new_text = new_text.into();
|
let new_text = new_text.into();
|
||||||
let new_text = if new_text.len() > 0 {
|
let new_text = if new_text.len() > 0 {
|
||||||
Some(new_text)
|
Some(new_text)
|
||||||
|
@ -578,8 +708,6 @@ impl Buffer {
|
||||||
None
|
None
|
||||||
};
|
};
|
||||||
|
|
||||||
let was_dirty = self.is_dirty();
|
|
||||||
let old_version = self.version.clone();
|
|
||||||
let old_ranges = old_ranges
|
let old_ranges = old_ranges
|
||||||
.into_iter()
|
.into_iter()
|
||||||
.map(|range| Ok(range.start.to_offset(self)?..range.end.to_offset(self)?))
|
.map(|range| Ok(range.start.to_offset(self)?..range.end.to_offset(self)?))
|
||||||
|
@ -595,19 +723,11 @@ impl Buffer {
|
||||||
for op in &ops {
|
for op in &ops {
|
||||||
if let Operation::Edit { edit, .. } = op {
|
if let Operation::Edit { edit, .. } = op {
|
||||||
self.history.push(edit.clone());
|
self.history.push(edit.clone());
|
||||||
self.history.push_undo(edit.id, now);
|
self.history.push_undo(edit.id);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if let Some(op) = ops.last() {
|
if let Some(op) = ops.last() {
|
||||||
if let Some(ctx) = ctx {
|
|
||||||
ctx.notify();
|
|
||||||
let changes = self.edits_since(old_version).collect::<Vec<_>>();
|
|
||||||
if !changes.is_empty() {
|
|
||||||
self.did_edit(changes, was_dirty, ctx);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if let Operation::Edit { edit, .. } = op {
|
if let Operation::Edit { edit, .. } = op {
|
||||||
self.last_edit = edit.id;
|
self.last_edit = edit.id;
|
||||||
self.version.observe(edit.id);
|
self.version.observe(edit.id);
|
||||||
|
@ -616,6 +736,8 @@ impl Buffer {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
self.end_transaction_at(None, now, ctx)?;
|
||||||
|
|
||||||
Ok(ops)
|
Ok(ops)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -675,9 +797,10 @@ impl Buffer {
|
||||||
selections: Vec<Selection>,
|
selections: Vec<Selection>,
|
||||||
ctx: Option<&mut ModelContext<Self>>,
|
ctx: Option<&mut ModelContext<Self>>,
|
||||||
) -> (SelectionSetId, Operation) {
|
) -> (SelectionSetId, Operation) {
|
||||||
|
let selections = Arc::from(selections);
|
||||||
let lamport_timestamp = self.lamport_clock.tick();
|
let lamport_timestamp = self.lamport_clock.tick();
|
||||||
self.selections
|
self.selections
|
||||||
.insert(lamport_timestamp, selections.clone());
|
.insert(lamport_timestamp, Arc::clone(&selections));
|
||||||
self.selections_last_update += 1;
|
self.selections_last_update += 1;
|
||||||
|
|
||||||
if let Some(ctx) = ctx {
|
if let Some(ctx) = ctx {
|
||||||
|
@ -701,7 +824,8 @@ impl Buffer {
|
||||||
ctx: Option<&mut ModelContext<Self>>,
|
ctx: Option<&mut ModelContext<Self>>,
|
||||||
) -> Result<Operation> {
|
) -> Result<Operation> {
|
||||||
self.merge_selections(&mut selections);
|
self.merge_selections(&mut selections);
|
||||||
self.selections.insert(set_id, selections.clone());
|
let selections = Arc::from(selections);
|
||||||
|
self.selections.insert(set_id, Arc::clone(&selections));
|
||||||
|
|
||||||
let lamport_timestamp = self.lamport_clock.tick();
|
let lamport_timestamp = self.lamport_clock.tick();
|
||||||
self.selections_last_update += 1;
|
self.selections_last_update += 1;
|
||||||
|
@ -742,7 +866,7 @@ impl Buffer {
|
||||||
pub fn selections(&self, set_id: SelectionSetId) -> Result<&[Selection]> {
|
pub fn selections(&self, set_id: SelectionSetId) -> Result<&[Selection]> {
|
||||||
self.selections
|
self.selections
|
||||||
.get(&set_id)
|
.get(&set_id)
|
||||||
.map(|s| s.as_slice())
|
.map(|s| s.as_ref())
|
||||||
.ok_or_else(|| anyhow!("invalid selection set id {:?}", set_id))
|
.ok_or_else(|| anyhow!("invalid selection set id {:?}", set_id))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -761,8 +885,10 @@ impl Buffer {
|
||||||
}))
|
}))
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn all_selections(&self) -> impl Iterator<Item = (&SelectionSetId, &Vec<Selection>)> {
|
pub fn all_selections(&self) -> impl Iterator<Item = (&SelectionSetId, &[Selection])> {
|
||||||
self.selections.iter()
|
self.selections
|
||||||
|
.iter()
|
||||||
|
.map(|(set_id, selections)| (set_id, selections.as_ref()))
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn all_selection_ranges<'a>(
|
pub fn all_selection_ranges<'a>(
|
||||||
|
@ -998,10 +1124,17 @@ impl Buffer {
|
||||||
let old_version = self.version.clone();
|
let old_version = self.version.clone();
|
||||||
|
|
||||||
let mut ops = Vec::new();
|
let mut ops = Vec::new();
|
||||||
if let Some(edit_group) = self.history.pop_undo() {
|
if let Some(transaction) = self.history.pop_undo() {
|
||||||
for edit_id in edit_group.edits.clone() {
|
let transaction_selections = transaction.selections.clone();
|
||||||
|
for edit_id in transaction.edits.clone() {
|
||||||
ops.push(self.undo_or_redo(edit_id).unwrap());
|
ops.push(self.undo_or_redo(edit_id).unwrap());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if let Some(transaction_selections) = transaction_selections {
|
||||||
|
if let Some(selections) = self.selections.get_mut(&transaction_selections.set_id) {
|
||||||
|
*selections = transaction_selections.before_transaction;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if let Some(ctx) = ctx {
|
if let Some(ctx) = ctx {
|
||||||
|
@ -1020,10 +1153,17 @@ impl Buffer {
|
||||||
let old_version = self.version.clone();
|
let old_version = self.version.clone();
|
||||||
|
|
||||||
let mut ops = Vec::new();
|
let mut ops = Vec::new();
|
||||||
if let Some(edit_group) = self.history.pop_redo() {
|
if let Some(transaction) = self.history.pop_redo() {
|
||||||
for edit_id in edit_group.edits.clone() {
|
let transaction_selections = transaction.selections.clone();
|
||||||
|
for edit_id in transaction.edits.clone() {
|
||||||
ops.push(self.undo_or_redo(edit_id).unwrap());
|
ops.push(self.undo_or_redo(edit_id).unwrap());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if let Some(transaction_selections) = transaction_selections {
|
||||||
|
if let Some(selections) = self.selections.get_mut(&transaction_selections.set_id) {
|
||||||
|
*selections = transaction_selections.after_transaction;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if let Some(ctx) = ctx {
|
if let Some(ctx) = ctx {
|
||||||
|
@ -1686,6 +1826,7 @@ impl Clone for Buffer {
|
||||||
last_edit: self.last_edit.clone(),
|
last_edit: self.last_edit.clone(),
|
||||||
undo_map: self.undo_map.clone(),
|
undo_map: self.undo_map.clone(),
|
||||||
history: self.history.clone(),
|
history: self.history.clone(),
|
||||||
|
pending_transaction: self.pending_transaction.clone(),
|
||||||
selections: self.selections.clone(),
|
selections: self.selections.clone(),
|
||||||
selections_last_update: self.selections_last_update.clone(),
|
selections_last_update: self.selections_last_update.clone(),
|
||||||
deferred_ops: self.deferred_ops.clone(),
|
deferred_ops: self.deferred_ops.clone(),
|
||||||
|
|
|
@ -379,6 +379,7 @@ impl BufferView {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
self.start_transaction(ctx);
|
||||||
let mut new_selections = Vec::new();
|
let mut new_selections = Vec::new();
|
||||||
self.buffer.update(ctx, |buffer, ctx| {
|
self.buffer.update(ctx, |buffer, ctx| {
|
||||||
if let Err(error) = buffer.edit(offset_ranges.iter().cloned(), text.as_str(), Some(ctx))
|
if let Err(error) = buffer.edit(offset_ranges.iter().cloned(), text.as_str(), Some(ctx))
|
||||||
|
@ -408,8 +409,7 @@ impl BufferView {
|
||||||
});
|
});
|
||||||
|
|
||||||
self.update_selections(new_selections, ctx);
|
self.update_selections(new_selections, ctx);
|
||||||
self.pause_cursor_blinking(ctx);
|
self.end_transaction(ctx);
|
||||||
*self.autoscroll_requested.lock() = true;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn newline(&mut self, _: &(), ctx: &mut ViewContext<Self>) {
|
fn newline(&mut self, _: &(), ctx: &mut ViewContext<Self>) {
|
||||||
|
@ -421,6 +421,7 @@ impl BufferView {
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn backspace(&mut self, _: &(), ctx: &mut ViewContext<Self>) {
|
pub fn backspace(&mut self, _: &(), ctx: &mut ViewContext<Self>) {
|
||||||
|
self.start_transaction(ctx);
|
||||||
let mut selections = self.selections(ctx.app()).to_vec();
|
let mut selections = self.selections(ctx.app()).to_vec();
|
||||||
{
|
{
|
||||||
let buffer = self.buffer.as_ref(ctx);
|
let buffer = self.buffer.as_ref(ctx);
|
||||||
|
@ -444,6 +445,7 @@ impl BufferView {
|
||||||
self.update_selections(selections, ctx);
|
self.update_selections(selections, ctx);
|
||||||
self.changed_selections(ctx);
|
self.changed_selections(ctx);
|
||||||
self.insert(&String::new(), ctx);
|
self.insert(&String::new(), ctx);
|
||||||
|
self.end_transaction(ctx);
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn undo(&mut self, _: &(), ctx: &mut ViewContext<Self>) {
|
pub fn undo(&mut self, _: &(), ctx: &mut ViewContext<Self>) {
|
||||||
|
@ -727,6 +729,22 @@ impl BufferView {
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn start_transaction(&self, ctx: &mut ViewContext<Self>) {
|
||||||
|
self.buffer.update(ctx, |buffer, _| {
|
||||||
|
buffer
|
||||||
|
.start_transaction(Some(self.selection_set_id))
|
||||||
|
.unwrap()
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
fn end_transaction(&self, ctx: &mut ViewContext<Self>) {
|
||||||
|
self.buffer.update(ctx, |buffer, ctx| {
|
||||||
|
buffer
|
||||||
|
.end_transaction(Some(self.selection_set_id), Some(ctx))
|
||||||
|
.unwrap()
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
pub fn page_up(&mut self, _: &(), _: &mut ViewContext<Self>) {
|
pub fn page_up(&mut self, _: &(), _: &mut ViewContext<Self>) {
|
||||||
log::info!("BufferView::page_up");
|
log::info!("BufferView::page_up");
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue