mirror of https://github.com/lapce/lapce.git
store cursor position for undo/redo
This commit is contained in:
parent
ed55108bcd
commit
3aa2180890
|
@ -17,6 +17,7 @@
|
|||
};
|
||||
|
||||
use crate::{
|
||||
cursor::CursorMode,
|
||||
editor::EditType,
|
||||
indent::{auto_detect_indent_style, IndentStyle},
|
||||
mode::Mode,
|
||||
|
@ -54,6 +55,8 @@ struct Revision {
|
|||
num: u64,
|
||||
max_undo_so_far: usize,
|
||||
edit: Contents,
|
||||
cursor_before: Option<CursorMode>,
|
||||
cursor_after: Option<CursorMode>,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
|
@ -103,6 +106,8 @@ pub fn new(text: &str) -> Self {
|
|||
toggled_groups: BTreeSet::new(),
|
||||
deletes_bitxor: Subset::new(0),
|
||||
},
|
||||
cursor_before: None,
|
||||
cursor_after: None,
|
||||
}],
|
||||
cur_undo: 1,
|
||||
undos: BTreeSet::new(),
|
||||
|
@ -133,6 +138,18 @@ pub fn is_pristine(&self) -> bool {
|
|||
self.is_equivalent_revision(self.pristine_rev_id, self.rev())
|
||||
}
|
||||
|
||||
pub fn set_cursor_before(&mut self, cursor: CursorMode) {
|
||||
self.revs
|
||||
.last_mut()
|
||||
.map(|rev| rev.cursor_before = Some(cursor));
|
||||
}
|
||||
|
||||
pub fn set_cursor_after(&mut self, cursor: CursorMode) {
|
||||
self.revs
|
||||
.last_mut()
|
||||
.map(|rev| rev.cursor_after = Some(cursor));
|
||||
}
|
||||
|
||||
fn is_equivalent_revision(&self, base_rev: u64, other_rev: u64) -> bool {
|
||||
let base_subset = self
|
||||
.find_rev(base_rev)
|
||||
|
@ -411,6 +428,8 @@ fn mk_new_rev(
|
|||
inserts: new_inserts,
|
||||
deletes: new_deletes,
|
||||
},
|
||||
cursor_before: None,
|
||||
cursor_after: None,
|
||||
},
|
||||
new_text,
|
||||
new_tombstones,
|
||||
|
@ -535,6 +554,32 @@ fn compute_undo(&self, groups: &BTreeSet<usize>) -> (Revision, Subset) {
|
|||
}
|
||||
}
|
||||
|
||||
let cursor_before = self
|
||||
.revs
|
||||
.get(first_candidate)
|
||||
.and_then(|rev| rev.cursor_before.clone());
|
||||
|
||||
let cursor_after = self
|
||||
.revs
|
||||
.get(first_candidate)
|
||||
.and_then(|rev| match &rev.edit {
|
||||
Contents::Edit { undo_group, .. } => Some(undo_group),
|
||||
Contents::Undo { .. } => None,
|
||||
})
|
||||
.and_then(|group| {
|
||||
let mut cursor: Option<&CursorMode> = None;
|
||||
for rev in &self.revs[first_candidate..] {
|
||||
if let Contents::Edit { ref undo_group, .. } = rev.edit {
|
||||
if group == undo_group {
|
||||
cursor = rev.cursor_after.as_ref();
|
||||
} else {
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
cursor.cloned()
|
||||
});
|
||||
|
||||
let deletes_bitxor = self.deletes_from_union.bitxor(&deletes_from_union);
|
||||
let max_undo_so_far = self.revs.last().unwrap().max_undo_so_far;
|
||||
self.atomic_rev
|
||||
|
@ -547,12 +592,22 @@ fn compute_undo(&self, groups: &BTreeSet<usize>) -> (Revision, Subset) {
|
|||
toggled_groups,
|
||||
deletes_bitxor,
|
||||
},
|
||||
cursor_before,
|
||||
cursor_after,
|
||||
},
|
||||
deletes_from_union,
|
||||
)
|
||||
}
|
||||
|
||||
fn undo(&mut self, groups: BTreeSet<usize>) -> (RopeDelta, InvalLines) {
|
||||
fn undo(
|
||||
&mut self,
|
||||
groups: BTreeSet<usize>,
|
||||
) -> (
|
||||
RopeDelta,
|
||||
InvalLines,
|
||||
Option<CursorMode>,
|
||||
Option<CursorMode>,
|
||||
) {
|
||||
let (new_rev, new_deletes_from_union) = self.compute_undo(&groups);
|
||||
let delta = Delta::synthesize(
|
||||
&self.tombstones,
|
||||
|
@ -568,6 +623,9 @@ fn undo(&mut self, groups: BTreeSet<usize>) -> (RopeDelta, InvalLines) {
|
|||
);
|
||||
self.undone_groups = groups;
|
||||
|
||||
let cursor_before = new_rev.cursor_before.clone();
|
||||
let cursor_after = new_rev.cursor_after.clone();
|
||||
|
||||
let inval_lines = self.apply_edit(
|
||||
&delta,
|
||||
new_rev,
|
||||
|
@ -576,26 +634,34 @@ fn undo(&mut self, groups: BTreeSet<usize>) -> (RopeDelta, InvalLines) {
|
|||
new_deletes_from_union,
|
||||
);
|
||||
|
||||
(delta, inval_lines)
|
||||
(delta, inval_lines, cursor_before, cursor_after)
|
||||
}
|
||||
|
||||
pub fn do_undo(&mut self) -> Option<(RopeDelta, InvalLines)> {
|
||||
pub fn do_undo(
|
||||
&mut self,
|
||||
) -> Option<(RopeDelta, InvalLines, Option<CursorMode>)> {
|
||||
if self.cur_undo > 1 {
|
||||
self.cur_undo -= 1;
|
||||
self.undos.insert(self.live_undos[self.cur_undo]);
|
||||
self.last_edit_type = EditType::Undo;
|
||||
Some(self.undo(self.undos.clone()))
|
||||
let (delta, inval_lines, cursor_before, _cursor_after) =
|
||||
self.undo(self.undos.clone());
|
||||
Some((delta, inval_lines, cursor_before))
|
||||
} else {
|
||||
None
|
||||
}
|
||||
}
|
||||
|
||||
pub fn do_redo(&mut self) -> Option<(RopeDelta, InvalLines)> {
|
||||
pub fn do_redo(
|
||||
&mut self,
|
||||
) -> Option<(RopeDelta, InvalLines, Option<CursorMode>)> {
|
||||
if self.cur_undo < self.live_undos.len() {
|
||||
self.undos.remove(&self.live_undos[self.cur_undo]);
|
||||
self.cur_undo += 1;
|
||||
self.last_edit_type = EditType::Redo;
|
||||
Some(self.undo(self.undos.clone()))
|
||||
let (delta, inval_lines, _cursor_before, cursor_after) =
|
||||
self.undo(self.undos.clone());
|
||||
Some((delta, inval_lines, cursor_after))
|
||||
} else {
|
||||
None
|
||||
}
|
||||
|
|
|
@ -33,6 +33,16 @@ pub enum CursorMode {
|
|||
Insert(Selection),
|
||||
}
|
||||
|
||||
impl CursorMode {
|
||||
pub fn offset(&self) -> usize {
|
||||
match &self {
|
||||
CursorMode::Normal(offset) => *offset,
|
||||
CursorMode::Visual { end, .. } => *end,
|
||||
CursorMode::Insert(selection) => selection.get_cursor_offset(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Cursor {
|
||||
pub fn new(
|
||||
mode: CursorMode,
|
||||
|
@ -48,11 +58,7 @@ pub fn new(
|
|||
}
|
||||
|
||||
pub fn offset(&self) -> usize {
|
||||
match &self.mode {
|
||||
CursorMode::Normal(offset) => *offset,
|
||||
CursorMode::Visual { end, .. } => *end,
|
||||
CursorMode::Insert(selection) => selection.get_cursor_offset(),
|
||||
}
|
||||
self.mode.offset()
|
||||
}
|
||||
|
||||
pub fn is_normal(&self) -> bool {
|
||||
|
|
|
@ -136,10 +136,14 @@ pub fn insert(
|
|||
let (delta, inval_lines) =
|
||||
buffer.edit(&edits, EditType::InsertChars);
|
||||
|
||||
buffer.set_cursor_before(CursorMode::Insert(selection.clone()));
|
||||
|
||||
// Update selection
|
||||
let mut selection =
|
||||
selection.apply_delta(&delta, true, InsertDrift::Default);
|
||||
|
||||
buffer.set_cursor_after(CursorMode::Insert(selection.clone()));
|
||||
|
||||
deltas.push((delta, inval_lines));
|
||||
// Apply late edits
|
||||
let edits_after = edits_after
|
||||
|
@ -158,9 +162,11 @@ pub fn insert(
|
|||
.map(|(selection, content)| (selection, content.as_str()))
|
||||
.collect::<Vec<_>>();
|
||||
|
||||
let (delta, inval_lines) =
|
||||
buffer.edit(&edits_after, EditType::InsertChars);
|
||||
deltas.push((delta, inval_lines));
|
||||
if !edits_after.is_empty() {
|
||||
let (delta, inval_lines) =
|
||||
buffer.edit(&edits_after, EditType::InsertChars);
|
||||
deltas.push((delta, inval_lines));
|
||||
}
|
||||
|
||||
// Adjust selection according to previous late edits
|
||||
let mut adjustment = 0;
|
||||
|
@ -783,13 +789,21 @@ pub fn do_edit<T: Clipboard>(
|
|||
vec![(delta, inval_lines)]
|
||||
}
|
||||
Undo => {
|
||||
if let Some((delta, inval_lines)) = buffer.do_undo() {
|
||||
if let Some(new_cursor) =
|
||||
get_first_selection_after(cursor, buffer, &delta)
|
||||
{
|
||||
*cursor = new_cursor
|
||||
if let Some((delta, inval_lines, cursor_mode)) = buffer.do_undo() {
|
||||
if let Some(cursor_mode) = cursor_mode {
|
||||
if modal {
|
||||
cursor.mode = CursorMode::Normal(cursor_mode.offset());
|
||||
} else {
|
||||
cursor.mode = cursor_mode;
|
||||
}
|
||||
} else {
|
||||
cursor.apply_delta(&delta);
|
||||
if let Some(new_cursor) =
|
||||
get_first_selection_after(cursor, buffer, &delta)
|
||||
{
|
||||
*cursor = new_cursor
|
||||
} else {
|
||||
cursor.apply_delta(&delta);
|
||||
}
|
||||
}
|
||||
vec![(delta, inval_lines)]
|
||||
} else {
|
||||
|
@ -797,13 +811,21 @@ pub fn do_edit<T: Clipboard>(
|
|||
}
|
||||
}
|
||||
Redo => {
|
||||
if let Some((delta, inval_lines)) = buffer.do_redo() {
|
||||
if let Some(new_cursor) =
|
||||
get_first_selection_after(cursor, buffer, &delta)
|
||||
{
|
||||
*cursor = new_cursor
|
||||
if let Some((delta, inval_lines, cursor_mode)) = buffer.do_redo() {
|
||||
if let Some(cursor_mode) = cursor_mode {
|
||||
if modal {
|
||||
cursor.mode = CursorMode::Normal(cursor_mode.offset());
|
||||
} else {
|
||||
cursor.mode = cursor_mode;
|
||||
}
|
||||
} else {
|
||||
cursor.apply_delta(&delta);
|
||||
if let Some(new_cursor) =
|
||||
get_first_selection_after(cursor, buffer, &delta)
|
||||
{
|
||||
*cursor = new_cursor
|
||||
} else {
|
||||
cursor.apply_delta(&delta);
|
||||
}
|
||||
}
|
||||
vec![(delta, inval_lines)]
|
||||
} else {
|
||||
|
|
|
@ -626,8 +626,11 @@ pub fn do_insert(
|
|||
cursor: &mut Cursor,
|
||||
s: &str,
|
||||
) -> Vec<(RopeDelta, InvalLines)> {
|
||||
let old_cursor = cursor.mode.clone();
|
||||
let deltas =
|
||||
Editor::insert(cursor, &mut self.buffer, s, self.syntax.as_ref());
|
||||
self.buffer_mut().set_cursor_before(old_cursor);
|
||||
self.buffer_mut().set_cursor_after(cursor.mode.clone());
|
||||
self.apply_deltas(&deltas);
|
||||
deltas
|
||||
}
|
||||
|
@ -644,14 +647,15 @@ pub fn do_raw_edit(
|
|||
|
||||
pub fn do_edit(
|
||||
&mut self,
|
||||
curosr: &mut Cursor,
|
||||
cursor: &mut Cursor,
|
||||
cmd: &EditCommand,
|
||||
modal: bool,
|
||||
register: &mut Register,
|
||||
) -> Vec<(RopeDelta, InvalLines)> {
|
||||
let mut clipboard = SystemClipboard {};
|
||||
let old_cursor = cursor.mode.clone();
|
||||
let deltas = Editor::do_edit(
|
||||
curosr,
|
||||
cursor,
|
||||
&mut self.buffer,
|
||||
cmd,
|
||||
self.syntax.as_ref(),
|
||||
|
@ -659,6 +663,8 @@ pub fn do_edit(
|
|||
modal,
|
||||
register,
|
||||
);
|
||||
self.buffer_mut().set_cursor_before(old_cursor);
|
||||
self.buffer_mut().set_cursor_after(cursor.mode.clone());
|
||||
self.apply_deltas(&deltas);
|
||||
deltas
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue