Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

OSC 8 Support #1197

Closed
rockorager opened this issue Jan 2, 2024 · 18 comments · Fixed by #1928
Closed

OSC 8 Support #1197

rockorager opened this issue Jan 2, 2024 · 18 comments · Fixed by #1928

Comments

@rockorager
Copy link
Collaborator

Ghostty should support OSC8 Hyperlinks

Some general implementation considerations and thoughts that go beyond the reference:

  • Links are generally rare. A look aside table would be appropriate, with each cell requiring only an index into that ArrayList. This could probably be a u8
  • Hyperlinks should be defined per-screen. I believe we can clear the hyperlink storage when exiting the alt screen. The primary screen should retain the list of hyperlinks for the life of the screen (any old link could be scrolled into and require us to know the ID and target)
  • My preference would be that OSC hyperlinks always show a dotted underline, and on hover show the normal hover underline. This would be unique to Ghostty but IMO is a huge benefit. In other terminals, applications need to style these cells separately on their own (and basically none of them do), leaving users with no idea when a hyperlink is present
  • Given that hyperlinks are rare and to keep the per-cell byte count low, the index value should be as small as possible, considering alignment. u8 seems appropriate but given the lifetime of some primary screens may be too small.
  • The cursor also needs an OSC 8 field. The OSC8 sequence is in effect for any cell the cursor paints, meaning after the OSC 8 opener we add this as an effective "attribute" to the cursor. For example, this is valid and works in terminals which support OSC 8:
printf '\x1B[3;3H\x1B]8;;https://example.org\x1B\\Hyperlink Text\x1B[HMore, non-consecutive text\x1B]8;;\x1B\\
@gpanders
Copy link
Member

gpanders commented Jan 2, 2024

My preference would be that OSC hyperlinks always show a dotted underline, and on hover show the normal hover underline. This would be unique to Ghostty but IMO is a huge benefit. In other terminals, applications need to style these cells separately on their own (and basically none of them do), leaving users with no idea when a hyperlink is present

Would you consider it acceptable to only do this on the primary screen? You mentioned applications, which leads me to think you are also suggesting doing this for alt screen, but whenever e.g. Neovim eventually implements OSC 8 support, we would want the ability to style this ourselves (using whatever highlight groups the user has defined).

@rockorager
Copy link
Collaborator Author

Would you consider it acceptable to only do this on the primary screen? You mentioned applications, which leads me to think you are also suggesting doing this for alt screen, but whenever e.g. Neovim eventually implements OSC 8 support, we would want the ability to style this ourselves (using whatever highlight groups the user has defined).

Yeah, that could be a good option. My main thought around default styling is that browsers style hyperlinks by default, and terminals (probably) should too. The difficulty in terminals is overriding defaults - there isn't a great way to do that vs a browser with CSS.

This is just a preference of mine though, and by no means is any part of default styling required functionality.

@gpanders
Copy link
Member

gpanders commented Jan 2, 2024

Could also do some kind of heuristic like "if no other SGR is applied then draw some default underline".

@rockorager
Copy link
Collaborator Author

Could also do some kind of heuristic like "if no other SGR is applied then draw some default underline".

I was thinking that too - that's probably the best way to deal with it. If a CLI or otherwise has any sort of style to it, better assume it was intentional but no style gets some default applied (personally I style them like browser hyperlinks anywhere I can...blue with underline)

@rockorager
Copy link
Collaborator Author

Another consideration: Some sort of hint for the target location when hovered would be incredibly helpful

@mitchellh
Copy link
Contributor

Just noting I'm supportive of this feature generally, but I do want to do the cell state refactor first. I'll keep OSC 8 in mind as best as I can as I do it. I'm working on this now but it'll be a while.

If someone wants to contribute OSC 8 to the existing (current) implementation and is able to do so in a way that doesn't negatively impact performance when OSC 8 is not in use, then I'd accept that as well. Please check-in periodically though since this is a big feature.

@rockorager
Copy link
Collaborator Author

It would be a nice UI feature to somehow show the OSC target (on hover or some other event)

@mitchellh
Copy link
Contributor

mitchellh commented Jul 3, 2024

I'm just adding some notes here since the specification is underspecified and the implementations I've found vary somewhat wildly. I'm adding notes for myself so I can think about how I want this to be behave.

Specifying IDs

  • iTerm2 doesn't seem to support this at all
  • Kitty supports this as expected
osc "8;id=bar;http://example.com"
printf "exam"
osc "8;;"
printf "[]"
osc "8;id=bar;http://example.com"
printf "ple"
osc "8;;"
echo

Hover highlights both parts in Kitty.

No IDs

  • iTerm2 only highlights contiguous URLs with the same URL
  • Kitty highlights all URLs anywhere on the viewport with the same URL
  • If you specify no-ID and then an ID with the same URL in two contiguous cells, both iTerm2 and Kitty split them

I like iTerm2's behavior here.

osc "8;;http://example.com"
printf "A"
osc "8;;"
osc "8;;http://example.com"
printf "B"
osc "8;;"
osc "8;;http://example.com"
printf "C"
osc "8;;"
echo
echo "Not a link."
echo

osc "8;;http://example.com"
printf "Another"
osc "8;;"
echo

@mitchellh
Copy link
Contributor

mitchellh commented Jul 3, 2024

Save/Restore Cursor

OSC8 does not appear to interact with save/restore cursor (i.e. it is not saved, it is not cleared)

For Ghostty, I plan to mimic this behavior.

osc "8;id=foo;http://example.com"
printf "\0337"
printf "save"
sleep 5
printf "\0338"
printf "restore"
osc "8;;"
echo

(Save and restore are both linked)

Alt Screen

  • Kitty clears OSC8 state on screen changes it appears, neither links work below
  • iTerm2 doesn't reset OSC8 state on screen change so both are linked below

For Ghostty, I believe OSC8 state should be unique per screen and swapping screens should reset the OSC8 state.

osc "8;id=foo;http://example.com"
csi "?1049h"
printf "in"
sleep 5
csi "?1049l"
printf "out"
osc "8;;"
echo

@mitchellh
Copy link
Contributor

image

Progress 😄 I've full OSC8 parsing -> terminal state -> renderer working. They aren't clickable yet, no configuration, and no hints to where the links go. Lots of work to do yet but this is still a large amount of foundational work out of the way.

@mitchellh
Copy link
Contributor

The osc8 branch is now working, except for last mile UX improvements. If anyone has OSC8 workloads, I'd love some testing on that branch. I expect bugs.

For now, OSC8 links behave identically to regex-matched hyperlinks: you must press ctrl (Linux) or command (macOS) to get hovering to work. If you're in a mouse capture program (like Neovim) you must also press shift.

There is no indication of what URL a link goes to, that's still a TODO in the branch. Beyond UI things like that, the core functionality should work.

@mitchellh
Copy link
Contributor

The OSC8 branch is now feature complete for the initial feature set I want to support. I added bottom-left (browser-style) hints to where URLs go. This works on both macOS and Linux/GTK:

CleanShot.2024-07-06.at.10.22.53.mp4

I want to improve this in the future. A community member suggested a discord style domain warning popup and allowlist, configurability on domains would be neat, etc. I don't want to push too much into the initial feature support PR though.

@jcollie
Copy link
Collaborator

jcollie commented Jul 7, 2024

UI nitpick: if there is an active overlay, and the mouse cursor moves into the overlay area, you can't access a URL that is underneath the overlay. The overlay should shift so that the overlay is not underneath the mouse cursor.

Screencast.from.2024-07-06.23-22-30.webm

@jcollie
Copy link
Collaborator

jcollie commented Jul 7, 2024

UI nitpick: If the mouse cursor is over an auto-detected URL, for consistency's sake the URL overlay should be activated even though the URL is displayed in full on the screen.

@mitchellh
Copy link
Contributor

UI nitpick: If the mouse cursor is over an auto-detected URL, for consistency's sake the URL overlay should be activated even though the URL is displayed in full on the screen.

Done.

@mitchellh
Copy link
Contributor

UI nitpick: if there is an active overlay, and the mouse cursor moves into the overlay area, you can't access a URL that is underneath the overlay. The overlay should shift so that the overlay is not underneath the mouse cursor.

Good catch. Fixed this in both macOS and GTK.

@gpanders
Copy link
Member

gpanders commented Jul 7, 2024

Mentioned in Discord already, but I noticed that occasionally the URL overlay sticks around in the following scenario:

  1. In the alternate screen,
  2. With the mouse hovered over a URL,
  3. Press the URL + mouse capture key combination (Ctrl+Shift on Linux, Cmd+Shift on macOS),
  4. Release the keys without moving the mouse

I cannot reproduce this on the primary screen at all, and this does not reproduce 100% of the time. But I have been able to reproduce reliably on both Linux and macOS.

Screencast.from.2024-07-07.12-10-49.webm

@mitchellh
Copy link
Contributor

Mentioned in Discord already, but I noticed that occasionally the URL overlay sticks around in the following scenario:

Fixed! This was related to mouse capture.

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 a pull request may close this issue.

4 participants