mirror of https://github.com/lapce/lapce.git
make undo more granular
This commit is contained in:
parent
7744f76ce6
commit
c5f1692ec7
|
@ -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);
|
||||||
|
|
|
@ -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
|
||||||
}
|
}
|
||||||
|
|
|
@ -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);
|
||||||
|
|
Loading…
Reference in New Issue