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

Support styling as a hyperlink #1028

Open
mo8it opened this issue Apr 12, 2024 · 4 comments
Open

Support styling as a hyperlink #1028

mo8it opened this issue Apr 12, 2024 · 4 comments
Labels
enhancement New feature or request

Comments

@mo8it
Copy link
Contributor

mo8it commented Apr 12, 2024

See crossterm-rs/crossterm#602 and https://gist.github.com/egmontkob/eb114294efbcd5adb1944c9f3cb5feda

@mo8it mo8it added the enhancement New feature or request label Apr 12, 2024
@joshka
Copy link
Member

joshka commented Apr 12, 2024

I want this too. I suspect OSC 8 will just work if #902 is fixed.
A super high level on that issue is that the calculation of how many cells to skip needs to take into account that ANSI escape codes might mean that we write many symbols to the same cell.

A full solution to this would be to add a hyperlink widget that has properties for the text and hyperlink so app code can just do:

Hyperlink::new("Google", "https://google.com).render(area, buf);

Alternatively, I think as phrased you might be looking to add the hyperlink as another part of the Style struct, which would allow it to be added to any span/line/text without having to break the flow. Thoughts?

@mo8it
Copy link
Contributor Author

mo8it commented Apr 14, 2024

Thanks for your quick reply 🤗

A widget would be too limiting. I think that this should be part of a Paragraph since such a hyperlink can be part of a longer text and might be broken/wrapped into multiple lines (so not only in one Line).

@joshka
Copy link
Member

joshka commented Apr 25, 2024

To be clear, a Hyperlink Widget as proposed above would accept anything that supports Into<Text>. I'd like eventually to move the wrapping into Text / Line / Span instead of wrapping being implemented in Paragraph only.

@joshka
Copy link
Member

joshka commented Apr 25, 2024

Demo

/// A hyperlink widget that renders a hyperlink in the terminal using [OSC 8].
///
/// [OSC 8]: https://gist.github.com/egmontkob/eb114294efbcd5adb1944c9f3cb5feda
struct Hyperlink<'content> {
    text: Text<'content>,
    url: String,
}

impl<'content> Hyperlink<'content> {
    fn new(text: impl Into<Text<'content>>, url: impl Into<String>) -> Self {
        Self {
            text: text.into(),
            url: url.into(),
        }
    }
}

impl WidgetRef for Hyperlink<'_> {
    fn render_ref(&self, area: Rect, buffer: &mut Buffer) {
        self.text.render_ref(area, buffer);

        // this is a hacky workaround for https://github.com/ratatui-org/ratatui/issues/902, a bug
        // in the terminal code that incorrectly calculates the width of ANSI escape sequences. It
        // works by rendering the hyperlink as a series of 2-character chunks, which is the
        // calculated width of the hyperlink text.
        for (i, two_chars) in self
            .text
            .to_string()
            .chars()
            .chunks(2)
            .into_iter()
            .enumerate()
        {
            let text = two_chars.collect::<String>();
            let hyperlink = format!("\x1B]8;;{}\x07{}\x1B]8;;\x07", self.url, text);
            buffer
                .get_mut(area.x + i as u16 * 2, area.y)
                .set_symbol(hyperlink.as_str());
        }
    }
}

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
enhancement New feature or request
Projects
None yet
Development

No branches or pull requests

2 participants