[gnome-terminal] app: Show useful information about numbers on right click
- From: Egmont Koblinger <egmontkob src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [gnome-terminal] app: Show useful information about numbers on right click
- Date: Fri, 23 Oct 2015 22:49:06 +0000 (UTC)
commit b2fd6a0a25ac65e3ee835bfd531443b20a19e901
Author: Egmont Koblinger <egmont gmail com>
Date: Sat Oct 24 00:43:23 2015 +0200
app: Show useful information about numbers on right click
Add infrastructure for matching extra regexes on right click.
When clicked on a number, add a new entry in the popup menu: group the
digits by 3, perform dec/hex conversion, and convert to kibi/mebi/etc.
https://bugzilla.gnome.org/show_bug.cgi?id=741728
src/terminal-screen.c | 75 +++++++++++++++++++++++++++++++-
src/terminal-screen.h | 4 +-
src/terminal-util.c | 112 +++++++++++++++++++++++++++++++++++++++++++++++++
src/terminal-util.h | 2 +
src/terminal-window.c | 10 ++++-
src/terminal.xml | 1 +
6 files changed, 199 insertions(+), 5 deletions(-)
---
diff --git a/src/terminal-screen.c b/src/terminal-screen.c
index a30726e..6eae7ab 100644
--- a/src/terminal-screen.c
+++ b/src/terminal-screen.c
@@ -152,6 +152,9 @@ static void terminal_screen_icon_title_changed (VteTerminal *vte_terminal
static void update_color_scheme (TerminalScreen *screen);
+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);
@@ -188,13 +191,21 @@ static const TerminalRegexPattern url_regex_patterns[] = {
{ "(?:news:|man:|info:)[-[:alnum:]\\Q^_{|}~!\"#$%&'()*+,./;:=?`\\E]+", FLAVOR_AS_IS, TRUE },
};
+static const TerminalRegexPattern extra_regex_patterns[] = {
+ { "(0[Xx][[:xdigit:]]+|[[:digit:]]+)", FLAVOR_NUMBER, FALSE },
+};
+
#ifdef WITH_PCRE2
static VteRegex **url_regexes;
+static VteRegex **extra_regexes;
#else
static GRegex **url_regexes;
+static GRegex **extra_regexes;
#endif
static TerminalURLFlavor *url_regex_flavors;
+static TerminalURLFlavor *extra_regex_flavors;
static guint n_url_regexes;
+static guint n_extra_regexes;
/* See bug #697024 */
#ifndef __linux__
@@ -594,6 +605,8 @@ terminal_screen_class_init (TerminalScreenClass *klass)
n_url_regexes = G_N_ELEMENTS (url_regex_patterns);
precompile_regexes (url_regex_patterns, n_url_regexes, &url_regexes, &url_regex_flavors);
+ n_extra_regexes = G_N_ELEMENTS (extra_regex_patterns);
+ precompile_regexes (extra_regex_patterns, n_extra_regexes, &extra_regexes, &extra_regex_flavors);
/* This fixes bug #329827 */
settings = terminal_app_get_global_settings (terminal_app_get ());
@@ -1445,6 +1458,7 @@ terminal_screen_popup_info_unref (TerminalScreenPopupInfo *info)
g_object_unref (info->screen);
g_weak_ref_clear (&info->window_weak_ref);
g_free (info->url);
+ g_free (info->number_info);
g_slice_free (TerminalScreenPopupInfo, info);
}
@@ -1482,7 +1496,8 @@ static void
terminal_screen_do_popup (TerminalScreen *screen,
GdkEventButton *event,
char *url,
- int url_flavor)
+ int url_flavor,
+ char *number_info)
{
TerminalScreenPopupInfo *info;
@@ -1492,6 +1507,7 @@ terminal_screen_do_popup (TerminalScreen *screen,
info->timestamp = event->time;
info->url = url; /* adopted */
info->url_flavor = url_flavor;
+ info->number_info = number_info; /* adopted */
g_signal_emit (screen, signals[SHOW_POPUP_MENU], 0, info);
terminal_screen_popup_info_unref (info);
@@ -1506,11 +1522,13 @@ terminal_screen_button_press (GtkWidget *widget,
GTK_WIDGET_CLASS (terminal_screen_parent_class)->button_press_event;
gs_free char *url = NULL;
int url_flavor = 0;
+ gs_free char *number_info = NULL;
guint state;
state = event->state & gtk_accelerator_get_default_mod_mask ();
url = terminal_screen_check_match (screen, (GdkEvent*)event, &url_flavor);
+ terminal_screen_check_extra (screen, (GdkEvent*)event, &number_info);
if (url != NULL &&
(event->button == 1 || event->button == 2) &&
@@ -1536,15 +1554,17 @@ terminal_screen_button_press (GtkWidget *widget,
if (button_press_event && button_press_event (widget, event))
return TRUE;
- terminal_screen_do_popup (screen, event, url, url_flavor);
+ terminal_screen_do_popup (screen, event, url, url_flavor, number_info);
url = NULL; /* adopted to the popup info */
+ number_info = NULL; /* detto */
return TRUE;
}
else if (!(event->state & (GDK_CONTROL_MASK | GDK_MOD1_MASK)))
{
/* do popup on shift+right-click */
- terminal_screen_do_popup (screen, event, url, url_flavor);
+ terminal_screen_do_popup (screen, event, url, url_flavor, number_info);
url = NULL; /* adopted to the popup info */
+ number_info = NULL; /* detto */
return TRUE;
}
}
@@ -1907,6 +1927,55 @@ terminal_screen_check_match (TerminalScreen *screen,
return NULL;
}
+static void
+terminal_screen_check_extra (TerminalScreen *screen,
+ GdkEvent *event,
+ char **number_info)
+{
+ guint i;
+ char **matches;
+ gboolean flavor_number_found = FALSE;
+
+ matches = g_newa (char *, n_extra_regexes);
+
+ if (
+#ifdef WITH_PCRE2
+ vte_terminal_event_check_regex_simple(
+#else
+ vte_terminal_event_check_gregex_simple(
+#endif
+ VTE_TERMINAL (screen),
+ event,
+ extra_regexes,
+ n_extra_regexes,
+ 0,
+ matches))
+ {
+ for (i = 0; i < n_extra_regexes; i++)
+ {
+ if (matches[i] != NULL)
+ {
+ /* Store the first match for each flavor, free all the others */
+ switch (extra_regex_flavors[i])
+ {
+ case FLAVOR_NUMBER:
+ if (!flavor_number_found)
+ {
+ *number_info = terminal_util_number_info (matches[i]);
+ flavor_number_found = TRUE;
+ }
+ g_free (matches[i]);
+ break;
+ default:
+ g_free (matches[i]);
+ }
+ }
+ }
+ }
+
+ return NULL;
+}
+
/**
* terminal_screen_has_foreground_process:
* @screen:
diff --git a/src/terminal-screen.h b/src/terminal-screen.h
index 5ac7f4c..be1e765 100644
--- a/src/terminal-screen.h
+++ b/src/terminal-screen.h
@@ -30,7 +30,8 @@ typedef enum {
FLAVOR_AS_IS,
FLAVOR_DEFAULT_TO_HTTP,
FLAVOR_VOIP_CALL,
- FLAVOR_EMAIL
+ FLAVOR_EMAIL,
+ FLAVOR_NUMBER,
} TerminalURLFlavor;
/* Forward decls */
@@ -139,6 +140,7 @@ struct _TerminalScreenPopupInfo {
TerminalScreen *screen;
char *url;
TerminalURLFlavor url_flavor;
+ char *number_info;
guint button;
guint state;
guint32 timestamp;
diff --git a/src/terminal-util.c b/src/terminal-util.c
index 973bd19..ce354a1 100644
--- a/src/terminal-util.c
+++ b/src/terminal-util.c
@@ -26,6 +26,7 @@
#include <time.h>
#include <unistd.h>
#include <sys/types.h>
+#include <langinfo.h>
#include <errno.h>
#include <glib.h>
@@ -951,3 +952,114 @@ terminal_util_bind_mnemonic_label_sensitivity (GtkWidget *widget)
(GtkCallback) terminal_util_bind_mnemonic_label_sensitivity,
NULL);
}
+
+/*
+ * "1234567", "'", 3 -> "1'234'567"
+ */
+static char *
+add_separators (const char *in, const char *sep, int groupby)
+{
+ int inlen, outlen, seplen, firstgrouplen;
+ char *out, *ret;
+
+ if (in[0] == '\0')
+ return g_strdup("");
+
+ inlen = strlen(in);
+ seplen = strlen(sep);
+ outlen = inlen + (inlen - 1) / groupby * seplen;
+ ret = out = g_malloc(outlen + 1);
+
+ firstgrouplen = (inlen - 1) % groupby + 1;
+ strncpy(out, in, firstgrouplen);
+ in += firstgrouplen;
+ out += firstgrouplen;
+
+ while (*in != '\0') {
+ strncpy(out, sep, seplen);
+ out += seplen;
+ strncpy(out, in, groupby);
+ in += groupby;
+ out += groupby;
+ }
+
+ g_assert(out - ret == outlen);
+ *out = '\0';
+ return ret;
+}
+
+/**
+ * terminal_util_number_info:
+ * @str: a dec or hex number as string
+ *
+ * Returns: (transfer full): Useful info about @str, or %NULL if it's too large
+ */
+char *
+terminal_util_number_info (const char *str)
+{
+ gs_free char *decstr = NULL;
+ gs_free char *hextmp = NULL;
+ gs_free char *hexstr = NULL;
+ gs_free char *magnitudestr = NULL;
+ unsigned long long num;
+ gboolean exact = TRUE;
+ gboolean hex = FALSE;
+ const char *thousep;
+
+ errno = 0;
+ /* Deliberately not handle octal */
+ if (str[1] == 'x' || str[1] == 'X') {
+ num = strtoull(str + 2, NULL, 16);
+ hex = TRUE;
+ } else {
+ num = strtoull(str, NULL, 10);
+ }
+ if (errno) {
+ return NULL;
+ }
+
+ /* No use in dec-hex conversion for so small numbers */
+ if (num < 10) {
+ return NULL;
+ }
+
+ /* Group the decimal digits */
+ thousep = nl_langinfo(THOUSEP);
+ if (thousep[0] != '\0') {
+ /* If thousep is nonempty, use printf's magic which can handle
+ more complex separating logics, e.g. 2+2+2+3 for some locales */
+ decstr = g_strdup_printf("%'llu", num);
+ } else {
+ /* If, however, thousep is empty, override it with a space so that we
+ do always group the digits (that's the whole point of this feature;
+ the choice of space guarantees not conflicting with the decimal separator) */
+ gs_free char *tmp = g_strdup_printf("%llu", num);
+ thousep = " ";
+ decstr = add_separators(tmp, thousep, 3);
+ }
+
+ /* Group the hex digits by 4 using the same nonempty separator */
+ hextmp = g_strdup_printf("%llx", num);
+ hexstr = add_separators(hextmp, thousep, 4);
+
+ /* Find out the human-readable magnitude, e.g. 15.99 Mi */
+ if (num >= 1024) {
+ int power = 0;
+ while (num >= 1024 * 1024) {
+ power++;
+ if (num % 1024 != 0)
+ exact = FALSE;
+ num /= 1024;
+ }
+ /* Show 2 fraction digits, always rounding downwards. Printf rounds floats to the nearest representable
value,
+ so do the calculation with integers until we get 100-fold the desired value, and then switch to
float. */
+ if (100 * num % 1024 != 0)
+ exact = FALSE;
+ num = 100 * num / 1024;
+ magnitudestr = g_strdup_printf(" %s %.2f %ci", exact ? "=" : "≈", (double) num / 100, "KMGTPE"[power]);
+ } else {
+ magnitudestr = g_strdup("");
+ }
+
+ return g_strdup_printf(hex ? "0x%2$s = %1$s%3$s" : "%s = 0x%s%s", decstr, hexstr, magnitudestr);
+}
diff --git a/src/terminal-util.h b/src/terminal-util.h
index b3f9df1..b8447f7 100644
--- a/src/terminal-util.h
+++ b/src/terminal-util.h
@@ -89,6 +89,8 @@ void terminal_g_settings_set_rgba_palette (GSettings *settings,
void terminal_util_bind_mnemonic_label_sensitivity (GtkWidget *widget);
+char *terminal_util_number_info (const char *str);
+
G_END_DECLS
#endif /* TERMINAL_UTIL_H */
diff --git a/src/terminal-window.c b/src/terminal-window.c
index e7e7e9c..b3c2649 100644
--- a/src/terminal-window.c
+++ b/src/terminal-window.c
@@ -2051,7 +2051,7 @@ popup_clipboard_targets_received_cb (GtkClipboard *clipboard,
TerminalScreen *screen = info->screen;
GtkWidget *popup_menu;
GtkAction *action;
- gboolean can_paste, can_paste_uris, show_link, show_email_link, show_call_link;
+ gboolean can_paste, can_paste_uris, show_link, show_email_link, show_call_link, show_number_info;
window = terminal_screen_popup_info_ref_window (info);
if (window == NULL ||
@@ -2072,6 +2072,7 @@ popup_clipboard_targets_received_cb (GtkClipboard *clipboard,
show_link = info->url != NULL && (info->url_flavor == FLAVOR_AS_IS || info->url_flavor ==
FLAVOR_DEFAULT_TO_HTTP);
show_email_link = info->url != NULL && info->url_flavor == FLAVOR_EMAIL;
show_call_link = info->url != NULL && info->url_flavor == FLAVOR_VOIP_CALL;
+ show_number_info = info->number_info != NULL;
action = gtk_action_group_get_action (priv->action_group, "PopupSendEmail");
gtk_action_set_visible (action, show_email_link);
@@ -2085,6 +2086,10 @@ popup_clipboard_targets_received_cb (GtkClipboard *clipboard,
gtk_action_set_visible (action, show_link);
action = gtk_action_group_get_action (priv->action_group, "PopupCopyLinkAddress");
gtk_action_set_visible (action, show_link);
+ action = gtk_action_group_get_action (priv->action_group, "PopupNumberInfo");
+ gtk_action_set_label (action, info->number_info);
+ gtk_action_set_sensitive (action, FALSE);
+ gtk_action_set_visible (action, show_number_info);
action = gtk_action_group_get_action (priv->action_group, "PopupCopy");
gtk_action_set_sensitive (action, vte_terminal_get_has_selection (VTE_TERMINAL (screen)));
@@ -2604,6 +2609,9 @@ terminal_window_init (TerminalWindow *window)
{ "PopupCopyLinkAddress", NULL, N_("_Copy Link Address"), NULL,
NULL,
G_CALLBACK (popup_copy_url_callback) },
+ { "PopupNumberInfo", NULL, "", NULL,
+ NULL,
+ NULL },
{ "PopupTerminalProfiles", NULL, N_("P_rofiles") },
{ "PopupCopy", "edit-copy", N_("Copy"), "",
NULL,
diff --git a/src/terminal.xml b/src/terminal.xml
index d2065b3..cbf21cc 100644
--- a/src/terminal.xml
+++ b/src/terminal.xml
@@ -82,6 +82,7 @@
<menuitem action="PopupCopyCallAddress" />
<menuitem action="PopupOpenLink" />
<menuitem action="PopupCopyLinkAddress" />
+ <menuitem action="PopupNumberInfo" />
<separator />
<menuitem action="PopupNewTerminal" />
<separator />
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]