Skip to content

Commit

Permalink
Implement Vim like movement commands
Browse files Browse the repository at this point in the history
This adds new movement commands to allow h/l to be rebound so that they
only operate within a single line like Vim does.  This however cannot be
fully emulated in Helix as Helix will happily place the character on the
newline rather than "before" like Vim does.  This means that if one
moves to the right, "i" is needed to insert rather than "a" what a Vim
user would expect.  "a" would still put the character into the new line.

The "move_from_line_end" command is provided which can optionally be
used after all movements to move the character one back if needed.

Unfortunately this also means that the cursor is repositioned which
causes it to forget the original position it had which makes movements
between lines annoying as the cursor has a left drift.
  • Loading branch information
mitsuhiko committed Oct 11, 2022
1 parent 7af7dad commit f01e27b
Show file tree
Hide file tree
Showing 2 changed files with 70 additions and 1 deletion.
25 changes: 25 additions & 0 deletions helix-core/src/movement.rs
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,31 @@ pub fn move_horizontally(
range.put_cursor(slice, new_pos, behaviour == Movement::Extend)
}

pub fn move_horizontally_line_bounded(
slice: RopeSlice,
range: Range,
dir: Direction,
count: usize,
behaviour: Movement,
tab_width: usize,
) -> Range {
let pos = range.cursor(slice);
let new_pos = match dir {
Direction::Forward => nth_next_grapheme_boundary(slice, pos, count),
Direction::Backward => nth_prev_grapheme_boundary(slice, pos, count),
};

let old_coords = visual_coords_at_pos(slice, pos, tab_width);
let new_coords = visual_coords_at_pos(slice, new_pos, tab_width);

// only allow moves within the same line.
if old_coords.row == new_coords.row {
range.put_cursor(slice, new_pos, behaviour == Movement::Extend)
} else {
range
}
}

pub fn move_vertically(
slice: RopeSlice,
range: Range,
Expand Down
46 changes: 45 additions & 1 deletion helix-term/src/commands.rs
Original file line number Diff line number Diff line change
Expand Up @@ -196,9 +196,12 @@ impl MappableCommand {
static_commands!(
no_op, "Do nothing",
move_char_left, "Move left",
move_char_left_same_line, "Move left within same line only",
move_char_right, "Move right",
move_char_right_same_line, "Move right within same line only",
move_line_up, "Move up",
move_line_down, "Move down",
move_from_line_end, "Move left from line end",
extend_char_left, "Extend left",
extend_char_right, "Extend right",
extend_line_up, "Extend up",
Expand Down Expand Up @@ -533,16 +536,34 @@ where
doc.set_selection(view.id, selection);
}

use helix_core::movement::{move_horizontally, move_vertically};
use helix_core::movement::{move_horizontally, move_horizontally_line_bounded, move_vertically};

fn move_char_left(cx: &mut Context) {
move_impl(cx, move_horizontally, Direction::Backward, Movement::Move)
}

fn move_char_left_same_line(cx: &mut Context) {
move_impl(
cx,
move_horizontally_line_bounded,
Direction::Backward,
Movement::Move,
)
}

fn move_char_right(cx: &mut Context) {
move_impl(cx, move_horizontally, Direction::Forward, Movement::Move)
}

fn move_char_right_same_line(cx: &mut Context) {
move_impl(
cx,
move_horizontally_line_bounded,
Direction::Forward,
Movement::Move,
)
}

fn move_line_up(cx: &mut Context) {
move_impl(cx, move_vertically, Direction::Backward, Movement::Move)
}
Expand All @@ -551,6 +572,29 @@ fn move_line_down(cx: &mut Context) {
move_impl(cx, move_vertically, Direction::Forward, Movement::Move)
}

fn move_from_line_end(cx: &mut Context) {
let (view, doc) = current!(cx.editor);
let text = doc.text().slice(..);

let selection = doc.selection(view.id).clone().transform(|range| {
let line = range.cursor_line(text);
let line_start = text.line_to_char(line);

let pos = range.cursor(text);

let last_line_char =
graphemes::prev_grapheme_boundary(text, line_end_char_index(&text, line))
.max(line_start);
if pos == last_line_char + 1 {
range.put_cursor(text, last_line_char, false)
} else {
range
}
});

doc.set_selection(view.id, selection);
}

fn extend_char_left(cx: &mut Context) {
move_impl(cx, move_horizontally, Direction::Backward, Movement::Extend)
}
Expand Down

0 comments on commit f01e27b

Please sign in to comment.