Skip to content

Paste into the desktop terminal - #1265

Merged
alexeyzimarev merged 2 commits into
mainfrom
norton/ai-3282-desktop-terminal-copy-paste
Oct 1, 2026
Merged

alexeyzimarev merged 2 commits into
mainfrom
norton/ai-3282-desktop-terminal-copy-paste

Conversation

@nortonandreev

@nortonandreev nortonandreev commented Oct 1, 2026 •

Copy link
Copy Markdown
Contributor

Closes #1200 — AI-3282

What & why

On the desktop Terminal view, the paste chord never inserts clipboard text. The terminal control turns Ctrl+V into a control byte and does not handle ⌘V. The workspace and remote session views claim the platform paste chord while the terminal is focused and send the same bracketed block the composer uses, without a trailing Enter. Copy is left to the control, and Ctrl+C still interrupts.

Where to look

The handler sits on the view, above the control, because the control's key handler runs first and ignores Handled. A paste goes through Model.Send, so a read-only attach still drops it. The remote pane only forwards special keys, so a paste there does not inject text.

Verification

dotnet run --project test/Capacitor.App.Tests.Unit/Capacitor.App.Tests.Unit.csproj -- --treenode-filter '/*/*/TerminalClipboardTests/*'

Passed: 5, failed: 0.

The terminal control clears a selection and turns Ctrl+C/V into control bytes, so the gesture is claimed on the view while the terminal is focused. A paste is the composer's bracketed block, with no trailing submit.
@linear-code

linear-code Bot commented Oct 1, 2026

Copy link
Copy Markdown

AI-3282

@nortonandreev nortonandreev self-assigned this Oct 1, 2026
@nortonandreev
nortonandreev force-pushed the norton/ai-3282-desktop-terminal-copy-paste branch from 3f88688 to 3bc3fa1 Compare October 1, 2026 12:23
The control turns that chord into a control byte or ignores it, so the view claims it while the terminal is focused. The block is the composer's bracketed paste, with no trailing submit.
@nortonandreev nortonandreev changed the title Copy and paste on the desktop terminal Paste into the desktop terminal Oct 1, 2026
@nortonandreev
nortonandreev marked this pull request as ready for review October 1, 2026 13:19
@nortonandreev

Copy link
Copy Markdown
Contributor Author

Changelog

  • Paste into the desktop terminal with ⌘V on macOS, or Ctrl+V on Windows and Linux. The text lands in the agent's composer and is not submitted.
  • Ctrl+C still interrupts the agent.

@qodo-code-review

Copy link
Copy Markdown

PR Summary by Qodo

Enable platform paste shortcuts in desktop terminal views

🐞 Bug fix 🧪 Tests 🕐 20-40 Minutes

Grey Divider

AI Description

• Make the platform paste shortcut insert clipboard text in workspace and remote terminals.
• Send paste as a bracketed block without submitting it; preserve Ctrl+C and composer focus
 behavior.
• Add headless tests for shortcuts, focus isolation, and both terminal views.
Diagram

graph TD
  W["Workspace view"] --> H["Clipboard handler"] --> F{"Focused paste?"} --> C["System clipboard"] --> E["Paste encoder"] --> M["Terminal model"]
  R["Remote view"] --> H
Loading
High-Level Assessment

The following are alternative approaches to this PR:

1. Handle paste inside TerminalControl
  • ➕ Would centralize shortcut behavior for every use of the control.
  • ➖ Requires changing the control's key handling, which currently runs first and ignores handled events.

Recommendation: Keep the shared tunneled handler on the views: it intercepts paste before the control while reusing the existing paste encoder and terminal model send path. Changing TerminalControl would be more invasive for these two desktop views.

Files changed (4) +171 / -0

Bug fix (3) +35 / -0
RemoteSessionView.axaml.csEnable terminal paste in remote sessions +1/-0

Enable terminal paste in remote sessions

• Attaches the shared clipboard shortcut handler to the remote session terminal host.

src/Capacitor.App/Views/RemoteSessionView.axaml.cs

TerminalClipboard.csIntercept focused terminal paste shortcuts +33/-0

Intercept focused terminal paste shortcuts

• Claims the platform paste gesture during tunneled key handling when the terminal has focus and a model. Reads clipboard text and sends an encoded bracketed paste through the model without submitting it.

src/Capacitor.App/Views/TerminalClipboard.cs

WorkspaceView.axaml.csEnable terminal paste in workspaces +1/-0

Enable terminal paste in workspaces

• Attaches the shared clipboard shortcut handler to the workspace terminal host.

src/Capacitor.App/Views/WorkspaceView.axaml.cs

Tests (1) +136 / -0
TerminalClipboardTests.csCover terminal paste and shortcut isolation +136/-0

Cover terminal paste and shortcut isolation

• Adds five headless tests for bracketed paste, both terminal views, composer focus isolation, and copy and Ctrl+C behavior.

test/Capacitor.App.Tests.Unit/TerminalClipboardTests.cs

@qodo-code-review

qodo-code-review Bot commented Oct 1, 2026 •

Copy link
Copy Markdown

Code Review by Qodo

🐞 Bugs (0) 📘 Rule violations (0) 🔗 Cross-repo conflicts (0) 📜 Skill insights (0)

Grey Divider


Remediation recommended

1. Clipboard failures leave pastes unexplained ✗ Dismissed
Description
OnKeyDown marks the paste chord handled and discards the task returned by PasteAsync, which has
no exception handler around the clipboard read. If that read fails, the paste produces no terminal
input and its exception is neither reported to the user nor observed by this handler.
Code

src/Capacitor.App/Views/TerminalClipboard.cs[R20-21]

+        e.Handled = true;
+        _ = PasteAsync(terminal);
Relevance

●●● Strong

Recent precedent accepts findings requiring fire-and-forget async failures to be observed or
handled.

PR-#766

ⓘ Recommendations generated based on similar findings in past PRs

Evidence
The new handler consumes the key and drops the task; PasteAsync awaits TryGetTextAsync without
catching failures. Another clipboard intake path in the app explicitly catches exceptions from
asynchronous clipboard work and produces a failure result.

src/Capacitor.App/Views/TerminalClipboard.cs[18-31]
src/Capacitor.App/Views/AttachmentDropPaste.cs[63-75]
src/Capacitor.App/Views/AttachmentDropPaste.cs[155-173]

Agent prompt
The issue below was found during a code review. Follow the provided context and guidance below and implement a solution

## Issue description
The paste event is consumed before an unobserved asynchronous clipboard read, so read failures leave no handled result or diagnostic.
## Fix Focus Areas
- src/Capacitor.App/Views/TerminalClipboard.cs[18-31]
## Recommended Fix
Catch failures in the asynchronous paste path, log the exception with its traceback, and provide an appropriate failure indication rather than leaving the consumed gesture unexplained.

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools


2. Pastes can reach a different session ✗ Dismissed
Description
PasteAsync reads terminal.Model only after awaiting the clipboard, without confirming that it is
the model that received the paste chord or that the terminal still has focus. If a session
reattaches or the user switches tabs during the read, the clipboard contents can be sent to a
replacement session or to a terminal that is no longer active.
Code

src/Capacitor.App/Views/TerminalClipboard.cs[R29-31]

+        var text = await clipboard.TryGetTextAsync();
+        if (string.IsNullOrEmpty(text) || terminal.Model is not { } model) return;
+        model.Send(TerminalInputEncoder.Paste(text));
Relevance

●● Moderate

The race is plausible, but historical evidence does not closely establish this model-switching
behavior as a team requirement.

PR-#1198

ⓘ Recommendations generated based on similar findings in past PRs

Evidence
The initial focus and model checks occur before PasteAsync starts, while the model used for Send is
fetched after the await. WorkspaceView retains the terminal control across tab changes, binds its
model to the terminal surface, and reattachment can replace that surface; the surface forwards model
input to its input event without checking tab focus.

src/Capacitor.App/Views/TerminalClipboard.cs[18-31]
src/Capacitor.App/Views/WorkspaceView.axaml[58-66]
src/Capacitor.App/ViewModels/TerminalTabViewModel.cs[485-491]
src/Capacitor.App/ViewModels/TerminalTabViewModel.cs[534-540]

Agent prompt
The issue below was found during a code review. Follow the provided context and guidance below and implement a solution

## Issue description
Clipboard retrieval is asynchronous, but the paste handler sends to whichever model is bound when the read completes, even if the terminal has lost focus.
## Fix Focus Areas
- src/Capacitor.App/Views/TerminalClipboard.cs[18-31]
## Recommended Fix
Capture the terminal model when handling the key, pass it to PasteAsync, and after the clipboard await send only if that same model is still bound and the terminal remains focused.

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools


Grey Divider

Context sources
✅ Compliance rules (platform): 64 rules
✅ Cross-repo context — repo relationships
Review mode: ⚖️ Balanced: This is a localized runtime input-handling change with user-visible terminal behavior and clipboard/platform event-routing implications, warranting a careful single-pass review.

Grey Divider

Tip of the day
💡 Did you know, you can keep summaries lean with Findings visible per group, which tucks the rest behind a View link

More tips ↗ | Customize Qodo ↗ | Qodo docs ↗

Grey Divider

Qodo Logo

Comment thread src/Capacitor.App/Views/TerminalClipboard.cs
Comment thread src/Capacitor.App/Views/TerminalClipboard.cs
@alexeyzimarev
alexeyzimarev merged commit 708f0fb into main Oct 1, 2026
8 checks passed
@alexeyzimarev
alexeyzimarev deleted the norton/ai-3282-desktop-terminal-copy-paste branch October 1, 2026 14:26
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Desktop app: copy and paste don't work on the Terminal view

2 participants