Add emacs mark mode (#23297)

Updates #21927
Replaces https://github.com/zed-industries/zed/pull/22904
Closes #8580

Adds actions (default keybinds with emacs keymap):
- editor::SetMark (`ctrl-space` and `ctrl-@`)
- editor::ExchangeMark (`ctrl-x ctrl-x`)

Co-Authored-By: Peter <peter@zed.dev>

Release Notes:

- Add Emacs mark mode (`ctrl-space` / `ctrl-@` to set mark; `ctrl-x
ctrl-x` to swap mark/cursor)
- Breaking change: `selection` keyboard context has been replaced with
`selection_mode`

---------

Co-authored-by: Peter <peter@zed.dev>
This commit is contained in:
Conrad Irwin 2025-01-21 08:18:25 -07:00 committed by GitHub
parent c4542ca731
commit 94189e1784
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
5 changed files with 98 additions and 10 deletions

View file

@ -377,6 +377,8 @@ gpui::actions!(
ToggleInlayHints,
ToggleInlineCompletions,
ToggleLineNumbers,
ExchangeMark,
SetMark,
ToggleRelativeLineNumbers,
ToggleSelectionMenu,
ToggleSoftWrap,

View file

@ -706,6 +706,7 @@ pub struct Editor {
next_scroll_position: NextScrollCursorCenterTopBottom,
addons: HashMap<TypeId, Box<dyn Addon>>,
registered_buffers: HashMap<BufferId, OpenLspBufferHandle>,
selection_mark_mode: bool,
toggle_fold_multiple_buffers: Task<()>,
_scroll_cursor_center_top_bottom_task: Task<()>,
}
@ -1364,6 +1365,7 @@ impl Editor {
addons: HashMap::default(),
registered_buffers: HashMap::default(),
_scroll_cursor_center_top_bottom_task: Task::ready(()),
selection_mark_mode: false,
toggle_fold_multiple_buffers: Task::ready(()),
text_style_refinement: None,
};
@ -1456,13 +1458,8 @@ impl Editor {
key_context.add("inline_completion");
}
if !self
.selections
.disjoint
.iter()
.all(|selection| selection.start == selection.end)
{
key_context.add("selection");
if self.selection_mark_mode {
key_context.add("selection_mode");
}
key_context
@ -2477,6 +2474,8 @@ impl Editor {
}
pub fn cancel(&mut self, _: &Cancel, cx: &mut ViewContext<Self>) {
self.selection_mark_mode = false;
if self.clear_expanded_diff_hunks(cx) {
cx.notify();
return;
@ -10622,6 +10621,32 @@ impl Editor {
}
}
pub fn set_mark(&mut self, _: &actions::SetMark, cx: &mut ViewContext<Self>) {
if self.selection_mark_mode {
self.change_selections(None, cx, |s| {
s.move_with(|_, sel| {
sel.collapse_to(sel.head(), SelectionGoal::None);
});
})
}
self.selection_mark_mode = true;
cx.notify();
}
pub fn exchange_mark(&mut self, _: &actions::ExchangeMark, cx: &mut ViewContext<Self>) {
if self.selection_mark_mode {
self.change_selections(None, cx, |s| {
s.move_with(|_, sel| {
if sel.start != sel.end {
sel.reversed = !sel.reversed
}
});
})
}
self.selection_mark_mode = true;
cx.notify();
}
pub fn toggle_fold(&mut self, _: &actions::ToggleFold, cx: &mut ViewContext<Self>) {
if self.is_singleton(cx) {
let selection = self.selections.newest::<Point>(cx);
@ -15234,7 +15259,6 @@ fn check_multiline_range(buffer: &Buffer, range: Range<usize>) -> Range<usize> {
range.start..range.start
}
}
pub struct KillRing(ClipboardItem);
impl Global for KillRing {}

View file

@ -356,6 +356,8 @@ impl EditorElement {
register_action(view, cx, Editor::unfold_all);
register_action(view, cx, Editor::unfold_at);
register_action(view, cx, Editor::fold_selected_ranges);
register_action(view, cx, Editor::set_mark);
register_action(view, cx, Editor::exchange_mark);
register_action(view, cx, Editor::show_completions);
register_action(view, cx, Editor::toggle_code_actions);
register_action(view, cx, Editor::open_excerpts);