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",
"tab": "editor::Tab",
"shift-tab": "editor::TabPrev",
"ctrl-k": "editor::CutToEndOfLine",
"ctrl-t": "editor::Transpose",
"ctrl-k": "editor::KillRingCut",
"ctrl-y": "editor::KillRingYank",
"cmd-k q": "editor::Rewrap",
"cmd-k cmd-q": "editor::Rewrap",
"cmd-backspace": "editor::DeleteToBeginningOfLine",

View file

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

View file

@ -74,7 +74,7 @@ use gpui::{
div, impl_actions, point, prelude::*, px, relative, size, uniform_list, Action, AnyElement,
AppContext, AsyncWindowContext, AvailableSpace, BackgroundExecutor, Bounds, ClipboardEntry,
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,
ScrollStrategy, SharedString, Size, StrikethroughStyle, Styled, StyledText, Subscription, Task,
TextStyle, TextStyleRefinement, UTF16Selection, UnderlineStyle, UniformListScrollHandle, View,
@ -7364,7 +7364,7 @@ impl Editor {
.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 buffer = self.buffer.read(cx).snapshot(cx);
let mut selections = self.selections.all::<Point>(cx);
@ -7408,11 +7408,38 @@ impl Editor {
s.select(selections);
});
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>) {
@ -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);

View file

@ -217,6 +217,8 @@ impl EditorElement {
register_action(view, cx, Editor::transpose);
register_action(view, cx, Editor::rewrap);
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::paste);
register_action(view, cx, Editor::undo);