Skip to content

fix(desktop): trim trailing whitespace when copying text from terminal#1104

Merged
Kitenite merged 1 commit intomainfrom
1018
Feb 1, 2026
Merged

fix(desktop): trim trailing whitespace when copying text from terminal#1104
Kitenite merged 1 commit intomainfrom
1018

Conversation

@Kitenite
Copy link
Copy Markdown
Collaborator

@Kitenite Kitenite commented Feb 1, 2026

Summary

  • Adds a copy handler that trims trailing whitespace from each line when copying text from the terminal
  • This matches the default behavior of iTerm2 and other popular terminal emulators (iTerm2's TrimWhitespaceOnCopy defaults to true)

Test plan

  • Select text in terminal that spans multiple lines
  • Copy with Cmd+C
  • Paste into a text editor and verify no trailing spaces on each line
  • Verify single-line copies still work correctly
  • Verify intentional newlines are preserved

Fixes #1018

Summary by CodeRabbit

  • New Features
    • Enhanced terminal copy functionality: When copying text from the terminal, trailing whitespace is automatically trimmed while preserving line breaks, resulting in cleaner copied content.

✏️ Tip: You can customize this high-level summary in your review settings.

Adds a copy handler that trims trailing whitespace from each line when
copying text from the terminal. This matches the default behavior of
iTerm2 and other popular terminal emulators.

Fixes #1018
@coderabbitai
Copy link
Copy Markdown
Contributor

coderabbitai Bot commented Feb 1, 2026

📝 Walkthrough

Walkthrough

Added a new copy event handler to the terminal that automatically trims trailing whitespace from copied text while preserving line breaks. The handler is integrated into the terminal's lifecycle hooks with proper cleanup during unmount.

Changes

Cohort / File(s) Summary
Terminal Copy Handler
apps/desktop/src/renderer/screens/main/components/WorkspaceView/ContentView/TabsContent/Terminal/helpers.ts, apps/desktop/src/renderer/screens/main/components/WorkspaceView/ContentView/TabsContent/Terminal/hooks/useTerminalLifecycle.ts
Introduced setupCopyHandler() function that intercepts copy events and trims trailing whitespace from each line. Integrated setup and cleanup into terminal lifecycle management.

Sequence Diagram

sequenceDiagram
    actor User
    participant XTerm
    participant CopyHandler
    participant Clipboard

    User->>XTerm: Initiates copy action
    XTerm->>CopyHandler: Copy event fires
    CopyHandler->>CopyHandler: Get selected text via xterm.getSelection()
    CopyHandler->>CopyHandler: Trim whitespace from each line
    CopyHandler->>Clipboard: setData("text/plain", trimmedText)
    Clipboard-->>User: Cleaned text available
Loading

Estimated code review effort

🎯 2 (Simple) | ⏱️ ~8 minutes

Possibly related PRs

Poem

🐰 A hop, a skip, a copy so clean!
Trailing spaces trimmed in between,
Each keystroke blessed by whiskers divine,
The clipboard now sparkles, no extra line! ✨

🚥 Pre-merge checks | ✅ 4 | ❌ 1
❌ Failed checks (1 warning)
Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 50.00% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Title check ✅ Passed The title clearly and specifically describes the main change: trimming trailing whitespace when copying from terminal.
Description check ✅ Passed The description includes a clear summary, test plan, and issue reference, though it could benefit from a Type of Change section per the template.
Linked Issues check ✅ Passed The PR directly addresses issue #1018 by implementing trailing whitespace trimming on terminal copy, matching iTerm2 behavior as a solution to the reported problem.
Out of Scope Changes check ✅ Passed All changes are directly related to the stated objective: adding copy handler setup and terminal lifecycle integration for whitespace trimming.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing touches
  • 📝 Generate docstrings
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branch 1018

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

Copy link
Copy Markdown
Contributor

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

🤖 Fix all issues with AI agents
In
`@apps/desktop/src/renderer/screens/main/components/WorkspaceView/ContentView/TabsContent/Terminal/helpers.ts`:
- Around line 340-341: The current copy handler calls event.preventDefault()
unconditionally then uses event.clipboardData?.setData("text/plain",
trimmedText), which can silently fail if clipboardData is null; change the logic
in the copy handler so you only preventDefault when you have a successful path
to place text on the clipboard (e.g. check event.clipboardData exists before
calling event.preventDefault() and event.clipboardData.setData(...)), and add a
fallback that attempts navigator.clipboard.writeText(trimmedText) (with
try/catch) if event.clipboardData is absent; update references to
event.preventDefault, event.clipboardData?.setData and trimmedText in the
handler accordingly and surface/log errors if both methods fail.

Comment on lines +340 to +341
event.preventDefault();
event.clipboardData?.setData("text/plain", trimmedText);
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟡 Minor

Potential silent copy failure if clipboardData is null.

When event.preventDefault() is called unconditionally on line 340, the default copy behavior is blocked. If clipboardData happens to be null (edge case in some browser/Electron contexts), line 341's optional chaining silently skips the write, leaving the user with an empty clipboard and no indication of failure.

Consider guarding the preventDefault() call or adding a fallback:

🛡️ Proposed fix
 	const handleCopy = (event: ClipboardEvent) => {
 		const selection = xterm.getSelection();
 		if (!selection) return;
+		if (!event.clipboardData) return;

 		// Trim trailing whitespace from each line while preserving intentional newlines
 		const trimmedText = selection
 			.split("\n")
 			.map((line) => line.trimEnd())
 			.join("\n");

 		event.preventDefault();
-		event.clipboardData?.setData("text/plain", trimmedText);
+		event.clipboardData.setData("text/plain", trimmedText);
 	};
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
event.preventDefault();
event.clipboardData?.setData("text/plain", trimmedText);
const handleCopy = (event: ClipboardEvent) => {
const selection = xterm.getSelection();
if (!selection) return;
if (!event.clipboardData) return;
// Trim trailing whitespace from each line while preserving intentional newlines
const trimmedText = selection
.split("\n")
.map((line) => line.trimEnd())
.join("\n");
event.preventDefault();
event.clipboardData.setData("text/plain", trimmedText);
};
🤖 Prompt for AI Agents
In
`@apps/desktop/src/renderer/screens/main/components/WorkspaceView/ContentView/TabsContent/Terminal/helpers.ts`
around lines 340 - 341, The current copy handler calls event.preventDefault()
unconditionally then uses event.clipboardData?.setData("text/plain",
trimmedText), which can silently fail if clipboardData is null; change the logic
in the copy handler so you only preventDefault when you have a successful path
to place text on the clipboard (e.g. check event.clipboardData exists before
calling event.preventDefault() and event.clipboardData.setData(...)), and add a
fallback that attempts navigator.clipboard.writeText(trimmedText) (with
try/catch) if event.clipboardData is absent; update references to
event.preventDefault, event.clipboardData?.setData and trimmedText in the
handler accordingly and surface/log errors if both methods fail.

@Kitenite Kitenite merged commit 82b8f30 into main Feb 1, 2026
5 checks passed
@github-actions
Copy link
Copy Markdown
Contributor

github-actions Bot commented Feb 1, 2026

🧹 Preview Cleanup Complete

The following preview resources have been cleaned up:

  • ✅ Neon database branch
  • ⚠️ Electric Fly.io app

Thank you for your contribution! 🎉

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.

[bug] Copying text copies spaces and newlines

1 participant