Implement readline/emacs/macos style ctrl-k cut and ctrl-y yank (#21003)

- Added support for ctrl-k / ctrl-y alternate cut/yank buffer on macos.

Co-authored-by: Conrad Irwin <conrad@zed.dev>
This commit is contained in:
Peter Tripp 2024-11-21 18:10:25 +00:00 committed by GitHub
parent 571c7d4f66
commit 268ac4c047
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
4 changed files with 42 additions and 7 deletions

View file

@ -49,8 +49,9 @@
"ctrl-d": "editor::Delete", "ctrl-d": "editor::Delete",
"tab": "editor::Tab", "tab": "editor::Tab",
"shift-tab": "editor::TabPrev", "shift-tab": "editor::TabPrev",
"ctrl-k": "editor::CutToEndOfLine",
"ctrl-t": "editor::Transpose", "ctrl-t": "editor::Transpose",
"ctrl-k": "editor::KillRingCut",
"ctrl-y": "editor::KillRingYank",
"cmd-k q": "editor::Rewrap", "cmd-k q": "editor::Rewrap",
"cmd-k cmd-q": "editor::Rewrap", "cmd-k cmd-q": "editor::Rewrap",
"cmd-backspace": "editor::DeleteToBeginningOfLine", "cmd-backspace": "editor::DeleteToBeginningOfLine",

View file

@ -271,6 +271,8 @@ gpui::actions!(
Hover, Hover,
Indent, Indent,
JoinLines, JoinLines,
KillRingCut,
KillRingYank,
LineDown, LineDown,
LineUp, LineUp,
MoveDown, MoveDown,

View file

@ -74,7 +74,7 @@ use gpui::{
div, impl_actions, point, prelude::*, px, relative, size, uniform_list, Action, AnyElement, div, impl_actions, point, prelude::*, px, relative, size, uniform_list, Action, AnyElement,
AppContext, AsyncWindowContext, AvailableSpace, BackgroundExecutor, Bounds, ClipboardEntry, AppContext, AsyncWindowContext, AvailableSpace, BackgroundExecutor, Bounds, ClipboardEntry,
ClipboardItem, Context, DispatchPhase, ElementId, EventEmitter, FocusHandle, FocusOutEvent, ClipboardItem, Context, DispatchPhase, ElementId, EventEmitter, FocusHandle, FocusOutEvent,
FocusableView, FontId, FontWeight, HighlightStyle, Hsla, InteractiveText, KeyContext, FocusableView, FontId, FontWeight, Global, HighlightStyle, Hsla, InteractiveText, KeyContext,
ListSizingBehavior, Model, ModelContext, MouseButton, PaintQuad, ParentElement, Pixels, Render, ListSizingBehavior, Model, ModelContext, MouseButton, PaintQuad, ParentElement, Pixels, Render,
ScrollStrategy, SharedString, Size, StrikethroughStyle, Styled, StyledText, Subscription, Task, ScrollStrategy, SharedString, Size, StrikethroughStyle, Styled, StyledText, Subscription, Task,
TextStyle, TextStyleRefinement, UTF16Selection, UnderlineStyle, UniformListScrollHandle, View, TextStyle, TextStyleRefinement, UTF16Selection, UnderlineStyle, UniformListScrollHandle, View,
@ -7364,7 +7364,7 @@ impl Editor {
.update(cx, |buffer, cx| buffer.edit(edits, None, cx)); .update(cx, |buffer, cx| buffer.edit(edits, None, cx));
} }
pub fn cut(&mut self, _: &Cut, cx: &mut ViewContext<Self>) { pub fn cut_common(&mut self, cx: &mut ViewContext<Self>) -> ClipboardItem {
let mut text = String::new(); let mut text = String::new();
let buffer = self.buffer.read(cx).snapshot(cx); let buffer = self.buffer.read(cx).snapshot(cx);
let mut selections = self.selections.all::<Point>(cx); let mut selections = self.selections.all::<Point>(cx);
@ -7408,11 +7408,38 @@ impl Editor {
s.select(selections); s.select(selections);
}); });
this.insert("", cx); this.insert("", cx);
cx.write_to_clipboard(ClipboardItem::new_string_with_json_metadata(
text,
clipboard_selections,
));
}); });
ClipboardItem::new_string_with_json_metadata(text, clipboard_selections)
}
pub fn cut(&mut self, _: &Cut, cx: &mut ViewContext<Self>) {
let item = self.cut_common(cx);
cx.write_to_clipboard(item);
}
pub fn kill_ring_cut(&mut self, _: &KillRingCut, cx: &mut ViewContext<Self>) {
self.change_selections(None, cx, |s| {
s.move_with(|snapshot, sel| {
if sel.is_empty() {
sel.end = DisplayPoint::new(sel.end.row(), snapshot.line_len(sel.end.row()))
}
});
});
let item = self.cut_common(cx);
cx.set_global(KillRing(item))
}
pub fn kill_ring_yank(&mut self, _: &KillRingYank, cx: &mut ViewContext<Self>) {
let (text, metadata) = if let Some(KillRing(item)) = cx.try_global() {
if let Some(ClipboardEntry::String(kill_ring)) = item.entries().first() {
(kill_ring.text().to_string(), kill_ring.metadata_json())
} else {
return;
}
} else {
return;
};
self.do_paste(&text, metadata, false, cx);
} }
pub fn copy(&mut self, _: &Copy, cx: &mut ViewContext<Self>) { pub fn copy(&mut self, _: &Copy, cx: &mut ViewContext<Self>) {
@ -15145,4 +15172,7 @@ fn check_multiline_range(buffer: &Buffer, range: Range<usize>) -> Range<usize> {
} }
} }
pub struct KillRing(ClipboardItem);
impl Global for KillRing {}
const UPDATE_DEBOUNCE: Duration = Duration::from_millis(50); const UPDATE_DEBOUNCE: Duration = Duration::from_millis(50);

View file

@ -217,6 +217,8 @@ impl EditorElement {
register_action(view, cx, Editor::transpose); register_action(view, cx, Editor::transpose);
register_action(view, cx, Editor::rewrap); register_action(view, cx, Editor::rewrap);
register_action(view, cx, Editor::cut); register_action(view, cx, Editor::cut);
register_action(view, cx, Editor::kill_ring_cut);
register_action(view, cx, Editor::kill_ring_yank);
register_action(view, cx, Editor::copy); register_action(view, cx, Editor::copy);
register_action(view, cx, Editor::paste); register_action(view, cx, Editor::paste);
register_action(view, cx, Editor::undo); register_action(view, cx, Editor::undo);