From a5993eb9b3be030f2f354cebc2827ca46d851fe9 Mon Sep 17 00:00:00 2001 From: George Waters Date: Tue, 5 May 2026 10:50:57 -0400 Subject: [PATCH] Support path pasting in terminal (#48222) This adds the functionality to support pasting the file path of an item when the copied item supports it. This mirrors the behavior of `Terminal.app` on macOS. This only implements the functionality on macOS but could be extended to other platforms. I find this convenient when I'm using Finder to navigate around the file system and I want to copy a directory or file path and put it in the terminal. You can copy the item from Finder and paste it into the terminal and it will write out the full path of the item, making it easy to change directories or provide path parameters to commands. Release Notes: - Added path pasting functionality in terminal --- assets/keymaps/default-macos.json | 1 + assets/keymaps/default-windows.json | 1 + crates/terminal/src/terminal.rs | 2 ++ crates/terminal_view/src/terminal_view.rs | 25 +++++++++++++++++++---- 4 files changed, 25 insertions(+), 4 deletions(-) diff --git a/assets/keymaps/default-macos.json b/assets/keymaps/default-macos.json index 8e115985db..d73c6d7a8b 100644 --- a/assets/keymaps/default-macos.json +++ b/assets/keymaps/default-macos.json @@ -1264,6 +1264,7 @@ "ctrl-cmd-space": "terminal::ShowCharacterPalette", "cmd-c": "terminal::Copy", "cmd-v": "terminal::Paste", + "ctrl-cmd-v": "terminal::PasteText", "cmd-f": "buffer_search::Deploy", "cmd-a": "editor::SelectAll", "cmd-k": "terminal::Clear", diff --git a/assets/keymaps/default-windows.json b/assets/keymaps/default-windows.json index 9ac7ed46cf..fc1d78b39f 100644 --- a/assets/keymaps/default-windows.json +++ b/assets/keymaps/default-windows.json @@ -1221,6 +1221,7 @@ "shift-insert": "terminal::Paste", "ctrl-v": "terminal::Paste", "ctrl-shift-v": "terminal::Paste", + "ctrl-alt-v": "terminal::PasteText", "ctrl-i": "assistant::InlineAssist", "alt-b": ["terminal::SendText", "\u001bb"], "alt-f": ["terminal::SendText", "\u001bf"], diff --git a/crates/terminal/src/terminal.rs b/crates/terminal/src/terminal.rs index 3be023e826..99b3b9d6ce 100644 --- a/crates/terminal/src/terminal.rs +++ b/crates/terminal/src/terminal.rs @@ -84,6 +84,8 @@ actions!( Copy, /// Pastes from the clipboard. Paste, + /// Pastes the text from the clipboard. + PasteText, /// Shows the character palette for special characters. ShowCharacterPalette, /// Searches for text in the terminal. diff --git a/crates/terminal_view/src/terminal_view.rs b/crates/terminal_view/src/terminal_view.rs index 36bac03312..a6e28a95f5 100644 --- a/crates/terminal_view/src/terminal_view.rs +++ b/crates/terminal_view/src/terminal_view.rs @@ -32,9 +32,9 @@ use std::{ }; use task::TaskId; use terminal::{ - Clear, Copy, Event, HoveredWord, MaybeNavigationTarget, Paste, ScrollLineDown, ScrollLineUp, - ScrollPageDown, ScrollPageUp, ScrollToBottom, ScrollToTop, ShowCharacterPalette, TaskState, - TaskStatus, Terminal, TerminalBounds, ToggleViMode, + Clear, Copy, Event, HoveredWord, MaybeNavigationTarget, Paste, PasteText, ScrollLineDown, + ScrollLineUp, ScrollPageDown, ScrollPageUp, ScrollToBottom, ScrollToTop, ShowCharacterPalette, + TaskState, TaskStatus, Terminal, TerminalBounds, ToggleViMode, alacritty_terminal::{ index::Point as AlacPoint, term::{TermMode, point_to_viewport, search::RegexSearch}, @@ -508,6 +508,7 @@ impl TerminalView { .separator() .action("Copy", Box::new(Copy)) .action("Paste", Box::new(Paste)) + .action("Paste Text", Box::new(PasteText)) .action("Select All", Box::new(SelectAll)) .action("Clear", Box::new(Clear)) .when(assistant_enabled, |menu| { @@ -811,7 +812,7 @@ impl TerminalView { } ///Attempt to paste the clipboard into the terminal - fn paste(&mut self, _: &Paste, _: &mut Window, cx: &mut Context) { + fn paste(&mut self, _: &Paste, window: &mut Window, cx: &mut Context) { let Some(clipboard) = cx.read_from_clipboard() else { return; }; @@ -820,6 +821,9 @@ impl TerminalView { Some(ClipboardEntry::Image(image)) if !image.bytes.is_empty() => { self.forward_ctrl_v(cx); } + Some(ClipboardEntry::ExternalPaths(paths)) => { + self.add_paths_to_terminal(paths.paths(), window, cx); + } _ => { if let Some(text) = clipboard.text() { self.terminal @@ -829,6 +833,18 @@ impl TerminalView { } } + ///Attempt to paste the clipboard text into the terminal + fn paste_text(&mut self, _: &PasteText, _: &mut Window, cx: &mut Context) { + let Some(clipboard) = cx.read_from_clipboard() else { + return; + }; + + if let Some(text) = clipboard.text() { + self.terminal + .update(cx, |terminal, _cx| terminal.paste(&text)); + } + } + /// Emits a raw Ctrl+V so TUI agents can read the OS clipboard directly /// and attach images using their native workflows. fn forward_ctrl_v(&self, cx: &mut Context) { @@ -1226,6 +1242,7 @@ impl Render for TerminalView { .on_action(cx.listener(TerminalView::send_keystroke)) .on_action(cx.listener(TerminalView::copy)) .on_action(cx.listener(TerminalView::paste)) + .on_action(cx.listener(TerminalView::paste_text)) .on_action(cx.listener(TerminalView::clear)) .on_action(cx.listener(TerminalView::scroll_line_up)) .on_action(cx.listener(TerminalView::scroll_line_down))