Detailed changes
@@ -97,8 +97,10 @@
"cmd-right": "editor::MoveToEndOfLine",
"ctrl-e": "editor::MoveToEndOfLine",
"end": "editor::MoveToEndOfLine",
- "cmd-up": "editor::MoveToBeginning",
- "cmd-down": "editor::MoveToEnd",
+ "cmd-up": "editor::MoveToStartOfExcerpt",
+ "cmd-down": "editor::MoveToEndOfExcerpt",
+ "cmd-home": "editor::MoveToBeginning", // Typed via `cmd-fn-left`
+ "cmd-end": "editor::MoveToEnd", // Typed via `cmd-fn-right`
"shift-up": "editor::SelectUp",
"ctrl-shift-p": "editor::SelectUp",
"shift-down": "editor::SelectDown",
@@ -111,8 +113,8 @@
"alt-shift-right": "editor::SelectToNextWordEnd", // cursorWordRightSelect
"ctrl-shift-up": "editor::SelectToStartOfParagraph",
"ctrl-shift-down": "editor::SelectToEndOfParagraph",
- "cmd-shift-up": "editor::SelectToBeginning",
- "cmd-shift-down": "editor::SelectToEnd",
+ "cmd-shift-up": "editor::SelectToStartOfExcerpt",
+ "cmd-shift-down": "editor::SelectToEndOfExcerpt",
"cmd-a": "editor::SelectAll",
"cmd-l": "editor::SelectLine",
"cmd-shift-i": "editor::Format",
@@ -329,6 +329,8 @@ gpui::actions!(
MoveToPreviousSubwordStart,
MoveToPreviousWordStart,
MoveToStartOfParagraph,
+ MoveToStartOfExcerpt,
+ MoveToEndOfExcerpt,
MoveUp,
Newline,
NewlineAbove,
@@ -364,6 +366,8 @@ gpui::actions!(
ScrollCursorTop,
SelectAll,
SelectAllMatches,
+ SelectToStartOfExcerpt,
+ SelectToEndOfExcerpt,
SelectDown,
SelectEnclosingSymbol,
SelectLargerSyntaxNode,
@@ -9033,6 +9033,98 @@ impl Editor {
})
}
+ pub fn move_to_start_of_excerpt(
+ &mut self,
+ _: &MoveToStartOfExcerpt,
+ window: &mut Window,
+ cx: &mut Context<Self>,
+ ) {
+ if matches!(self.mode, EditorMode::SingleLine { .. }) {
+ cx.propagate();
+ return;
+ }
+
+ self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
+ s.move_with(|map, selection| {
+ selection.collapse_to(
+ movement::start_of_excerpt(
+ map,
+ selection.head(),
+ workspace::searchable::Direction::Prev,
+ ),
+ SelectionGoal::None,
+ )
+ });
+ })
+ }
+
+ pub fn move_to_end_of_excerpt(
+ &mut self,
+ _: &MoveToEndOfExcerpt,
+ window: &mut Window,
+ cx: &mut Context<Self>,
+ ) {
+ if matches!(self.mode, EditorMode::SingleLine { .. }) {
+ cx.propagate();
+ return;
+ }
+
+ self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
+ s.move_with(|map, selection| {
+ selection.collapse_to(
+ movement::end_of_excerpt(
+ map,
+ selection.head(),
+ workspace::searchable::Direction::Next,
+ ),
+ SelectionGoal::None,
+ )
+ });
+ })
+ }
+
+ pub fn select_to_start_of_excerpt(
+ &mut self,
+ _: &SelectToStartOfExcerpt,
+ window: &mut Window,
+ cx: &mut Context<Self>,
+ ) {
+ if matches!(self.mode, EditorMode::SingleLine { .. }) {
+ cx.propagate();
+ return;
+ }
+
+ self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
+ s.move_heads_with(|map, head, _| {
+ (
+ movement::start_of_excerpt(map, head, workspace::searchable::Direction::Prev),
+ SelectionGoal::None,
+ )
+ });
+ })
+ }
+
+ pub fn select_to_end_of_excerpt(
+ &mut self,
+ _: &SelectToEndOfExcerpt,
+ window: &mut Window,
+ cx: &mut Context<Self>,
+ ) {
+ if matches!(self.mode, EditorMode::SingleLine { .. }) {
+ cx.propagate();
+ return;
+ }
+
+ self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
+ s.move_heads_with(|map, head, _| {
+ (
+ movement::end_of_excerpt(map, head, workspace::searchable::Direction::Next),
+ SelectionGoal::None,
+ )
+ });
+ })
+ }
+
pub fn move_to_beginning(
&mut self,
_: &MoveToBeginning,
@@ -290,6 +290,8 @@ impl EditorElement {
register_action(editor, window, Editor::move_to_end_of_paragraph);
register_action(editor, window, Editor::move_to_beginning);
register_action(editor, window, Editor::move_to_end);
+ register_action(editor, window, Editor::move_to_start_of_excerpt);
+ register_action(editor, window, Editor::move_to_end_of_excerpt);
register_action(editor, window, Editor::select_up);
register_action(editor, window, Editor::select_down);
register_action(editor, window, Editor::select_left);
@@ -302,6 +304,8 @@ impl EditorElement {
register_action(editor, window, Editor::select_to_end_of_line);
register_action(editor, window, Editor::select_to_start_of_paragraph);
register_action(editor, window, Editor::select_to_end_of_paragraph);
+ register_action(editor, window, Editor::select_to_start_of_excerpt);
+ register_action(editor, window, Editor::select_to_end_of_excerpt);
register_action(editor, window, Editor::select_to_beginning);
register_action(editor, window, Editor::select_to_end);
register_action(editor, window, Editor::select_all);
@@ -7,6 +7,7 @@ use gpui::{Pixels, WindowTextSystem};
use language::Point;
use multi_buffer::{MultiBufferRow, MultiBufferSnapshot};
use serde::Deserialize;
+use workspace::searchable::Direction;
use std::{ops::Range, sync::Arc};
@@ -403,6 +404,69 @@ pub fn end_of_paragraph(
map.max_point()
}
+pub fn start_of_excerpt(
+ map: &DisplaySnapshot,
+ display_point: DisplayPoint,
+ direction: Direction,
+) -> DisplayPoint {
+ let point = map.display_point_to_point(display_point, Bias::Left);
+ let Some(excerpt) = map.buffer_snapshot.excerpt_containing(point..point) else {
+ return display_point;
+ };
+ match direction {
+ Direction::Prev => {
+ let mut start = excerpt.start_anchor().to_display_point(&map);
+ if start >= display_point && start.row() > DisplayRow(0) {
+ let Some(excerpt) = map.buffer_snapshot.excerpt_before(excerpt.id()) else {
+ return display_point;
+ };
+ start = excerpt.start_anchor().to_display_point(&map);
+ }
+ start
+ }
+ Direction::Next => {
+ let mut end = excerpt.end_anchor().to_display_point(&map);
+ *end.row_mut() += 1;
+ map.clip_point(end, Bias::Right)
+ }
+ }
+}
+
+pub fn end_of_excerpt(
+ map: &DisplaySnapshot,
+ display_point: DisplayPoint,
+ direction: Direction,
+) -> DisplayPoint {
+ let point = map.display_point_to_point(display_point, Bias::Left);
+ let Some(excerpt) = map.buffer_snapshot.excerpt_containing(point..point) else {
+ return display_point;
+ };
+ match direction {
+ Direction::Prev => {
+ let mut start = excerpt.start_anchor().to_display_point(&map);
+ if start.row() > DisplayRow(0) {
+ *start.row_mut() -= 1;
+ }
+ map.clip_point(start, Bias::Left)
+ }
+ Direction::Next => {
+ let mut end = excerpt.end_anchor().to_display_point(&map);
+ *end.column_mut() = 0;
+ if end <= display_point {
+ *end.row_mut() += 1;
+ let point_end = map.display_point_to_point(end, Bias::Right);
+ let Some(excerpt) = map.buffer_snapshot.excerpt_containing(point_end..point_end)
+ else {
+ return display_point;
+ };
+ end = excerpt.end_anchor().to_display_point(&map);
+ *end.column_mut() = 0;
+ }
+ end
+ }
+ }
+}
+
/// Scans for a boundary preceding the given start point `from` until a boundary is found,
/// indicated by the given predicate returning true.
/// The predicate is called with the character to the left and right of the candidate boundary location.
@@ -2699,49 +2699,10 @@ fn section_motion(
};
for _ in 0..times {
- let point = map.display_point_to_point(display_point, Bias::Left);
- let Some(excerpt) = map.buffer_snapshot.excerpt_containing(point..point) else {
- return display_point;
- };
- let next_point = match (direction, is_start) {
- (Direction::Prev, true) => {
- let mut start = excerpt.start_anchor().to_display_point(&map);
- if start >= display_point && start.row() > DisplayRow(0) {
- let Some(excerpt) = map.buffer_snapshot.excerpt_before(excerpt.id()) else {
- return display_point;
- };
- start = excerpt.start_anchor().to_display_point(&map);
- }
- start
- }
- (Direction::Prev, false) => {
- let mut start = excerpt.start_anchor().to_display_point(&map);
- if start.row() > DisplayRow(0) {
- *start.row_mut() -= 1;
- }
- map.clip_point(start, Bias::Left)
- }
- (Direction::Next, true) => {
- let mut end = excerpt.end_anchor().to_display_point(&map);
- *end.row_mut() += 1;
- map.clip_point(end, Bias::Right)
- }
- (Direction::Next, false) => {
- let mut end = excerpt.end_anchor().to_display_point(&map);
- *end.column_mut() = 0;
- if end <= display_point {
- *end.row_mut() += 1;
- let point_end = map.display_point_to_point(end, Bias::Right);
- let Some(excerpt) =
- map.buffer_snapshot.excerpt_containing(point_end..point_end)
- else {
- return display_point;
- };
- end = excerpt.end_anchor().to_display_point(&map);
- *end.column_mut() = 0;
- }
- end
- }
+ let next_point = if is_start {
+ movement::start_of_excerpt(map, display_point, direction)
+ } else {
+ movement::end_of_excerpt(map, display_point, direction)
};
if next_point == display_point {
break;