[gnome-terminal/wip/text-objects: 2/4] Text-Objects: on profile change callback load text-objects vte match.
- From: Christian Persch <chpe src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [gnome-terminal/wip/text-objects: 2/4] Text-Objects: on profile change callback load text-objects vte match.
- Date: Sun, 26 May 2019 21:17:12 +0000 (UTC)
commit fbb25fee07fc7d74146171455e9ab8d39475acd6
Author: Rodolfo Granata <warlock cc gmail com>
Date: Fri May 10 16:42:43 2019 -0400
Text-Objects: on profile change callback load text-objects vte match.
src/profile-editor.c | 4 +-
src/profile-text-objects.c | 101 +++++++++++++++++++++++++++++++++++++++++++--
src/profile-text-objects.h | 18 +++++++-
src/terminal-debug.h | 3 +-
src/terminal-screen.c | 94 ++++++++++++++++++++++++++++++++---------
src/terminal-screen.h | 1 +
src/terminal-util.c | 17 ++++----
7 files changed, 202 insertions(+), 36 deletions(-)
---
diff --git a/src/profile-editor.c b/src/profile-editor.c
index d9f0926f..0609559c 100644
--- a/src/profile-editor.c
+++ b/src/profile-editor.c
@@ -837,7 +837,7 @@ profile_prefs_init (void)
g_free (text);
/* Text-Objects: setup list */
- profile_text_objects_init();
+ profile_text_objects_editor_init ();
}
/* Called each time the user switches away from a profile, so it's no longer being edited */
@@ -1260,7 +1260,7 @@ profile_prefs_load (const char *uuid, GSettings *profile)
G_SETTINGS_BIND_GET | G_SETTINGS_BIND_SET);
/* Text-Object options */
- profile_text_objects_load(profile);
+ profile_text_objects_editor_load (profile);
}
/* Called once per Preferences window, to destroy stuff that doesn't depend on the profile being edited */
diff --git a/src/profile-text-objects.c b/src/profile-text-objects.c
index 23e42f4d..2faafce7 100644
--- a/src/profile-text-objects.c
+++ b/src/profile-text-objects.c
@@ -17,13 +17,16 @@
#include "config.h"
-#include "profile-editor.h"
-#include "profile-text-objects.h"
+#include "terminal-debug.h"
#include "terminal-libgsystem.h"
+#include "terminal-pcre2.h"
#include "terminal-prefs.h"
+#include "profile-editor.h"
+#include "profile-text-objects.h"
#include <glib/gi18n.h>
+
enum {
TEXT_OBJ_NAME = 0,
TEXT_OBJ_MATCH,
@@ -34,7 +37,7 @@ enum {
/* setup the the profile editor's text-object tab */
void
-profile_text_objects_init(void)
+profile_text_objects_editor_init(void)
{
GtkBuilder *builder = the_pref_data->builder;
GtkTreeView *tree_view =
@@ -263,6 +266,17 @@ validate_text_object_cb (GtkEntry *entry, gpointer user_data)
valid &= (end_ptr == text + strlen(text));
}
+ /* Check that the 'match' field contains a valid regex */
+ GtkEntry *regex = GTK_ENTRY (gtk_builder_get_object (builder, "txt-obj-match"));
+ if (entry == regex) {
+ VteRegex *ok = vte_regex_new_for_match (
+ text, -1, PCRE2_UTF | PCRE2_NO_UTF_CHECK | PCRE2_MULTILINE, NULL);
+ valid &= (ok != NULL);
+ if (ok) {
+ vte_regex_unref (ok);
+ }
+ }
+
/* react to input being valid: set warning icon and toggle Save button */
gtk_entry_set_icon_from_icon_name (
entry,
@@ -321,7 +335,7 @@ profile_text_objects_bind(GSettings *profile)
}
void
-profile_text_objects_load(GSettings *profile)
+profile_text_objects_editor_load(GSettings *profile)
{
/* Create the model */
GtkListStore *store = gtk_list_store_new (
@@ -357,3 +371,82 @@ profile_text_objects_load(GSettings *profile)
/* bind buttons and actions */
profile_text_objects_bind (profile);
}
+
+static gint
+_handler_prio_compare(const UrlHandler *a, const UrlHandler *b) {
+ /* Higher priority objects first */
+ return (a->prio < b->prio) ? 1 : ((a->prio > b->prio) ? -1 : 0);
+}
+
+static void
+_free_url_handler(UrlHandler *uh) {
+ if (uh) {
+ g_free(uh->name);
+ g_free(uh->match);
+ g_free(uh->rewrite);
+ g_free(uh);
+ }
+}
+
+void profile_text_objects_free (GSList *handlers) {
+ g_slist_free_full(handlers, (GDestroyNotify)_free_url_handler);
+}
+
+/**
+ * terminal_util_load_url_handlers:
+ *
+ * Load text-object conf from GSettings
+ */
+GSList *
+profile_text_objects_load (GSettings *profile)
+{
+ GError *error = NULL;
+ GSList *handlers = NULL;
+ GVariantIter viter;
+ gchar *name, *match, *rewrite;
+ gint prio;
+
+ /* Load text-objects config from profile gsettings */
+ gs_unref_variant GVariant *text_objects =
+ g_settings_get_value(profile, "text-objects");
+ /* populate the text-object table */
+ g_variant_iter_init (&viter, text_objects);
+ while (g_variant_iter_next (&viter, "{s(ssi)}", &name, &match, &rewrite, &prio)) {
+ UrlHandler *uh = g_new0(UrlHandler, 1);
+ /* adopted: uh members take ownership of strings */
+ uh->name = name;
+ uh->match = match;
+ uh->rewrite = rewrite;
+ uh->prio = prio;
+ uh->regex = vte_regex_new_for_match (uh->match, -1,
+ PCRE2_UTF | PCRE2_NO_UTF_CHECK |
+ PCRE2_MULTILINE, &error);
+ if (error != NULL) {
+ _terminal_debug_print (
+ TERMINAL_DEBUG_TEXT_OBJECTS,
+ "Text-Objects: error compiling regex [%s]\n", name);
+ g_clear_error(&error);
+ _free_url_handler(uh);
+ continue;
+ }
+ if (!vte_regex_jit (uh->regex, PCRE2_JIT_COMPLETE, &error) ||
+ !vte_regex_jit (uh->regex, PCRE2_JIT_PARTIAL_SOFT, &error)) {
+ _terminal_debug_print (
+ TERMINAL_DEBUG_TEXT_OBJECTS,
+ "Text-Objects: failed to JIT regex for [%s]: '%s' %s\n",
+ name, (char*)uh->match, error->message);
+ g_clear_error (&error);
+ _free_url_handler(uh);
+ continue;
+ }
+ _terminal_debug_print (
+ TERMINAL_DEBUG_TEXT_OBJECTS,
+ "Text-Objects: loaded [%s]: %s -> %s\n", name, uh->match, uh->rewrite);
+ /* when vte checks for matches (vte_terminal_match_check_event)
+ * they're returned in order of calling vte_terminal_match_add_regex */
+ handlers =
+ g_slist_insert_sorted(handlers, uh, (GCompareFunc)_handler_prio_compare);
+ }
+
+ return handlers;
+}
diff --git a/src/profile-text-objects.h b/src/profile-text-objects.h
index ae4f328b..9c06877c 100644
--- a/src/profile-text-objects.h
+++ b/src/profile-text-objects.h
@@ -20,11 +20,25 @@
#include <gio/gio.h>
#include <gtk/gtk.h>
+#include <vte/vte.h>
G_BEGIN_DECLS
-void profile_text_objects_init(void);
-void profile_text_objects_load(GSettings *profile);
+typedef struct
+{
+ char *name;
+ char *match;
+ char *rewrite;
+ gint prio;
+ VteRegex *regex;
+ int tag;
+} UrlHandler;
+
+void profile_text_objects_editor_init (void);
+void profile_text_objects_editor_load (GSettings *profile);
+
+GSList *profile_text_objects_load (GSettings *profile);
+void profile_text_objects_free (GSList*);
G_END_DECLS
diff --git a/src/terminal-debug.h b/src/terminal-debug.h
index 0fafcc3a..5795d3b7 100644
--- a/src/terminal-debug.h
+++ b/src/terminal-debug.h
@@ -34,7 +34,8 @@ typedef enum {
TERMINAL_DEBUG_PROCESSES = 1 << 6,
TERMINAL_DEBUG_PROFILE = 1 << 7,
TERMINAL_DEBUG_SETTINGS_LIST = 1 << 8,
- TERMINAL_DEBUG_SEARCH = 1 << 9
+ TERMINAL_DEBUG_SEARCH = 1 << 9,
+ TERMINAL_DEBUG_TEXT_OBJECTS = 1 << 10,
} TerminalDebugFlags;
void _terminal_debug_init(void);
diff --git a/src/terminal-screen.c b/src/terminal-screen.c
index 23134e80..ea01444a 100644
--- a/src/terminal-screen.c
+++ b/src/terminal-screen.c
@@ -59,6 +59,7 @@
#include "terminal-window.h"
#include "terminal-info-bar.h"
#include "terminal-libgsystem.h"
+#include "profile-text-objects.h"
#include "eggshell.h"
@@ -77,6 +78,7 @@ typedef struct
{
int tag;
TerminalURLFlavor flavor;
+ UrlHandler *url_handler;
} TagData;
struct _TerminalScreenPrivate
@@ -94,6 +96,7 @@ struct _TerminalScreenPrivate
int child_pid;
GSList *match_tags;
guint launch_child_source_id;
+ GSList *custom_url_handlers;
};
enum
@@ -155,9 +158,10 @@ static char* terminal_screen_check_hyperlink (TerminalScreen *scree
static void terminal_screen_check_extra (TerminalScreen *screen,
GdkEvent *event,
char **number_info);
-static char* terminal_screen_check_match (TerminalScreen *screen,
- GdkEvent *event,
- int *flavor);
+static char* terminal_screen_check_match (TerminalScreen *screen,
+ GdkEvent *event,
+ int *flavor,
+ UrlHandler **uhandler);
static void terminal_screen_set_override_command (TerminalScreen *screen,
char **argv,
@@ -487,7 +491,7 @@ terminal_screen_class_init (TerminalScreenClass *klass)
g_cclosure_marshal_VOID__OBJECT,
G_TYPE_NONE,
1, G_TYPE_SETTINGS);
-
+
signals[SHOW_POPUP_MENU] =
g_signal_new (I_("show-popup-menu"),
G_OBJECT_CLASS_TYPE (object_class),
@@ -508,7 +512,7 @@ terminal_screen_class_init (TerminalScreenClass *klass)
_terminal_marshal_BOOLEAN__STRING_INT_UINT,
G_TYPE_BOOLEAN,
3, G_TYPE_STRING, G_TYPE_INT, G_TYPE_UINT);
-
+
signals[CLOSE_SCREEN] =
g_signal_new (I_("close-screen"),
G_OBJECT_CLASS_TYPE (object_class),
@@ -699,7 +703,7 @@ terminal_screen_new (GSettings *profile,
return screen;
}
-gboolean
+gboolean
terminal_screen_exec (TerminalScreen *screen,
char **argv,
char **envv,
@@ -824,7 +828,7 @@ terminal_screen_profile_changed_cb (GSettings *profile,
if (!prop_name || prop_name == I_(TERMINAL_PROFILE_BACKSPACE_BINDING_KEY))
vte_terminal_set_backspace_binding (vte_terminal,
g_settings_get_enum (profile, TERMINAL_PROFILE_BACKSPACE_BINDING_KEY));
-
+
if (!prop_name || prop_name == I_(TERMINAL_PROFILE_DELETE_BINDING_KEY))
vte_terminal_set_delete_binding (vte_terminal,
g_settings_get_enum (profile, TERMINAL_PROFILE_DELETE_BINDING_KEY));
@@ -859,6 +863,40 @@ terminal_screen_profile_changed_cb (GSettings *profile,
vte_terminal_set_word_char_exceptions (vte_terminal, word_char_exceptions);
}
+ VteTerminal *terminal = VTE_TERMINAL (screen);
+
+ /* remove old text-object handlers if any */
+ if (priv->custom_url_handlers) {
+ GSList *next = priv->custom_url_handlers;
+ while (next != NULL)
+ {
+ UrlHandler *uh = (UrlHandler*)next->data;
+ next = g_slist_next(next);
+ vte_terminal_match_remove (terminal, uh->tag);
+ }
+ profile_text_objects_free (priv->custom_url_handlers);
+ }
+
+ /* connect new text-object handlers */
+ priv->custom_url_handlers = profile_text_objects_load (profile);
+ if (priv->custom_url_handlers) {
+ GSList *next = priv->custom_url_handlers;
+ while (next != NULL)
+ {
+ UrlHandler *uh = (UrlHandler*)next->data;
+ next = g_slist_next(next);
+ TagData *tag_data;
+ tag_data = g_slice_new (TagData);
+ tag_data->flavor = FLAVOR_CUSTOM_URI;
+ tag_data->tag = vte_terminal_match_add_regex (terminal, uh->regex, 0);
+ uh->tag = tag_data->tag;
+ tag_data->url_handler = uh;
+ vte_terminal_match_set_cursor_type (terminal,
+ tag_data->tag, URL_MATCH_CURSOR);
+ priv->match_tags = g_slist_prepend (priv->match_tags, tag_data);
+ }
+ }
+
g_object_thaw_notify (object);
}
@@ -1538,6 +1576,7 @@ terminal_screen_button_press (GtkWidget *widget,
GTK_WIDGET_CLASS (terminal_screen_parent_class)->button_press_event;
gs_free char *hyperlink = NULL;
gs_free char *url = NULL;
+ UrlHandler *uhandler = NULL;
int url_flavor = 0;
gs_free char *number_info = NULL;
guint state;
@@ -1545,9 +1584,6 @@ terminal_screen_button_press (GtkWidget *widget,
state = event->state & gtk_accelerator_get_default_mod_mask ();
hyperlink = terminal_screen_check_hyperlink (screen, (GdkEvent*)event);
- url = terminal_screen_check_match (screen, (GdkEvent*)event, &url_flavor);
- terminal_screen_check_extra (screen, (GdkEvent*)event, &number_info);
-
if (hyperlink != NULL &&
(event->button == 1 || event->button == 2) &&
(state & GDK_CONTROL_MASK))
@@ -1563,6 +1599,22 @@ terminal_screen_button_press (GtkWidget *widget,
return TRUE; /* don't do anything else such as select with the click */
}
+ url = terminal_screen_check_match (screen, (GdkEvent*)event,
+ &url_flavor, &uhandler);
+ /* try re-writing the URL if its a custom flavor */
+ if (url_flavor == FLAVOR_CUSTOM_URI && uhandler != NULL) {
+ gchar *urltmp = vte_regex_substitute (
+ uhandler->regex,
+ url,
+ uhandler->rewrite,
+ PCRE2_SUBSTITUTE_EXTENDED,
+ NULL);
+ if (urltmp != NULL) {
+ g_free(url);
+ url = urltmp;
+ }
+ }
+
if (url != NULL &&
(event->button == 1 || event->button == 2) &&
(state & GDK_CONTROL_MASK))
@@ -1578,6 +1630,7 @@ terminal_screen_button_press (GtkWidget *widget,
return TRUE; /* don't do anything else such as select with the click */
}
+ terminal_screen_check_extra (screen, (GdkEvent*)event, &number_info);
if (event->type == GDK_BUTTON_PRESS && event->button == 3)
{
if (!(event->state & (GDK_SHIFT_MASK | GDK_CONTROL_MASK | GDK_MOD1_MASK)))
@@ -1618,7 +1671,7 @@ terminal_screen_button_press (GtkWidget *widget,
* Tries to determine the current working directory of the foreground process
* in @screen's PTY, falling back to the current working directory of the
* primary child.
- *
+ *
* Returns: a newly allocated string containing the current working directory,
* or %NULL on failure
*/
@@ -1663,9 +1716,9 @@ terminal_screen_child_exited (VteTerminal *terminal,
screen);
priv->child_pid = -1;
-
+
action = g_settings_get_enum (priv->profile, TERMINAL_PROFILE_EXIT_ACTION_KEY);
-
+
switch (action)
{
case TERMINAL_EXIT_CLOSE:
@@ -1737,8 +1790,8 @@ terminal_screen_drag_data_received (GtkWidget *widget,
{
GdkAtom atom = GDK_POINTER_TO_ATOM (tmp->data);
- g_print ("Target: %s\n", gdk_atom_name (atom));
-
+ g_print ("Target: %s\n", gdk_atom_name (atom));
+
tmp = tmp->next;
}
@@ -1801,7 +1854,7 @@ terminal_screen_drag_data_received (GtkWidget *widget,
char *utf8_data, *newline, *text;
char *uris[2];
gsize len;
-
+
/* MOZ_URL is in UCS-2 but in format 8. BROKEN!
*
* The data contains the URL, a \n, then the
@@ -1838,7 +1891,7 @@ terminal_screen_drag_data_received (GtkWidget *widget,
char *utf8_data, *newline, *text;
char *uris[2];
gsize len;
-
+
/* The data contains the URL, a \n, then the
* title of the web page.
*/
@@ -1942,7 +1995,8 @@ terminal_screen_check_hyperlink (TerminalScreen *screen,
static char*
terminal_screen_check_match (TerminalScreen *screen,
GdkEvent *event,
- int *flavor)
+ int *flavor,
+ UrlHandler **uhandler)
{
TerminalScreenPrivate *priv = screen->priv;
GSList *tags;
@@ -1957,6 +2011,8 @@ terminal_screen_check_match (TerminalScreen *screen,
{
if (flavor)
*flavor = tag_data->flavor;
+ if (uhandler != NULL)
+ *uhandler = tag_data->url_handler;
return match;
}
}
@@ -2016,7 +2072,7 @@ terminal_screen_check_extra (TerminalScreen *screen,
*
* Checks whether there's a foreground process running in
* this terminal.
- *
+ *
* Returns: %TRUE iff there's a foreground process running in @screen
*/
gboolean
diff --git a/src/terminal-screen.h b/src/terminal-screen.h
index ff77fcf7..11349deb 100644
--- a/src/terminal-screen.h
+++ b/src/terminal-screen.h
@@ -32,6 +32,7 @@ typedef enum {
FLAVOR_VOIP_CALL,
FLAVOR_EMAIL,
FLAVOR_NUMBER,
+ FLAVOR_CUSTOM_URI,
} TerminalURLFlavor;
/* Forward decls */
diff --git a/src/terminal-util.c b/src/terminal-util.c
index 72a0d401..3ea70b7c 100644
--- a/src/terminal-util.c
+++ b/src/terminal-util.c
@@ -51,17 +51,17 @@
* @message_format: printf() style format string
*
* Create a #GtkMessageDialog window with the message, and present it, handling its buttons.
- * If @weap_ptr is not #NULL, only create the dialog if <literal>*weap_ptr</literal> is #NULL
- * (and in that * case, set @weap_ptr to be a weak pointer to the new dialog), otherwise just
+ * If @weap_ptr is not #NULL, only create the dialog if <literal>*weap_ptr</literal> is #NULL
+ * (and in that * case, set @weap_ptr to be a weak pointer to the new dialog), otherwise just
* present <literal>*weak_ptr</literal>. Note that in this last case, the message <emph>will</emph>
* be changed.
*/
void
-terminal_util_show_error_dialog (GtkWindow *transient_parent,
+terminal_util_show_error_dialog (GtkWindow *transient_parent,
GtkWidget **weak_ptr,
GError *error,
- const char *message_format,
- ...)
+ const char *message_format,
+ ...)
{
gs_free char *message;
va_list args;
@@ -97,10 +97,10 @@ terminal_util_show_error_dialog (GtkWindow *transient_parent,
}
gtk_window_set_resizable (GTK_WINDOW (dialog), FALSE);
-
+
gtk_widget_show_all (dialog);
}
- else
+ else
{
g_return_if_fail (GTK_IS_MESSAGE_DIALOG (*weak_ptr));
@@ -264,7 +264,7 @@ terminal_util_set_atk_name_description (GtkWidget *widget,
const char *desc)
{
AtkObject *obj;
-
+
obj = gtk_widget_get_accessible (widget);
if (obj == NULL)
@@ -306,6 +306,7 @@ terminal_util_open_url (GtkWidget *parent,
else
uri = g_strdup (orig_url);
break;
+ case FLAVOR_CUSTOM_URI:
case FLAVOR_VOIP_CALL:
case FLAVOR_AS_IS:
uri = g_strdup (orig_url);
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]