make undo more granular

This commit is contained in:
Dongdong Zhou 2022-07-18 20:09:44 +01:00
parent 7744f76ce6
commit c5f1692ec7
3 changed files with 76 additions and 41 deletions

View File

@ -19,18 +19,30 @@
#[derive(Clone, Copy, Debug, PartialEq)] #[derive(Clone, Copy, Debug, PartialEq)]
pub enum EditType { pub enum EditType {
Other,
InsertChars, InsertChars,
InsertNewline,
Delete, Delete,
DeleteSelection,
InsertNewline,
Cut,
Paste,
Indent,
Outdent,
ToggleComment,
MoveLine,
Completion,
DeleteWord,
DeleteToBeginningOfLine,
MotionDelete,
Undo, Undo,
Redo, Redo,
Other,
} }
impl EditType { impl EditType {
/// Checks whether a new undo group should be created between two edits. /// Checks whether a new undo group should be created between two edits.
pub fn breaks_undo_group(self, previous: EditType) -> bool { pub fn breaks_undo_group(self, previous: EditType) -> bool {
self == EditType::Other || self != previous !((self == EditType::InsertChars || self == EditType::Delete)
&& self == previous)
} }
} }
@ -356,7 +368,7 @@ fn format_start_end(
); );
let selection = Selection::region(start, end); let selection = Selection::region(start, end);
let (delta, inval_lines) = let (delta, inval_lines) =
buffer.edit(&[(&selection, "")], EditType::Delete); buffer.edit(&[(&selection, "")], EditType::MotionDelete);
cursor.apply_delta(&delta); cursor.apply_delta(&delta);
deltas.push((delta, inval_lines)); deltas.push((delta, inval_lines));
} }
@ -407,8 +419,8 @@ pub fn do_paste(
} }
}; };
let after = cursor.is_insert() || !data.content.contains('\n'); let after = cursor.is_insert() || !data.content.contains('\n');
let (delta, inval_lines) = buffer let (delta, inval_lines) =
.edit(&[(&selection, &data.content)], EditType::InsertChars); buffer.edit(&[(&selection, &data.content)], EditType::Paste);
let selection = let selection =
selection.apply_delta(&delta, after, InsertDrift::Default); selection.apply_delta(&delta, after, InsertDrift::Default);
deltas.push((delta, inval_lines)); deltas.push((delta, inval_lines));
@ -459,7 +471,7 @@ pub fn do_paste(
} }
}; };
let (delta, inval_lines) = let (delta, inval_lines) =
buffer.edit(&[(&selection, &content)], EditType::InsertChars); buffer.edit(&[(&selection, &content)], EditType::Paste);
let selection = selection.apply_delta( let selection = selection.apply_delta(
&delta, &delta,
cursor.is_insert(), cursor.is_insert(),
@ -519,7 +531,7 @@ fn do_indent(
} }
} }
buffer.edit(&edits, EditType::InsertChars) buffer.edit(&edits, EditType::Indent)
} }
fn do_outdent( fn do_outdent(
@ -557,7 +569,7 @@ fn do_outdent(
} }
} }
buffer.edit(&edits, EditType::Delete) buffer.edit(&edits, EditType::Outdent)
} }
pub fn do_edit<T: Clipboard>( pub fn do_edit<T: Clipboard>(
@ -595,7 +607,7 @@ pub fn do_edit<T: Clipboard>(
&content, &content,
), ),
], ],
EditType::InsertChars, EditType::MoveLine,
); );
deltas.push((delta, inval_lines)); deltas.push((delta, inval_lines));
region.start -= previous_line_len; region.start -= previous_line_len;
@ -631,7 +643,7 @@ pub fn do_edit<T: Clipboard>(
), ),
(&Selection::region(start, end), ""), (&Selection::region(start, end), ""),
], ],
EditType::InsertChars, EditType::MoveLine,
); );
deltas.push((delta, inval_lines)); deltas.push((delta, inval_lines));
region.start += next_line_len; region.start += next_line_len;
@ -773,7 +785,7 @@ pub fn do_edit<T: Clipboard>(
None, None,
)) ))
} }
buffer.edit(&[(&selection, "")], EditType::Delete) buffer.edit(&[(&selection, "")], EditType::ToggleComment)
} else { } else {
let mut selection = Selection::new(); let mut selection = Selection::new();
for (line, _, _) in lines.iter() { for (line, _, _) in lines.iter() {
@ -782,7 +794,7 @@ pub fn do_edit<T: Clipboard>(
} }
buffer.edit( buffer.edit(
&[(&selection, &format!("{comment_token} "))], &[(&selection, &format!("{comment_token} "))],
EditType::InsertChars, EditType::ToggleComment,
) )
}; };
cursor.apply_delta(&delta); cursor.apply_delta(&delta);
@ -868,7 +880,7 @@ pub fn do_edit<T: Clipboard>(
}; };
let (delta, inval_lines) = let (delta, inval_lines) =
buffer.edit(&[(&selection, "")], EditType::Delete); buffer.edit(&[(&selection, "")], EditType::Cut);
let selection = let selection =
selection.apply_delta(&delta, true, InsertDrift::Default); selection.apply_delta(&delta, true, InsertDrift::Default);
cursor.update_selection(buffer, selection); cursor.update_selection(buffer, selection);
@ -928,13 +940,21 @@ pub fn do_edit<T: Clipboard>(
Self::insert_new_line(buffer, cursor, Selection::caret(offset)) Self::insert_new_line(buffer, cursor, Selection::caret(offset))
} }
DeleteBackward => { DeleteBackward => {
let selection = match cursor.mode { let (selection, edit_type) = match cursor.mode {
CursorMode::Normal(_) | CursorMode::Visual { .. } => { CursorMode::Normal(_) => {
cursor.edit_selection(buffer) (cursor.edit_selection(buffer), EditType::Delete)
}
CursorMode::Visual { .. } => {
(cursor.edit_selection(buffer), EditType::DeleteSelection)
} }
CursorMode::Insert(_) => { CursorMode::Insert(_) => {
let indent = buffer.indent_unit();
let selection = cursor.edit_selection(buffer); let selection = cursor.edit_selection(buffer);
let edit_type = if selection.is_caret() {
EditType::Delete
} else {
EditType::DeleteSelection
};
let indent = buffer.indent_unit();
let mut new_selection = Selection::new(); let mut new_selection = Selection::new();
for region in selection.regions() { for region in selection.regions() {
let new_region = if region.is_caret() { let new_region = if region.is_caret() {
@ -1005,23 +1025,31 @@ pub fn do_edit<T: Clipboard>(
} }
} }
} }
selection (selection, edit_type)
} }
}; };
let (delta, inval_lines) = let (delta, inval_lines) =
buffer.edit(&[(&selection, "")], EditType::Delete); buffer.edit(&[(&selection, "")], edit_type);
let selection = let selection =
selection.apply_delta(&delta, true, InsertDrift::Default); selection.apply_delta(&delta, true, InsertDrift::Default);
cursor.update_selection(buffer, selection); cursor.update_selection(buffer, selection);
vec![(delta, inval_lines)] vec![(delta, inval_lines)]
} }
DeleteForward => { DeleteForward => {
let selection = match cursor.mode { let (selection, edit_type) = match cursor.mode {
CursorMode::Normal(_) | CursorMode::Visual { .. } => { CursorMode::Normal(_) => {
cursor.edit_selection(buffer) (cursor.edit_selection(buffer), EditType::Delete)
}
CursorMode::Visual { .. } => {
(cursor.edit_selection(buffer), EditType::DeleteSelection)
} }
CursorMode::Insert(_) => { CursorMode::Insert(_) => {
let selection = cursor.edit_selection(buffer); let selection = cursor.edit_selection(buffer);
let edit_type = if selection.is_caret() {
EditType::Delete
} else {
EditType::DeleteSelection
};
let mut new_selection = Selection::new(); let mut new_selection = Selection::new();
for region in selection.regions() { for region in selection.regions() {
let new_region = if region.is_caret() { let new_region = if region.is_caret() {
@ -1033,11 +1061,11 @@ pub fn do_edit<T: Clipboard>(
}; };
new_selection.add_region(new_region); new_selection.add_region(new_region);
} }
new_selection (new_selection, edit_type)
} }
}; };
let (delta, inval_lines) = let (delta, inval_lines) =
buffer.edit(&[(&selection, "")], EditType::Delete); buffer.edit(&[(&selection, "")], edit_type);
let selection = let selection =
selection.apply_delta(&delta, true, InsertDrift::Default); selection.apply_delta(&delta, true, InsertDrift::Default);
cursor.update_selection(buffer, selection); cursor.update_selection(buffer, selection);
@ -1062,7 +1090,7 @@ pub fn do_edit<T: Clipboard>(
} }
}; };
let (delta, inval_lines) = let (delta, inval_lines) =
buffer.edit(&[(&selection, "")], EditType::Delete); buffer.edit(&[(&selection, "")], EditType::DeleteWord);
let selection = let selection =
selection.apply_delta(&delta, true, InsertDrift::Default); selection.apply_delta(&delta, true, InsertDrift::Default);
cursor.update_selection(buffer, selection); cursor.update_selection(buffer, selection);
@ -1087,7 +1115,7 @@ pub fn do_edit<T: Clipboard>(
} }
}; };
let (delta, inval_lines) = let (delta, inval_lines) =
buffer.edit(&[(&selection, "")], EditType::Delete); buffer.edit(&[(&selection, "")], EditType::DeleteWord);
let selection = let selection =
selection.apply_delta(&delta, true, InsertDrift::Default); selection.apply_delta(&delta, true, InsertDrift::Default);
cursor.update_selection(buffer, selection); cursor.update_selection(buffer, selection);
@ -1112,8 +1140,8 @@ pub fn do_edit<T: Clipboard>(
new_selection new_selection
} }
}; };
let (delta, inval_lines) = let (delta, inval_lines) = buffer
buffer.edit(&[(&selection, "")], EditType::Delete); .edit(&[(&selection, "")], EditType::DeleteToBeginningOfLine);
let selection = let selection =
selection.apply_delta(&delta, true, InsertDrift::Default); selection.apply_delta(&delta, true, InsertDrift::Default);
cursor.update_selection(buffer, selection); cursor.update_selection(buffer, selection);

View File

@ -172,6 +172,15 @@ pub fn len(&self) -> usize {
self.regions.len() self.regions.len()
} }
pub fn is_caret(&self) -> bool {
for region in self.regions.iter() {
if !region.is_caret() {
return false;
}
}
true
}
pub fn is_empty(&self) -> bool { pub fn is_empty(&self) -> bool {
self.len() == 0 self.len() == 0
} }

View File

@ -39,7 +39,10 @@
use lapce_core::command::{ use lapce_core::command::{
EditCommand, FocusCommand, MotionModeCommand, MultiSelectionCommand, EditCommand, FocusCommand, MotionModeCommand, MultiSelectionCommand,
}; };
use lapce_core::editor::EditType;
use lapce_core::mode::{Mode, MotionMode}; use lapce_core::mode::{Mode, MotionMode};
use lapce_core::selection::InsertDrift;
use lapce_core::selection::Selection;
pub use lapce_core::syntax::Syntax; pub use lapce_core::syntax::Syntax;
use lsp_types::request::GotoTypeDefinitionResponse; use lsp_types::request::GotoTypeDefinitionResponse;
use lsp_types::CodeActionOrCommand; use lsp_types::CodeActionOrCommand;
@ -324,12 +327,12 @@ pub fn apply_completion_item(&mut self, item: &CompletionItem) -> Result<()> {
&additional_edit[..], &additional_edit[..],
] ]
.concat(), .concat(),
lapce_core::editor::EditType::InsertChars, EditType::Completion,
); );
let selection = selection.apply_delta( let selection = selection.apply_delta(
&delta, &delta,
true, true,
lapce_core::selection::InsertDrift::Default, InsertDrift::Default,
); );
Arc::make_mut(&mut self.editor) Arc::make_mut(&mut self.editor)
.cursor .cursor
@ -347,12 +350,12 @@ pub fn apply_completion_item(&mut self, item: &CompletionItem) -> Result<()> {
&additional_edit[..], &additional_edit[..],
] ]
.concat(), .concat(),
lapce_core::editor::EditType::InsertChars, EditType::Completion,
); );
let selection = selection.apply_delta( let selection = selection.apply_delta(
&delta, &delta,
true, true,
lapce_core::selection::InsertDrift::Default, InsertDrift::Default,
); );
let mut transformer = Transformer::new(&delta); let mut transformer = Transformer::new(&delta);
@ -393,8 +396,7 @@ pub fn apply_completion_item(&mut self, item: &CompletionItem) -> Result<()> {
let offset = self.editor.cursor.offset(); let offset = self.editor.cursor.offset();
let start_offset = self.doc.buffer().prev_code_boundary(offset); let start_offset = self.doc.buffer().prev_code_boundary(offset);
let end_offset = self.doc.buffer().next_code_boundary(offset); let end_offset = self.doc.buffer().next_code_boundary(offset);
let selection = let selection = Selection::region(start_offset, end_offset);
lapce_core::selection::Selection::region(start_offset, end_offset);
let (delta, inval_lines) = Arc::make_mut(&mut self.doc).do_raw_edit( let (delta, inval_lines) = Arc::make_mut(&mut self.doc).do_raw_edit(
&[ &[
@ -405,13 +407,9 @@ pub fn apply_completion_item(&mut self, item: &CompletionItem) -> Result<()> {
&additional_edit[..], &additional_edit[..],
] ]
.concat(), .concat(),
lapce_core::editor::EditType::InsertChars, EditType::Completion,
);
let selection = selection.apply_delta(
&delta,
true,
lapce_core::selection::InsertDrift::Default,
); );
let selection = selection.apply_delta(&delta, true, InsertDrift::Default);
Arc::make_mut(&mut self.editor) Arc::make_mut(&mut self.editor)
.cursor .cursor
.update_selection(self.doc.buffer(), selection); .update_selection(self.doc.buffer(), selection);