diff --git a/locales/en.yml b/locales/en.yml index c7f71bd..eaabd81 100644 --- a/locales/en.yml +++ b/locales/en.yml @@ -117,7 +117,9 @@ software_builtin: "Built-in" retry: "Retry" right_click_copy_paste: "Right-click Copy/Paste" keyword_highlight: "Terminal Keyword Highlighting" -copy_paste_hint: "Regardless of this switch, you can always use %{key} + C/V to copy/paste." +copy_paste_hint: "Selected text can also be copied by left-clicking." +settings_copy: "Copy Selection" +settings_paste: "Paste Clipboard" edit_file: "Edit File" edit_file_tooltip: "Download to temporary directory, open in default editor, and auto upload on save." auto_saved_and_uploaded: "Auto-saved & uploaded: %{base}" diff --git a/locales/zh-CN.yml b/locales/zh-CN.yml index 65c50e6..a0b6de7 100644 --- a/locales/zh-CN.yml +++ b/locales/zh-CN.yml @@ -118,7 +118,9 @@ software_builtin: "软件内置" retry: "重试" right_click_copy_paste: "右键复制/粘贴" keyword_highlight: "终端关键词高亮" -copy_paste_hint: "不管是否开启此开关,都可以使用 %{key} + C/V 快捷键进行复制和粘贴。" +copy_paste_hint: "选中后左键点击也可复制。" +settings_copy: "复制选区" +settings_paste: "粘贴剪贴板" edit_file: "编辑文件" edit_file_tooltip: "下载到临时目录,使用默认编辑器打开,并在保存后自动上传。" auto_saved_and_uploaded: "已自动保存并上传: %{base}" diff --git a/src/app/dialogs.rs b/src/app/dialogs.rs index 44b20a3..94bc48c 100644 --- a/src/app/dialogs.rs +++ b/src/app/dialogs.rs @@ -1594,7 +1594,7 @@ impl Ashell { .into_any_element() } }) - ).description(t!("copy_paste_hint", key = if cfg!(target_os = "macos") { "Command" } else { "Ctrl" }).to_string()) + ).description(t!("copy_paste_hint").to_string()) ) .item( SettingItem::new( diff --git a/src/app/keybinding_recorder.rs b/src/app/keybinding_recorder.rs index dcd6284..d5bee35 100644 --- a/src/app/keybinding_recorder.rs +++ b/src/app/keybinding_recorder.rs @@ -29,7 +29,9 @@ gpui::actions!( SplitPaneRight, SplitPaneUp, SplitPaneDown, - ClosePane + ClosePane, + Copy, + Paste ] ); @@ -123,6 +125,16 @@ pub(crate) const WORKSPACE_ACTIONS: &[WorkspaceAction] = &[ label_key: "settings_close_pane", default_suffix: "w", }, + WorkspaceAction { + id: "Copy", + label_key: "settings_copy", + default_suffix: if cfg!(target_os = "macos") { "c" } else { "shift-c" }, + }, + WorkspaceAction { + id: "Paste", + label_key: "settings_paste", + default_suffix: if cfg!(target_os = "macos") { "v" } else { "shift-v" }, + }, ]; pub(crate) fn default_modifier() -> &'static str { @@ -224,6 +236,8 @@ pub(crate) fn unbind_all_workspace_keys(cx: &mut App, config: &ConfigStore) { unbind_action!("SplitPaneUp", crate::SplitPaneUp); unbind_action!("SplitPaneDown", crate::SplitPaneDown); unbind_action!("ClosePane", crate::ClosePane); + unbind_action!("Copy", crate::Copy); + unbind_action!("Paste", crate::Paste); cx.bind_keys(bindings); } @@ -280,6 +294,8 @@ fn bind_workspace_actions(cx: &mut App, config: &ConfigStore) { bind_action!("SplitPaneUp", crate::SplitPaneUp); bind_action!("SplitPaneDown", crate::SplitPaneDown); bind_action!("ClosePane", crate::ClosePane); + bind_action!("Copy", crate::Copy); + bind_action!("Paste", crate::Paste); cx.bind_keys(bindings); } @@ -289,7 +305,7 @@ impl KeybindingsPage { let groups = [ ( "settings_group_keybind_general", - vec!["OpenSettings", "OpenSession", "OpenTransfers", "NewSsh", "OpenSearch"], + vec!["OpenSettings", "OpenSession", "OpenTransfers", "NewSsh", "OpenSearch", "Copy", "Paste"], ), ( "settings_group_keybind_zoom", diff --git a/src/app/ui.rs b/src/app/ui.rs index f5ef338..f319493 100644 --- a/src/app/ui.rs +++ b/src/app/ui.rs @@ -2723,6 +2723,25 @@ impl Render for Ashell { this.close_tab(active_id, cx); } })) + .on_action(cx.listener(|this, _: &crate::Copy, window, cx| { + if let Some(text) = this.active_terminal_selection_text() { + cx.write_to_clipboard(gpui::ClipboardItem::new_string(text)); + if let Some(active_id) = &this.active_tab { + if let Some(tab) = this.tabs.iter_mut().find(|tab| &tab.id == active_id) { + tab.clear_selection(); + } + } + window.prevent_default(); + cx.stop_propagation(); + } + })) + .on_action(cx.listener(|this, _: &crate::Paste, window, cx| { + if let Some(clipboard) = cx.read_from_clipboard() { + if let Some(text) = clipboard.text() { + this.paste_into_terminal(&text, window, cx); + } + } + })) .when(self.active_title_bar_style == crate::session::config::TitleBarStyle::Integrated, |this| { this.child( div() diff --git a/src/main.rs b/src/main.rs index 9c4e91e..30e76c8 100644 --- a/src/main.rs +++ b/src/main.rs @@ -18,7 +18,7 @@ gpui::actions!(ashell_terminal, [TerminalTabKey, TerminalBacktabKey]); pub(crate) use app::keybinding_recorder::{ ClosePane, FocusPaneDown, FocusPaneLeft, FocusPaneRight, FocusPaneUp, NewSsh, OpenSearch, OpenSession, OpenSettings, OpenTransfers, SplitPaneDown, SplitPaneLeft, SplitPaneRight, - SplitPaneUp, ToggleSftpZoom, ToggleSidebar, + SplitPaneUp, ToggleSftpZoom, ToggleSidebar, Copy, Paste, }; pub(crate) use app::{ diff --git a/src/terminal/input.rs b/src/terminal/input.rs index f9c68ca..2b4d8fd 100644 --- a/src/terminal/input.rs +++ b/src/terminal/input.rs @@ -190,7 +190,7 @@ impl Ashell { .and_then(|tab| tab.selection_text()) } - fn paste_into_terminal(&mut self, text: &str, window: &mut Window, cx: &mut Context) { + pub(crate) fn paste_into_terminal(&mut self, text: &str, window: &mut Window, cx: &mut Context) { let Some(active_id) = self.active_tab.clone() else { return; };