From 30bbf529ad3073fd449c7f9331a889b114fad1e1 Mon Sep 17 00:00:00 2001 From: Wynn Wolf Arbor Date: Sat, 28 Mar 2020 15:10:55 +0100 Subject: Add OSC 8 hyperlink support This commit adds support for the OSC 8 hyperlink escape sequence [1]. As this is not a mature feature and there seem to be outstanding security concerns [2], the setting that controls whether or not OSC 8 is interpreted is disabled by default. Just like gnome-terminal, weltschmerz will display a tooltip with the canonicalized URI when hovering over a hyperlink. [1] https://gist.github.com/egmontkob/eb114294efbcd5adb1944c9f3cb5feda [2] https://gist.github.com/egmontkob/eb114294efbcd5adb1944c9f3cb5feda#security --- terminal.vala | 37 ++++++++++++++++++++++++++++--------- 1 file changed, 28 insertions(+), 9 deletions(-) (limited to 'terminal.vala') diff --git a/terminal.vala b/terminal.vala index 99c21ce..5f4f4e0 100644 --- a/terminal.vala +++ b/terminal.vala @@ -25,14 +25,17 @@ class Terminal : Gtk.Overlay { [GtkChild] Gtk.Label infobar_label; [GtkChild] Gtk.Menu standard_context_menu; [GtkChild] Gtk.Menu url_context_menu; + [GtkChild] Gtk.Menu hyperlink_context_menu; [GtkChild] Gtk.MenuItem copy_item; [GtkChild] Gtk.Revealer search_revealer; [GtkChild] Gtk.ScrolledWindow scrolled_window; [GtkChild] Gtk.SearchEntry search_entry; [GtkChild] Vte.Terminal vte; + Gtk.Clipboard clipboard; bool has_search; string url_match; + string hyperlink_match; uint? infobar_timeout_id; double scroll_delta; @@ -45,8 +48,11 @@ class Terminal : Gtk.Overlay { vte.search_set_wrap_around(true); url_context_menu.attach_to_widget(vte, null); + hyperlink_context_menu.attach_to_widget(vte, null); standard_context_menu.attach_to_widget(vte, null); + clipboard = Gtk.Clipboard.get_default(window.get_display()); + try { var regex = new Vte.Regex.for_match(URL_REGEX, URL_REGEX.length, PCRE2_CASELESS | PCRE2_MULTILINE); vte.match_add_regex(regex, 0); @@ -69,6 +75,8 @@ class Terminal : Gtk.Overlay { Gtk.PolicyType policy = conf.scrollbar ? Gtk.PolicyType.AUTOMATIC : Gtk.PolicyType.NEVER; scrolled_window.set_policy(policy, policy); + vte.set_allow_hyperlink(conf.allow_hyperlinks); + vte.set_font(conf.font); var geometry = Gdk.Geometry() { // This must be kept in sync with the padding size in terminal.css @@ -262,9 +270,9 @@ class Terminal : Gtk.Overlay { search_button_down.set_sensitive(has_search); } - void url_match_open() { + void uri_open(string uri) { try { - AppInfo.launch_default_for_uri(url_match, get_display().get_app_launch_context()); + AppInfo.launch_default_for_uri(uri, get_display().get_app_launch_context()); } catch (Error e) { warning(e.message); infobar_show(e.message, Gtk.MessageType.ERROR); @@ -272,13 +280,12 @@ class Terminal : Gtk.Overlay { } [GtkCallback] - void url_match_copy() { - if (url_match == null) { - return; + void uri_copy() { + if (url_match != null) { + clipboard.set_text(url_match, -1); + } else if (hyperlink_match != null) { + clipboard.set_text(hyperlink_match, -1); } - - Gtk.Clipboard clipboard = Gtk.Clipboard.get_default(window.get_display()); - clipboard.set_text(url_match, -1); } void adjust_font_scale(double scale) { @@ -309,9 +316,12 @@ class Terminal : Gtk.Overlay { bool vte_button_press(Gdk.EventButton event) { if (match_button(event, 0, Gdk.BUTTON_SECONDARY)) { url_match = vte.match_check_event(event, null); + hyperlink_match = vte.hyperlink_check_event(event); if (url_match != null) { url_context_menu.popup_at_pointer(event); + } else if (hyperlink_match != null) { + hyperlink_context_menu.popup_at_pointer(event); } else { copy_item.set_sensitive(vte.get_has_selection()); standard_context_menu.popup_at_pointer(event); @@ -326,8 +336,12 @@ class Terminal : Gtk.Overlay { bool vte_button_release(Gdk.EventButton event) { if (match_button(event, 0, Gdk.BUTTON_PRIMARY)) { url_match = vte.match_check_event(event, null); + hyperlink_match = vte.hyperlink_check_event(event); + if (url_match != null && !vte.get_has_selection()) { - url_match_open(); + uri_open(url_match); + } else if (hyperlink_match != null && !vte.get_has_selection()) { + uri_open(hyperlink_match); } } @@ -397,6 +411,11 @@ class Terminal : Gtk.Overlay { return false; } + [GtkCallback] + void vte_hyperlink_hover(string? uri, Gdk.Rectangle? box) { + vte.set_tooltip_text(Utils.normalize_uri(uri)); + } + [GtkCallback] void window_set_title() { string title = null; -- cgit v1.2.3-2-gb3c3