ghostty icon indicating copy to clipboard operation
ghostty copied to clipboard

feat: Select/Copy Links On Right Click If Present

Open mkasberg opened this issue 2 months ago • 0 comments

This is a solution for https://github.com/ghostty-org/ghostty/issues/2107.

AI Disclosure: I used Gemini CLI to help me with this PR because while I have many years of programming experience, this is my first time writing Zig. I prototyped a couple different approaches with AI before landing on this one, so AI generated various prototypes and I chose the final imlementation. I've verified that my code compiles and works as intended.

When a user right-clicks, and there's no existing selection, the existing behavior is to try to select the word under the cursor:

https://github.com/ghostty-org/ghostty/blob/3548acfac63e7674b5e25896f6b393474fe8ea65/src/Surface.zig#L3740-L3742

This PR tweaks that behavior slightly: If there's a link under our cursor, as determined by linkAtPos, select the link (to copy with the right-click context menu). Otherwise, select the word as before.

As noted in https://github.com/ghostty-org/ghostty/issues/2107, this matches the behavior of iTerm and Gnome Terminal.

It's worth noting that linkAtPos already does the right thing in terms of checking the links from config and their highlight/hover states (modified by Ctrl or Super depending on platform).

https://github.com/ghostty-org/ghostty/blob/3548acfac63e7674b5e25896f6b393474fe8ea65/src/Surface.zig#L3896-L3901

It also therefore respects link-url from config.

https://github.com/ghostty-org/ghostty/blob/3548acfac63e7674b5e25896f6b393474fe8ea65/src/config/Config.zig#L3411-L3416

By using linkAtPos, we get all that behavior for free. In practical terms, that means:

  • If I'm holding Ctrl so a link is underlined and I right click on it, it selects the underlined link.
  • If I'm not holding Ctrl and I right click on a link that is no underlined, it selects the word as before.
  • This behavior respects per-platform key bindings and user config settings.

linkAtPos requires that the render state mutex is held. I believe it's safe to call because we're inside a block holding the mutex: https://github.com/ghostty-org/ghostty/blob/3548acfac63e7674b5e25896f6b393474fe8ea65/src/Surface.zig#L3702-L3704

Original Behavior: (first without ctrl, then with ctrl)

https://github.com/user-attachments/assets/f9236c44-bea4-4be8-a54b-24d5ae24b2e7

New Behavior: (first without ctrl, then with ctrl, then pasting)

https://github.com/user-attachments/assets/1e7fa1a9-236e-471d-9504-c820c68600bb

mkasberg avatar Oct 21 '25 23:10 mkasberg