@@ -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,
]
);
@@ -5379,6 +5379,86 @@ impl Editor {
})
}
+ pub fn move_up_by_lines(&mut self, action: &MoveUpByLines, cx: &mut ViewContext<Self>) {
+ 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<Self>) {
+ 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<Self>) {
+ 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<Self>) {
+ 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<Self>) {
if self.take_rename(true, cx).is_some() {
return;
@@ -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);