Skip to content

Commit

Permalink
Reset mode when changing buffers (helix-editor#5072)
Browse files Browse the repository at this point in the history
* Reset mode when changing buffers

This is similar to the change in
e4c9d40: reset the editor to normal
mode when changing buffers. Usually the editor is already in normal
mode but it's possible to setup insert-mode keybindings that change
buffers.

* Move normal mode entering code to Editor

This should be called internally in the Editor when changing documents
(Editor::switch) or changing focuses (Editor::focus).
  • Loading branch information
the-mikedavis authored and Frederik Vestre committed Feb 6, 2023
1 parent 110ef1b commit 3f54731
Show file tree
Hide file tree
Showing 2 changed files with 70 additions and 57 deletions.
57 changes: 1 addition & 56 deletions helix-term/src/commands.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2672,62 +2672,7 @@ fn open_above(cx: &mut Context) {
}

fn normal_mode(cx: &mut Context) {
if cx.editor.mode == Mode::Normal {
return;
}

cx.editor.mode = Mode::Normal;
let (view, doc) = current!(cx.editor);

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;
use helix_core::Operation;

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)
});
apply_transaction(&transaction, doc, view);
}
cx.editor.enter_normal_mode();
}

// Store a jump on the jumplist.
Expand Down
70 changes: 69 additions & 1 deletion helix-view/src/editor.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1005,6 +1005,8 @@ impl Editor {
return;
}

self.enter_normal_mode();

match action {
Action::Replace => {
let (view, doc) = current_ref!(self);
Expand All @@ -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`.
Expand Down Expand Up @@ -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.
Expand Down Expand Up @@ -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);
}
}

0 comments on commit 3f54731

Please sign in to comment.