Skip to content

Open a terminal link on a plain click - #25

Merged
bharathm03 merged 1 commit into
developmentfrom
fix/terminal-plain-click-hyperlinks
Aug 27, 2026
Merged

Open a terminal link on a plain click#25
bharathm03 merged 1 commit into
developmentfrom
fix/terminal-plain-click-hyperlinks

Conversation

@bharathm03

Copy link
Copy Markdown
Contributor

Follow-up to #14. The links still did not work where it mattered.

Why

Measured on Claude Code's own PTY, not inferred:

MOUSE modes enabled: 1000, 1002, 1003, 1006   <- all-motion SGR, in its first frame
OSC 8 URIs seen: 2  ["https://claude.ai/code/session_...", ...]

A full-screen agent takes the mouse before it prints anything, so _handleTapUp hit the mouse-capture guard and returned before hyperlink resolution on every click -- while the render path kept painting the cell blue and underlined, because hasHyperlink paints unconditionally. Shift+click reached the link; nothing on screen said the chord existed. That is the original bug, still standing in the one case the OSC 8 work was written for.

#14 had already decided a bare finger tap should open an explicit OSC 8 link even when the program holds the mouse -- OSC 8 is the program declaring these cells are a link, which outranks its claim on the pointer. That argument never depended on the pointer being a finger.

What is in here

Pin bump to antgrid-ai/dart_terminal#6 (ce7f469 -> f8e2e82), which:

  • opens an explicit OSC 8 link on a plain primary click, withholding the whole press-motion-release span so the agent is never handed half a click
  • leaves bare-URL matches, cells outside the link, and right/middle click with the agent
  • keeps Shift meaning what it meant, now as the way to reach a bare-URL match
  • makes hover mark only what a click will actually open

Six tests there, each negative-checked against a reverted terminal_view.dart.

A wrong claim this turned up

_revealsDestinationOnHover skipped the confirm sheet on desktop because "Desktop does, through the terminal's hover affordance, so a click there is already an informed one."

That is false and always was. _hoveredHyperlink drives one thing -- SystemMouseCursors.click -- and neither the view nor this app ever paints the URI. So the desktop path was skipping the spoof check on a premise that does not hold, and this PR makes that path reachable in one plain click.

The gating is still right, for a different reason: desktop hands the URI to a browser whose address bar reads it back, which is the disclosure every terminal leans on. Mobile has no such guarantee -- an https: host holding a verified App Link opens that app instead of any browser, so the destination can be acted on without ever being shown. Renamed to _browserRevealsDestination and documented as that.

The real fix for desktop is a hover preview of the destination, which needs an onHyperlinkHover callback the fork does not expose yet. Not in scope here; flagged rather than quietly left as-is.

Gates

App suite +2617 ~2, all pass. flutter analyze clean. check:font-tokens OK. Fork: +208 -28, the 28 pre-existing on master.

Not verified in the running app

flutter_driver has no tap-at-coordinate command, so a terminal cell is not reachable from the harness. The evidence is the PTY measurement plus the widget tests.

…hows where it goes

A full-screen agent takes the mouse before it prints anything -- Claude Code enables 1000/1002/1003/1006 in its first frame, measured on its PTY -- so every click went to the agent and the link stayed dead, in exactly the case the OSC 8 work was written for. The cell still painted as a link. Bumps the fork pin to antgrid-ai/dart_terminal#6, which opens an explicit OSC 8 link on a plain primary click and makes hover mark only what a click will actually open.

The desktop path skipped the confirm sheet because the terminal was said to reveal a link's destination on hover. It does not, and never did: the hovered URI only swaps the mouse cursor to a pointer, and nothing in the view or this app ever paints it. What actually discloses on desktop is the browser's address bar -- which is why the sheet still belongs on mobile alone, where a verified App Link can open its own app instead of any browser. Renamed to say the true reason.
@bharathm03
bharathm03 merged commit c0f7165 into development Aug 27, 2026
4 checks passed
@bharathm03
bharathm03 deleted the fix/terminal-plain-click-hyperlinks branch August 27, 2026 12:47
@bharathm03
bharathm03 restored the fix/terminal-plain-click-hyperlinks branch August 27, 2026 12:49
@bharathm03
bharathm03 deleted the fix/terminal-plain-click-hyperlinks branch August 27, 2026 12:50
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.

1 participant