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
This commit is contained in:
George Waters 2026-05-05 10:50:57 -04:00 committed by GitHub
parent 02af528c5a
commit 4b3c0cda73
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
4 changed files with 25 additions and 4 deletions

View file

@ -1264,6 +1264,7 @@
"ctrl-cmd-space": "terminal::ShowCharacterPalette", "ctrl-cmd-space": "terminal::ShowCharacterPalette",
"cmd-c": "terminal::Copy", "cmd-c": "terminal::Copy",
"cmd-v": "terminal::Paste", "cmd-v": "terminal::Paste",
"ctrl-cmd-v": "terminal::PasteText",
"cmd-f": "buffer_search::Deploy", "cmd-f": "buffer_search::Deploy",
"cmd-a": "editor::SelectAll", "cmd-a": "editor::SelectAll",
"cmd-k": "terminal::Clear", "cmd-k": "terminal::Clear",

View file

@ -1221,6 +1221,7 @@
"shift-insert": "terminal::Paste", "shift-insert": "terminal::Paste",
"ctrl-v": "terminal::Paste", "ctrl-v": "terminal::Paste",
"ctrl-shift-v": "terminal::Paste", "ctrl-shift-v": "terminal::Paste",
"ctrl-alt-v": "terminal::PasteText",
"ctrl-i": "assistant::InlineAssist", "ctrl-i": "assistant::InlineAssist",
"alt-b": ["terminal::SendText", "\u001bb"], "alt-b": ["terminal::SendText", "\u001bb"],
"alt-f": ["terminal::SendText", "\u001bf"], "alt-f": ["terminal::SendText", "\u001bf"],

View file

@ -84,6 +84,8 @@ actions!(
Copy, Copy,
/// Pastes from the clipboard. /// Pastes from the clipboard.
Paste, Paste,
/// Pastes the text from the clipboard.
PasteText,
/// Shows the character palette for special characters. /// Shows the character palette for special characters.
ShowCharacterPalette, ShowCharacterPalette,
/// Searches for text in the terminal. /// Searches for text in the terminal.

View file

@ -32,9 +32,9 @@ use std::{
}; };
use task::TaskId; use task::TaskId;
use terminal::{ use terminal::{
Clear, Copy, Event, HoveredWord, MaybeNavigationTarget, Paste, ScrollLineDown, ScrollLineUp, Clear, Copy, Event, HoveredWord, MaybeNavigationTarget, Paste, PasteText, ScrollLineDown,
ScrollPageDown, ScrollPageUp, ScrollToBottom, ScrollToTop, ShowCharacterPalette, TaskState, ScrollLineUp, ScrollPageDown, ScrollPageUp, ScrollToBottom, ScrollToTop, ShowCharacterPalette,
TaskStatus, Terminal, TerminalBounds, ToggleViMode, TaskState, TaskStatus, Terminal, TerminalBounds, ToggleViMode,
alacritty_terminal::{ alacritty_terminal::{
index::Point as AlacPoint, index::Point as AlacPoint,
term::{TermMode, point_to_viewport, search::RegexSearch}, term::{TermMode, point_to_viewport, search::RegexSearch},
@ -508,6 +508,7 @@ impl TerminalView {
.separator() .separator()
.action("Copy", Box::new(Copy)) .action("Copy", Box::new(Copy))
.action("Paste", Box::new(Paste)) .action("Paste", Box::new(Paste))
.action("Paste Text", Box::new(PasteText))
.action("Select All", Box::new(SelectAll)) .action("Select All", Box::new(SelectAll))
.action("Clear", Box::new(Clear)) .action("Clear", Box::new(Clear))
.when(assistant_enabled, |menu| { .when(assistant_enabled, |menu| {
@ -811,7 +812,7 @@ impl TerminalView {
} }
///Attempt to paste the clipboard into the terminal ///Attempt to paste the clipboard into the terminal
fn paste(&mut self, _: &Paste, _: &mut Window, cx: &mut Context<Self>) { fn paste(&mut self, _: &Paste, window: &mut Window, cx: &mut Context<Self>) {
let Some(clipboard) = cx.read_from_clipboard() else { let Some(clipboard) = cx.read_from_clipboard() else {
return; return;
}; };
@ -820,6 +821,9 @@ impl TerminalView {
Some(ClipboardEntry::Image(image)) if !image.bytes.is_empty() => { Some(ClipboardEntry::Image(image)) if !image.bytes.is_empty() => {
self.forward_ctrl_v(cx); self.forward_ctrl_v(cx);
} }
Some(ClipboardEntry::ExternalPaths(paths)) => {
self.add_paths_to_terminal(paths.paths(), window, cx);
}
_ => { _ => {
if let Some(text) = clipboard.text() { if let Some(text) = clipboard.text() {
self.terminal 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<Self>) {
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 /// Emits a raw Ctrl+V so TUI agents can read the OS clipboard directly
/// and attach images using their native workflows. /// and attach images using their native workflows.
fn forward_ctrl_v(&self, cx: &mut Context<Self>) { fn forward_ctrl_v(&self, cx: &mut Context<Self>) {
@ -1226,6 +1242,7 @@ impl Render for TerminalView {
.on_action(cx.listener(TerminalView::send_keystroke)) .on_action(cx.listener(TerminalView::send_keystroke))
.on_action(cx.listener(TerminalView::copy)) .on_action(cx.listener(TerminalView::copy))
.on_action(cx.listener(TerminalView::paste)) .on_action(cx.listener(TerminalView::paste))
.on_action(cx.listener(TerminalView::paste_text))
.on_action(cx.listener(TerminalView::clear)) .on_action(cx.listener(TerminalView::clear))
.on_action(cx.listener(TerminalView::scroll_line_up)) .on_action(cx.listener(TerminalView::scroll_line_up))
.on_action(cx.listener(TerminalView::scroll_line_down)) .on_action(cx.listener(TerminalView::scroll_line_down))