Skip to content

Commit

Permalink
support matching of different tokens via regexes
Browse files Browse the repository at this point in the history
This patch implements a match registry that can provide a set of
different regular expressions to be registered in the terminal.

This not only allows us to perform correct matching of more complex URLs
but also file links, email addresses, VoIP links, man pages and numbers.

LICENSE NOTES

This includes code taken from gnome-terminal, which is licensed under
GPLv3. According to the [compatibility matrix][1] of the GNU GPL license
FAQ this means that existing code in tilda can remain "GPLv2 or later"
licensed, but the combined code is now licensed under "GPLv3 or later".

Fixes: #405

[1]: https://www.gnu.org/licenses/gpl-faq.html#AllCompatibility
  • Loading branch information
lanoxx committed Nov 1, 2020
1 parent 6906144 commit f855ae4
Show file tree
Hide file tree
Showing 8 changed files with 478 additions and 103 deletions.
2 changes: 2 additions & 0 deletions src/Makefile.am
Original file line number Diff line number Diff line change
Expand Up @@ -53,7 +53,9 @@ src_tilda_SOURCES = \
src/tilda-keybinding.c src/tilda-keybinding.h \
src/tilda-cli-options.c src/tilda-cli-options.h \
src/tilda-context-menu.c src/tilda-context-menu.h \
src/tilda-match-registry.c src/tilda-match-registry.h \
src/tilda-palettes.h src/tilda-palettes.c \
src/tilda-regex.h \
src/tilda-search-box.c src/tilda-search-box.h \
src/tilda_terminal.h src/tilda_terminal.c \
src/tilda_window.h src/tilda_window.c \
Expand Down
12 changes: 5 additions & 7 deletions src/tilda-context-menu.c
Original file line number Diff line number Diff line change
Expand Up @@ -142,8 +142,8 @@ on_selection_done (GtkWidget *widget, TildaContextMenu * context_menu)
tilda_context_menu_free (context_menu);
}

void
tilda_context_menu_popup (tilda_window *tw, tilda_term *tt, GdkEvent * event)
GtkWidget *
tilda_context_menu_popup (tilda_window *tw, tilda_term *tt, char * match, TerminalURLFlavor flavor)
{
DEBUG_FUNCTION ("popup_menu");
DEBUG_ASSERT (tw != NULL);
Expand All @@ -152,6 +152,7 @@ tilda_context_menu_popup (tilda_window *tw, tilda_term *tt, GdkEvent * event)
TildaContextMenu * context_menu = g_new0 (TildaContextMenu, 1);
context_menu->tw = tw;
context_menu->tt = tt;
context_menu->match = g_strdup (match);

GtkBuilder *builder = gtk_builder_new ();

Expand Down Expand Up @@ -192,9 +193,6 @@ tilda_context_menu_popup (tilda_window *tw, tilda_term *tt, GdkEvent * event)
g_action_map_add_action_entries (G_ACTION_MAP (action_group),
entries_for_tilda_terminal, G_N_ELEMENTS (entries_for_tilda_terminal), tt);

char * match = vte_terminal_match_check_event (VTE_TERMINAL (tt->vte_term), event, NULL);
context_menu->match = g_strdup (match);

g_action_map_add_action_entries (G_ACTION_MAP (action_group),
entries_for_regex, G_N_ELEMENTS (entries_for_regex), context_menu->match);

Expand All @@ -221,10 +219,10 @@ tilda_context_menu_popup (tilda_window *tw, tilda_term *tt, GdkEvent * event)
g_signal_connect (G_OBJECT (menu), "unmap", G_CALLBACK (on_popup_hide), context_menu);
g_signal_connect (G_OBJECT (menu), "selection-done", G_CALLBACK (on_selection_done), context_menu);

gtk_menu_popup_at_pointer (GTK_MENU (menu), event);

g_object_unref (action_group);
g_object_unref (builder);

return menu;
}

static void
Expand Down
4 changes: 2 additions & 2 deletions src/tilda-context-menu.h
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@
#include "tilda_terminal.h"
#include "tilda_window.h"

void
tilda_context_menu_popup (tilda_window *tw, tilda_term *tt, GdkEvent * event);
GtkWidget *
tilda_context_menu_popup (tilda_window *tw, tilda_term *tt, char * match, TerminalURLFlavor flavor);

#endif
143 changes: 143 additions & 0 deletions src/tilda-match-registry.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,143 @@
#include "tilda-match-registry.h"
#include "tilda-regex.h"

#define PCRE2_CODE_UNIT_WIDTH 0
#include <pcre2.h>

typedef struct {
const char *pattern;
TerminalURLFlavor flavor;
} MatchPattern;

static const MatchPattern match_patterns[] = {
{ REGEX_URL_AS_IS, TILDA_MATCH_FLAVOR_AS_IS },
{ REGEX_URL_HTTP, TILDA_MATCH_FLAVOR_DEFAULT_TO_HTTP },
{ REGEX_URL_FILE, TILDA_MATCH_FLAVOR_AS_IS },
{ REGEX_URL_VOIP, TILDA_MATCH_FLAVOR_VOIP_CALL },
{ REGEX_EMAIL, TILDA_MATCH_FLAVOR_EMAIL },
{ REGEX_NEWS_MAN, TILDA_MATCH_FLAVOR_AS_IS },
{ REGEX_NUMBER, TILDA_MATCH_FLAVOR_NUMBER }
};

typedef struct {
VteRegex * regex;
TerminalURLFlavor flavor;
int tag;
} RegistryEntry;

static void
tilda_match_registry_add (TildaMatchRegistry * registry,
const MatchPattern * pattern_item,
guint32 flags, GError ** error);

static void registry_entry_free (gpointer data)
{
RegistryEntry * entry = data;

vte_regex_unref (entry->regex);

g_slice_free (RegistryEntry, data);
}

TildaMatchRegistry *
tilda_match_registry_new ()
{
GError * error;
guint32 flags;
TildaMatchRegistry * registry = g_new0 (TildaMatchRegistry, 1);

registry->entries = NULL;

flags = PCRE2_CASELESS | PCRE2_MULTILINE;

for (guint i = 0; i < G_N_ELEMENTS (match_patterns); i++)
{
const MatchPattern * pattern_item = match_patterns + i;

error = NULL;

tilda_match_registry_add (registry, pattern_item, flags, &error);

if (error) {
g_critical ("Could not register match pattern: %s", error->message);
g_error_free (error);
}
}

return registry;
}

/**
* tilda_match_registry_for_each:
* @registry: An instance of a TildaMatchRegistry.
* @callback: A function to call for each item in the registry.
* @user_data: user data to pass to the function.
*/
/**
* TildaMatchHookFunc:
* @regex: The VteRegex begin enumerated.
* @user_data: The user data passed to tilda_match_registry_for_each()
*
* Declares a type of function that can be passed to
* tilda_match_registry_for_each() to perform an action on each item
* in the registry.
*
* Returns: A tag to be stored with the regex.
*/
void tilda_match_registry_for_each (TildaMatchRegistry * registry, TildaMatchHookFunc callback, gpointer user_data)
{
GList * entries = registry->entries;

for (GList * item = entries; item; item = item->next)
{
RegistryEntry * entry = item->data;

gint tag = callback (entry->regex, user_data);

entry->tag = tag;
}
}

static void
tilda_match_registry_add (TildaMatchRegistry * registry,
const MatchPattern *pattern_item, guint32 flags, GError ** error)
{
VteRegex * regex = vte_regex_new_for_match (pattern_item->pattern, -1, flags, error);

RegistryEntry * entry = g_slice_new0 (RegistryEntry);

entry->flavor = pattern_item->flavor;
entry->regex = regex;
entry->tag = -1;

registry->entries = g_list_append (registry->entries, entry);
}

TerminalURLFlavor
tilda_match_registry_get_flavor_for_tag (TildaMatchRegistry * registry,
gint tag)
{
GList * entries = registry->entries;

if (entries == NULL) {
return TILDA_MATCH_FLAVOR_LAST;
}

for (GList * item = entries; item; item = item->next)
{
RegistryEntry * entry = item->data;

if (entry->tag == tag) {
return entry->flavor;
}
}

return TILDA_MATCH_FLAVOR_LAST;
}

void tilda_match_registry_free (TildaMatchRegistry * registry)
{
g_list_free_full (registry->entries, registry_entry_free);

g_free (registry);
}
34 changes: 34 additions & 0 deletions src/tilda-match-registry.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
#ifndef TILDA_MATCH_REGISTRY_H
#define TILDA_MATCH_REGISTRY_H

#include <glib.h>
#include <vte/vte.h>

typedef enum {
TILDA_MATCH_FLAVOR_AS_IS,
TILDA_MATCH_FLAVOR_DEFAULT_TO_HTTP,
TILDA_MATCH_FLAVOR_VOIP_CALL,
TILDA_MATCH_FLAVOR_EMAIL,
TILDA_MATCH_FLAVOR_NUMBER,
TILDA_MATCH_FLAVOR_LAST
} TerminalURLFlavor;

typedef struct {
GList *entries;
} TildaMatchRegistry;

typedef int (*TildaMatchHookFunc)(VteRegex * regex, gpointer user_data);

TildaMatchRegistry * tilda_match_registry_new (void);

void tilda_match_registry_for_each (TildaMatchRegistry * registry,
TildaMatchHookFunc callback,
gpointer user_data);

TerminalURLFlavor
tilda_match_registry_get_flavor_for_tag (TildaMatchRegistry * registry,
gint tag);

void tilda_match_registry_free (TildaMatchRegistry * registry);

#endif
Loading

0 comments on commit f855ae4

Please sign in to comment.