aboutsummaryrefslogtreecommitdiff
path: root/helix-view/src/editor.rs
diff options
context:
space:
mode:
Diffstat (limited to 'helix-view/src/editor.rs')
-rw-r--r--helix-view/src/editor.rs70
1 files changed, 69 insertions, 1 deletions
diff --git a/helix-view/src/editor.rs b/helix-view/src/editor.rs
index 973cf82e..c13a6673 100644
--- a/helix-view/src/editor.rs
+++ b/helix-view/src/editor.rs
@@ -1005,6 +1005,8 @@ impl Editor {
return;
}
+ self.enter_normal_mode();
+
match action {
Action::Replace => {
let (view, doc) = current_ref!(self);
@@ -1025,6 +1027,9 @@ impl Editor {
let (view, doc) = current!(self);
let view_id = view.id;
+ // Append any outstanding changes to history in the old document.
+ doc.append_changes_to_history(view);
+
if remove_empty_scratch {
// Copy `doc.id` into a variable before calling `self.documents.remove`, which requires a mutable
// borrow, invalidating direct access to `doc.id`.
@@ -1262,7 +1267,7 @@ impl Editor {
// if leaving the view: mode should reset and the cursor should be
// within view
if prev_id != view_id {
- self.mode = Mode::Normal;
+ self.enter_normal_mode();
self.ensure_cursor_in_view(view_id);
// Update jumplist selections with new document changes.
@@ -1427,4 +1432,67 @@ impl Editor {
Ok(())
}
+
+ /// Switches the editor into normal mode.
+ pub fn enter_normal_mode(&mut self) {
+ use helix_core::{graphemes, Range};
+
+ if self.mode == Mode::Normal {
+ return;
+ }
+
+ self.mode = Mode::Normal;
+ let (view, doc) = current!(self);
+
+ try_restore_indent(doc, view);
+
+ // if leaving append mode, move cursor back by 1
+ if doc.restore_cursor {
+ let text = doc.text().slice(..);
+ let selection = doc.selection(view.id).clone().transform(|range| {
+ Range::new(
+ range.from(),
+ graphemes::prev_grapheme_boundary(text, range.to()),
+ )
+ });
+
+ doc.set_selection(view.id, selection);
+ doc.restore_cursor = false;
+ }
+ }
+}
+
+fn try_restore_indent(doc: &mut Document, view: &mut View) {
+ use helix_core::{
+ chars::char_is_whitespace, line_ending::line_end_char_index, Operation, Transaction,
+ };
+
+ fn inserted_a_new_blank_line(changes: &[Operation], pos: usize, line_end_pos: usize) -> bool {
+ if let [Operation::Retain(move_pos), Operation::Insert(ref inserted_str), Operation::Retain(_)] =
+ changes
+ {
+ move_pos + inserted_str.len() == pos
+ && inserted_str.starts_with('\n')
+ && inserted_str.chars().skip(1).all(char_is_whitespace)
+ && pos == line_end_pos // ensure no characters exists after current position
+ } else {
+ false
+ }
+ }
+
+ let doc_changes = doc.changes().changes();
+ let text = doc.text().slice(..);
+ let range = doc.selection(view.id).primary();
+ let pos = range.cursor(text);
+ let line_end_pos = line_end_char_index(&text, range.cursor_line(text));
+
+ if inserted_a_new_blank_line(doc_changes, pos, line_end_pos) {
+ // Removes tailing whitespaces.
+ let transaction =
+ Transaction::change_by_selection(doc.text(), doc.selection(view.id), |range| {
+ let line_start_pos = text.line_to_char(range.cursor_line(text));
+ (line_start_pos, pos, None)
+ });
+ crate::apply_transaction(&transaction, doc, view);
+ }
}