Fixes to excerpt movement actions and bindings + add multibuffer and singleton_buffer key contexts (#26264)

Closes #26002 

Release Notes:

- Added `multibuffer` key context.
- `cmd-down` and `cmd-shift-down` on Mac now moves to the end of the
last line of a singleton buffer instead of the beginning. In
multibuffers, these now move to the start of the next excerpt.
- Fixed `vim::PreviousSectionEnd` (bound to `[ ]`) to move to the
beginning of the line, matching the behavior of `vim::NextSectionEnd`.
- Added `editor::MoveToStartOfNextExcerpt` and
`editor::MoveToEndOfPreviousExcerpt`.
This commit is contained in:
Michael Sloan 2025-03-07 17:58:47 -07:00 committed by GitHub
parent 60b3eb3f76
commit 450d727a04
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
5 changed files with 127 additions and 12 deletions

View file

@ -108,8 +108,8 @@
"cmd-right": ["editor::MoveToEndOfLine", { "stop_at_soft_wraps": true }], "cmd-right": ["editor::MoveToEndOfLine", { "stop_at_soft_wraps": true }],
"ctrl-e": ["editor::MoveToEndOfLine", { "stop_at_soft_wraps": false }], "ctrl-e": ["editor::MoveToEndOfLine", { "stop_at_soft_wraps": false }],
"end": ["editor::MoveToEndOfLine", { "stop_at_soft_wraps": true }], "end": ["editor::MoveToEndOfLine", { "stop_at_soft_wraps": true }],
"cmd-up": "editor::MoveToStartOfExcerpt", "cmd-up": "editor::MoveToBeginning",
"cmd-down": "editor::MoveToEndOfExcerpt", "cmd-down": "editor::MoveToEnd",
"cmd-home": "editor::MoveToBeginning", // Typed via `cmd-fn-left` "cmd-home": "editor::MoveToBeginning", // Typed via `cmd-fn-left`
"cmd-end": "editor::MoveToEnd", // Typed via `cmd-fn-right` "cmd-end": "editor::MoveToEnd", // Typed via `cmd-fn-right`
"shift-up": "editor::SelectUp", "shift-up": "editor::SelectUp",
@ -124,8 +124,8 @@
"alt-shift-right": "editor::SelectToNextWordEnd", // cursorWordRightSelect "alt-shift-right": "editor::SelectToNextWordEnd", // cursorWordRightSelect
"ctrl-shift-up": "editor::SelectToStartOfParagraph", "ctrl-shift-up": "editor::SelectToStartOfParagraph",
"ctrl-shift-down": "editor::SelectToEndOfParagraph", "ctrl-shift-down": "editor::SelectToEndOfParagraph",
"cmd-shift-up": "editor::SelectToStartOfExcerpt", "cmd-shift-up": "editor::SelectToBeginning",
"cmd-shift-down": "editor::SelectToEndOfExcerpt", "cmd-shift-down": "editor::SelectToEnd",
"cmd-a": "editor::SelectAll", "cmd-a": "editor::SelectAll",
"cmd-l": "editor::SelectLine", "cmd-l": "editor::SelectLine",
"cmd-shift-i": "editor::Format", "cmd-shift-i": "editor::Format",
@ -172,6 +172,16 @@
"alt-enter": "editor::OpenSelectionsInMultibuffer" "alt-enter": "editor::OpenSelectionsInMultibuffer"
} }
}, },
{
"context": "Editor && multibuffer",
"use_key_equivalents": true,
"bindings": {
"cmd-up": "editor::MoveToStartOfExcerpt",
"cmd-down": "editor::MoveToStartOfNextExcerpt",
"cmd-shift-up": "editor::SelectToStartOfExcerpt",
"cmd-shift-down": "editor::SelectToStartOfNextExcerpt"
}
},
{ {
"context": "Editor && mode == full && edit_prediction", "context": "Editor && mode == full && edit_prediction",
"use_key_equivalents": true, "use_key_equivalents": true,

View file

@ -340,7 +340,9 @@ gpui::actions!(
MoveToPreviousWordStart, MoveToPreviousWordStart,
MoveToStartOfParagraph, MoveToStartOfParagraph,
MoveToStartOfExcerpt, MoveToStartOfExcerpt,
MoveToStartOfNextExcerpt,
MoveToEndOfExcerpt, MoveToEndOfExcerpt,
MoveToEndOfPreviousExcerpt,
MoveUp, MoveUp,
Newline, Newline,
NewlineAbove, NewlineAbove,
@ -378,7 +380,9 @@ gpui::actions!(
SelectAll, SelectAll,
SelectAllMatches, SelectAllMatches,
SelectToStartOfExcerpt, SelectToStartOfExcerpt,
SelectToStartOfNextExcerpt,
SelectToEndOfExcerpt, SelectToEndOfExcerpt,
SelectToEndOfPreviousExcerpt,
SelectDown, SelectDown,
SelectEnclosingSymbol, SelectEnclosingSymbol,
SelectLargerSyntaxNode, SelectLargerSyntaxNode,

View file

@ -1573,13 +1573,16 @@ impl Editor {
} }
} }
if let Some(extension) = self if let Some(singleton_buffer) = self.buffer.read(cx).as_singleton() {
.buffer if let Some(extension) = singleton_buffer
.read(cx) .read(cx)
.as_singleton() .file()
.and_then(|buffer| buffer.read(cx).file()?.path().extension()?.to_str()) .and_then(|file| file.path().extension()?.to_str())
{ {
key_context.set("extension", extension.to_string()); key_context.set("extension", extension.to_string());
}
} else {
key_context.add("multibuffer");
} }
if has_active_edit_prediction { if has_active_edit_prediction {
@ -9845,6 +9848,31 @@ impl Editor {
}) })
} }
pub fn move_to_start_of_next_excerpt(
&mut self,
_: &MoveToStartOfNextExcerpt,
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::Next,
),
SelectionGoal::None,
)
});
})
}
pub fn move_to_end_of_excerpt( pub fn move_to_end_of_excerpt(
&mut self, &mut self,
_: &MoveToEndOfExcerpt, _: &MoveToEndOfExcerpt,
@ -9870,6 +9898,31 @@ impl Editor {
}) })
} }
pub fn move_to_end_of_previous_excerpt(
&mut self,
_: &MoveToEndOfPreviousExcerpt,
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::Prev,
),
SelectionGoal::None,
)
});
})
}
pub fn select_to_start_of_excerpt( pub fn select_to_start_of_excerpt(
&mut self, &mut self,
_: &SelectToStartOfExcerpt, _: &SelectToStartOfExcerpt,
@ -9891,6 +9944,27 @@ impl Editor {
}) })
} }
pub fn select_to_start_of_next_excerpt(
&mut self,
_: &SelectToStartOfNextExcerpt,
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::Next),
SelectionGoal::None,
)
});
})
}
pub fn select_to_end_of_excerpt( pub fn select_to_end_of_excerpt(
&mut self, &mut self,
_: &SelectToEndOfExcerpt, _: &SelectToEndOfExcerpt,
@ -9912,6 +9986,27 @@ impl Editor {
}) })
} }
pub fn select_to_end_of_previous_excerpt(
&mut self,
_: &SelectToEndOfPreviousExcerpt,
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::Prev),
SelectionGoal::None,
)
});
})
}
pub fn move_to_beginning( pub fn move_to_beginning(
&mut self, &mut self,
_: &MoveToBeginning, _: &MoveToBeginning,

View file

@ -282,7 +282,9 @@ impl EditorElement {
register_action(editor, window, Editor::move_to_beginning); register_action(editor, window, Editor::move_to_beginning);
register_action(editor, window, Editor::move_to_end); 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_start_of_excerpt);
register_action(editor, window, Editor::move_to_start_of_next_excerpt);
register_action(editor, window, Editor::move_to_end_of_excerpt); register_action(editor, window, Editor::move_to_end_of_excerpt);
register_action(editor, window, Editor::move_to_end_of_previous_excerpt);
register_action(editor, window, Editor::select_up); register_action(editor, window, Editor::select_up);
register_action(editor, window, Editor::select_down); register_action(editor, window, Editor::select_down);
register_action(editor, window, Editor::select_left); register_action(editor, window, Editor::select_left);
@ -296,7 +298,9 @@ impl EditorElement {
register_action(editor, window, Editor::select_to_start_of_paragraph); 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_end_of_paragraph);
register_action(editor, window, Editor::select_to_start_of_excerpt); register_action(editor, window, Editor::select_to_start_of_excerpt);
register_action(editor, window, Editor::select_to_start_of_next_excerpt);
register_action(editor, window, Editor::select_to_end_of_excerpt); register_action(editor, window, Editor::select_to_end_of_excerpt);
register_action(editor, window, Editor::select_to_end_of_previous_excerpt);
register_action(editor, window, Editor::select_to_beginning); register_action(editor, window, Editor::select_to_beginning);
register_action(editor, window, Editor::select_to_end); register_action(editor, window, Editor::select_to_end);
register_action(editor, window, Editor::select_all); register_action(editor, window, Editor::select_all);

View file

@ -448,7 +448,9 @@ pub fn end_of_excerpt(
if start.row() > DisplayRow(0) { if start.row() > DisplayRow(0) {
*start.row_mut() -= 1; *start.row_mut() -= 1;
} }
map.clip_point(start, Bias::Left) start = map.clip_point(start, Bias::Left);
*start.column_mut() = 0;
start
} }
Direction::Next => { Direction::Next => {
let mut end = excerpt.end_anchor().to_display_point(&map); let mut end = excerpt.end_anchor().to_display_point(&map);