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

View File

@ -172,6 +172,15 @@ pub fn len(&self) -> usize {
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 {
self.len() == 0
}

View File

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