From 11bd28870aa41876eea178e9d65ffd3df1f0ad6d Mon Sep 17 00:00:00 2001 From: Thorsten Ball Date: Fri, 2 Feb 2024 16:48:04 +0100 Subject: [PATCH] editor: Add MoveUpByLines and MoveDownByLines actions (#7208) This adds four new actions: - `editor::MoveUpByLines` - `editor::MoveDownByLines` - `editor::SelectUpByLines` - `editor::SelectDownByLines` They all take a count by which to move the cursor up and down. (Requested by Adam here: https://twitter.com/adamwathan/status/1753017094248018302) Example `keymap.json` entries: ```json { "context": "Editor", "bindings": [ "alt-up": [ "editor::MoveUpByLines", { "lines": 3 } ], "alt-down": [ "editor::MoveDownByLines", { "lines": 3 } ], "alt-shift-up": [ "editor::SelectUpByLines", { "lines": 3 } ], "alt-shift-down": [ "editor::SelectDownByLines", { "lines": 3 } ] ] } ``` They are *not* bound by default, so as to not conflict with the `alt-up/down` bindings that already exist. Release Notes: - Added four new actions: `editor::MoveUpByLines`, `editor::MoveDownByLines`, `editor::SelectUpByLines`, `editor::SelectDownByLines` that can take a line count configuration and move the cursor up by the count. ### Demo https://github.com/zed-industries/zed/assets/1185253/e78d4077-5bd5-4d72-a806-67695698af5d https://github.com/zed-industries/zed/assets/1185253/0b086ec9-eb90-40a2-9009-844a215e6378 --- crates/editor/src/actions.rs | 30 +++++++++++++- crates/editor/src/editor.rs | 80 ++++++++++++++++++++++++++++++++++++ crates/editor/src/element.rs | 4 ++ 3 files changed, 113 insertions(+), 1 deletion(-) diff --git a/crates/editor/src/actions.rs b/crates/editor/src/actions.rs index dd3735c6a9..049c152e2c 100644 --- a/crates/editor/src/actions.rs +++ b/crates/editor/src/actions.rs @@ -70,6 +70,30 @@ pub struct FoldAt { pub struct UnfoldAt { pub buffer_row: u32, } + +#[derive(PartialEq, Clone, Deserialize, Default)] +pub struct MoveUpByLines { + #[serde(default)] + pub(super) lines: u32, +} + +#[derive(PartialEq, Clone, Deserialize, Default)] +pub struct MoveDownByLines { + #[serde(default)] + pub(super) lines: u32, +} +#[derive(PartialEq, Clone, Deserialize, Default)] +pub struct SelectUpByLines { + #[serde(default)] + pub(super) lines: u32, +} + +#[derive(PartialEq, Clone, Deserialize, Default)] +pub struct SelectDownByLines { + #[serde(default)] + pub(super) lines: u32, +} + impl_actions!( editor, [ @@ -84,7 +108,11 @@ impl_actions!( ConfirmCodeAction, ToggleComments, FoldAt, - UnfoldAt + UnfoldAt, + MoveUpByLines, + MoveDownByLines, + SelectUpByLines, + SelectDownByLines, ] ); diff --git a/crates/editor/src/editor.rs b/crates/editor/src/editor.rs index b244ba6d12..21092ca085 100644 --- a/crates/editor/src/editor.rs +++ b/crates/editor/src/editor.rs @@ -5379,6 +5379,86 @@ impl Editor { }) } + pub fn move_up_by_lines(&mut self, action: &MoveUpByLines, cx: &mut ViewContext) { + if self.take_rename(true, cx).is_some() { + return; + } + + if matches!(self.mode, EditorMode::SingleLine) { + cx.propagate(); + return; + } + + let text_layout_details = &self.text_layout_details(cx); + + self.change_selections(Some(Autoscroll::fit()), cx, |s| { + let line_mode = s.line_mode; + s.move_with(|map, selection| { + if !selection.is_empty() && !line_mode { + selection.goal = SelectionGoal::None; + } + let (cursor, goal) = movement::up_by_rows( + map, + selection.start, + action.lines, + selection.goal, + false, + &text_layout_details, + ); + selection.collapse_to(cursor, goal); + }); + }) + } + + pub fn move_down_by_lines(&mut self, action: &MoveDownByLines, cx: &mut ViewContext) { + if self.take_rename(true, cx).is_some() { + return; + } + + if matches!(self.mode, EditorMode::SingleLine) { + cx.propagate(); + return; + } + + let text_layout_details = &self.text_layout_details(cx); + + self.change_selections(Some(Autoscroll::fit()), cx, |s| { + let line_mode = s.line_mode; + s.move_with(|map, selection| { + if !selection.is_empty() && !line_mode { + selection.goal = SelectionGoal::None; + } + let (cursor, goal) = movement::down_by_rows( + map, + selection.start, + action.lines, + selection.goal, + false, + &text_layout_details, + ); + selection.collapse_to(cursor, goal); + }); + }) + } + + pub fn select_down_by_lines(&mut self, action: &SelectDownByLines, cx: &mut ViewContext) { + let text_layout_details = &self.text_layout_details(cx); + self.change_selections(Some(Autoscroll::fit()), cx, |s| { + s.move_heads_with(|map, head, goal| { + movement::down_by_rows(map, head, action.lines, goal, false, &text_layout_details) + }) + }) + } + + pub fn select_up_by_lines(&mut self, action: &SelectUpByLines, cx: &mut ViewContext) { + let text_layout_details = &self.text_layout_details(cx); + self.change_selections(Some(Autoscroll::fit()), cx, |s| { + s.move_heads_with(|map, head, goal| { + movement::up_by_rows(map, head, action.lines, goal, false, &text_layout_details) + }) + }) + } + pub fn move_page_up(&mut self, action: &MovePageUp, cx: &mut ViewContext) { if self.take_rename(true, cx).is_some() { return; diff --git a/crates/editor/src/element.rs b/crates/editor/src/element.rs index b96ec9e068..7e546cc272 100644 --- a/crates/editor/src/element.rs +++ b/crates/editor/src/element.rs @@ -147,7 +147,11 @@ impl EditorElement { register_action(view, cx, Editor::move_left); register_action(view, cx, Editor::move_right); register_action(view, cx, Editor::move_down); + register_action(view, cx, Editor::move_down_by_lines); + register_action(view, cx, Editor::select_down_by_lines); register_action(view, cx, Editor::move_up); + register_action(view, cx, Editor::move_up_by_lines); + register_action(view, cx, Editor::select_up_by_lines); register_action(view, cx, Editor::cancel); register_action(view, cx, Editor::newline); register_action(view, cx, Editor::newline_above);