Skip to content

Fix text selection in mouse-tracking sessions on macOS - #81

Merged
abasiri merged 1 commit into
doctly:mainfrom
Bono2007:fix/macos-selection-mouse-tracking
Aug 1, 2026
Merged

Fix text selection in mouse-tracking sessions on macOS#81
abasiri merged 1 commit into
doctly:mainfrom
Bono2007:fix/macos-selection-mouse-tracking

Conversation

@Bono2007

@Bono2007 Bono2007 commented Jul 27, 2026

Copy link
Copy Markdown
Contributor

Problem

Text cannot be selected with the mouse on macOS in any session running a TUI that enables mouse tracking, which makes copying impossible.

When an application turns on mouse tracking (CSI ?1002h / CSI ?1003h), xterm.js forwards every drag to that application instead of starting a selection. Terminal.app and iTerm2 let you hold Option to override the convention, but xterm.js gates the same escape hatch behind macOptionClickForcesSelection, which defaults to false and was never set here.

The symptom users report is misleading. Cmd+C finds no selection, so xterm's copy handler is a no-op and it fails silently — the previous clipboard contents stay in place. The next paste then inserts stale text, which reads as "paste is broken" even though the paste path itself is fine.

Reproduction

Measured against the live renderer over the Chrome DevTools Protocol, driving synthetic mouse and key events. The session runs vim -c "set mouse=a" on a file containing one known line:

mouseTrackingMode = "drag"

[option OFF] plain drag  -> ""
[option OFF] Option+drag -> ""

[option ON]  plain drag  -> ""
[option ON]  Option+drag -> "the quick brown fox jumps over the lazy dog"

clipboard after Cmd+C    =  "the quick brown fox jumps over the lazy dog"

Same gesture, same session, only the option toggled — which isolates the cause. Plain drag correctly keeps going to the application in both states, so mouse-driven TUIs stay usable.

Fix

One option on the xterm instance in public/terminal-manager.js:

macOptionClickForcesSelection: true,

Windows and Linux were never affected — there shouldForceSelection keys off Shift, which needs no option.

Verification

  • Full round trip in a mouse-tracking session: Option+drag → Cmd+CCmd+V returns the selected line intact.
  • No regression in sessions without mouse tracking: plain drag, Option+drag, double-click (one word) and triple-click (full line) all behave as before.
  • npm test passes, npm run bundle:codemirror succeeds.

Trade-off

Enabling this flag disables Option+drag rectangular (column) selection on macOS, since xterm's shouldColumnSelect and shouldForceSelection share the same modifier. This is the standard trade-off and matches iTerm2's default behaviour.

Related

Distinct from #54 / #55, which cover copy on Linux/Wayland via OSC 52. Worth noting separately that Switchboard doesn't handle OSC 52 at all, so an application's own clipboard requests are dropped — out of scope here.

A TUI that turns on mouse tracking (CSI ?1002h / ?1003h) makes xterm.js
forward every drag to the application, so no text can be selected. Terminal.app
and iTerm2 let you hold Option to override that; xterm.js gates the same escape
hatch behind macOptionClickForcesSelection, which defaults to false.

The symptom is misleading: Cmd+C finds no selection, so xterm's copy handler is
a no-op and fails silently, leaving the previous clipboard contents in place.
The next paste then inserts stale text and reads as a broken paste.

Windows and Linux are unaffected — there the override is Shift, which needs no
option.
@Bono2007
Bono2007 force-pushed the fix/macos-selection-mouse-tracking branch from 571a088 to 35c567d Compare July 27, 2026 11:13
@Bono2007 Bono2007 changed the title Fix text selection in Claude Code sessions on macOS Fix text selection in mouse-tracking sessions on macOS Jul 27, 2026
@abasiri
abasiri merged commit fae085a into doctly:main Aug 1, 2026
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.

2 participants