From 9ab3f9d01a8ea4967f5a7e64a3f6c8f350674c18 Mon Sep 17 00:00:00 2001 From: AlexanderDickie <75994927+AlexanderDickie@users.noreply.github.com> Date: Sun, 18 Feb 2024 23:13:04 +0000 Subject: [PATCH] Scroll cursor and page together (neovim-like scrolling) (#8015) * neovim like scroll function * clear line annotations outside of move_vertically/_visual * add nvim scroll function to commands * assign nvim-scroll to C-d and C-u (half page scrolls) * dont remove backspace and space mapping * move non-softwrap logic to seperate function, call this in nvim-scroll fn * Revert "move non-softwrap logic to seperate function, call this in nvim-scroll fn" This reverts commit e4905729c338a2260e6981f1d8fac022897b4191. * Revert "clear line annotations outside of move_vertically/_visual" This reverts commit 1df3fefe55afc840d1ab5094b2116d1127fc363f. * add TODO for when inline diagnostics gets merged * move nvim-scroll logic into scroll(), dont respect scrolloff * run cargo fmt * run cargo clippy * update documenation for Ctrl-d and Ctrl-u remap --- book/src/keymap.md | 28 ++++++------- helix-term/src/commands.rs | 68 ++++++++++++++++++++++++++++---- helix-term/src/keymap/default.rs | 12 +++--- helix-term/src/ui/editor.rs | 2 +- 4 files changed, 81 insertions(+), 29 deletions(-) diff --git a/book/src/keymap.md b/book/src/keymap.md index a3e41666f..ac84147cd 100644 --- a/book/src/keymap.md +++ b/book/src/keymap.md @@ -53,8 +53,8 @@ ### Movement | `End` | Move to the end of the line | `goto_line_end` | | `Ctrl-b`, `PageUp` | Move page up | `page_up` | | `Ctrl-f`, `PageDown` | Move page down | `page_down` | -| `Ctrl-u` | Move half page up | `half_page_up` | -| `Ctrl-d` | Move half page down | `half_page_down` | +| `Ctrl-u` | Move cursor and page half page up | `page_cursor_half_up` | +| `Ctrl-d` | Move cursor and page half page down | `page_cursor_half_down` | | `Ctrl-i` | Jump forward on the jumplist | `jump_forward` | | `Ctrl-o` | Jump backward on the jumplist | `jump_backward` | | `Ctrl-s` | Save the current selection to the jumplist | `save_selection` | @@ -182,18 +182,18 @@ #### View mode useful when you're simply looking over text and not actively editing it. -| Key | Description | Command | -| ----- | ----------- | ------- | -| `z`, `c` | Vertically center the line | `align_view_center` | -| `t` | Align the line to the top of the screen | `align_view_top` | -| `b` | Align the line to the bottom of the screen | `align_view_bottom` | -| `m` | Align the line to the middle of the screen (horizontally) | `align_view_middle` | -| `j`, `down` | Scroll the view downwards | `scroll_down` | -| `k`, `up` | Scroll the view upwards | `scroll_up` | -| `Ctrl-f`, `PageDown` | Move page down | `page_down` | -| `Ctrl-b`, `PageUp` | Move page up | `page_up` | -| `Ctrl-d` | Move half page down | `half_page_down` | -| `Ctrl-u` | Move half page up | `half_page_up` | +| Key | Description | Command | +| ----- | ----------- | ------- | +| `z`, `c` | Vertically center the line | `align_view_center` | +| `t` | Align the line to the top of the screen | `align_view_top` | +| `b` | Align the line to the bottom of the screen | `align_view_bottom` | +| `m` | Align the line to the middle of the screen (horizontally) | `align_view_middle` | +| `j`, `down` | Scroll the view downwards | `scroll_down` | +| `k`, `up` | Scroll the view upwards | `scroll_up` | +| `Ctrl-f`, `PageDown` | Move page down | `page_down` | +| `Ctrl-b`, `PageUp` | Move page up | `page_up` | +| `Ctrl-u` | Move cursor and page half page up | `page_cursor_half_up` | +| `Ctrl-d` | Move cursor and page half page down | `page_cursor_half_down` | #### Goto mode diff --git a/helix-term/src/commands.rs b/helix-term/src/commands.rs index e46109c0f..51a1ede9b 100644 --- a/helix-term/src/commands.rs +++ b/helix-term/src/commands.rs @@ -277,6 +277,10 @@ pub fn doc(&self) -> &str { page_down, "Move page down", half_page_up, "Move half page up", half_page_down, "Move half page down", + page_cursor_up, "Move page and cursor up", + page_cursor_down, "Move page and cursor down", + page_cursor_half_up, "Move page and cursor half up", + page_cursor_half_down, "Move page and cursor half down", select_all, "Select whole document", select_regex, "Select all regex matches inside selections", split_selection, "Split selections on regex matches", @@ -1608,7 +1612,7 @@ fn switch_to_lowercase(cx: &mut Context) { }); } -pub fn scroll(cx: &mut Context, offset: usize, direction: Direction) { +pub fn scroll(cx: &mut Context, offset: usize, direction: Direction, sync_cursor: bool) { use Direction::*; let config = cx.editor.config(); let (view, doc) = current!(cx.editor); @@ -1628,7 +1632,7 @@ pub fn scroll(cx: &mut Context, offset: usize, direction: Direction) { let doc_text = doc.text().slice(..); let viewport = view.inner_area(doc); let text_fmt = doc.text_format(viewport.width, None); - let annotations = view.text_annotations(doc, None); + let mut annotations = view.text_annotations(doc, None); (view.offset.anchor, view.offset.vertical_offset) = char_idx_at_visual_offset( doc_text, view.offset.anchor, @@ -1638,6 +1642,30 @@ pub fn scroll(cx: &mut Context, offset: usize, direction: Direction) { &annotations, ); + if sync_cursor { + let movement = match cx.editor.mode { + Mode::Select => Movement::Extend, + _ => Movement::Move, + }; + // TODO: When inline diagnostics gets merged- 1. move_vertically_visual removes + // line annotations/diagnostics so the cursor may jump further than the view. + // 2. If the cursor lands on a complete line of virtual text, the cursor will + // jump a different distance than the view. + let selection = doc.selection(view.id).clone().transform(|range| { + move_vertically_visual( + doc_text, + range, + direction, + offset.unsigned_abs(), + movement, + &text_fmt, + &mut annotations, + ) + }); + doc.set_selection(view.id, selection); + return; + } + let mut head; match direction { Forward => { @@ -1688,25 +1716,49 @@ pub fn scroll(cx: &mut Context, offset: usize, direction: Direction) { fn page_up(cx: &mut Context) { let view = view!(cx.editor); let offset = view.inner_height(); - scroll(cx, offset, Direction::Backward); + scroll(cx, offset, Direction::Backward, false); } fn page_down(cx: &mut Context) { let view = view!(cx.editor); let offset = view.inner_height(); - scroll(cx, offset, Direction::Forward); + scroll(cx, offset, Direction::Forward, false); } fn half_page_up(cx: &mut Context) { let view = view!(cx.editor); let offset = view.inner_height() / 2; - scroll(cx, offset, Direction::Backward); + scroll(cx, offset, Direction::Backward, false); } fn half_page_down(cx: &mut Context) { let view = view!(cx.editor); let offset = view.inner_height() / 2; - scroll(cx, offset, Direction::Forward); + scroll(cx, offset, Direction::Forward, false); +} + +fn page_cursor_up(cx: &mut Context) { + let view = view!(cx.editor); + let offset = view.inner_height(); + scroll(cx, offset, Direction::Backward, true); +} + +fn page_cursor_down(cx: &mut Context) { + let view = view!(cx.editor); + let offset = view.inner_height(); + scroll(cx, offset, Direction::Forward, true); +} + +fn page_cursor_half_up(cx: &mut Context) { + let view = view!(cx.editor); + let offset = view.inner_height() / 2; + scroll(cx, offset, Direction::Backward, true); +} + +fn page_cursor_half_down(cx: &mut Context) { + let view = view!(cx.editor); + let offset = view.inner_height() / 2; + scroll(cx, offset, Direction::Forward, true); } #[allow(deprecated)] @@ -4856,11 +4908,11 @@ fn align_view_middle(cx: &mut Context) { } fn scroll_up(cx: &mut Context) { - scroll(cx, cx.count(), Direction::Backward); + scroll(cx, cx.count(), Direction::Backward, false); } fn scroll_down(cx: &mut Context) { - scroll(cx, cx.count(), Direction::Forward); + scroll(cx, cx.count(), Direction::Forward, false); } fn goto_ts_object_impl(cx: &mut Context, object: &'static str, direction: Direction) { diff --git a/helix-term/src/keymap/default.rs b/helix-term/src/keymap/default.rs index 763ed4ae7..92d6b5906 100644 --- a/helix-term/src/keymap/default.rs +++ b/helix-term/src/keymap/default.rs @@ -178,8 +178,8 @@ pub fn default() -> HashMap { "esc" => normal_mode, "C-b" | "pageup" => page_up, "C-f" | "pagedown" => page_down, - "C-u" => half_page_up, - "C-d" => half_page_down, + "C-u" => page_cursor_half_up, + "C-d" => page_cursor_half_down, "C-w" => { "Window" "C-w" | "w" => rotate_view, @@ -287,8 +287,8 @@ pub fn default() -> HashMap { "j" | "down" => scroll_down, "C-b" | "pageup" => page_up, "C-f" | "pagedown" => page_down, - "C-u" | "backspace" => half_page_up, - "C-d" | "space" => half_page_down, + "C-u" | "backspace" => page_cursor_half_up, + "C-d" | "space" => page_cursor_half_down, "/" => search, "?" => rsearch, @@ -304,8 +304,8 @@ pub fn default() -> HashMap { "j" | "down" => scroll_down, "C-b" | "pageup" => page_up, "C-f" | "pagedown" => page_down, - "C-u" | "backspace" => half_page_up, - "C-d" | "space" => half_page_down, + "C-u" | "backspace" => page_cursor_half_up, + "C-d" | "space" => page_cursor_half_down, "/" => search, "?" => rsearch, diff --git a/helix-term/src/ui/editor.rs b/helix-term/src/ui/editor.rs index bb749d2e7..a87e6cbca 100644 --- a/helix-term/src/ui/editor.rs +++ b/helix-term/src/ui/editor.rs @@ -1156,7 +1156,7 @@ fn handle_mouse_event( } let offset = config.scroll_lines.unsigned_abs(); - commands::scroll(cxt, offset, direction); + commands::scroll(cxt, offset, direction, false); cxt.editor.tree.focus = current_view; cxt.editor.ensure_cursor_in_view(current_view);