[gnome-builder] terminal: allow opening filename:line:column



commit 8dd11ce96037c226592a0e852281fc9f03798f68
Author: Christian Hergert <chergert redhat com>
Date:   Thu Jan 17 21:26:55 2019 -0800

    terminal: allow opening filename:line:column
    
    We try to discover the file from the filename using the resovle_file API
    from the workbench. That is somewhat difficult because we don't have the
    active CWD from the point when the line was printed. So we do a bit of
    discovery in case we don't find it.
    
    We will want to extend this handle some other filename variants such as
    without line or columns. But this is a start.

 src/libide/terminal/ide-terminal.c | 77 +++++++++++++++++++++++++++++++++-----
 1 file changed, 67 insertions(+), 10 deletions(-)
---
diff --git a/src/libide/terminal/ide-terminal.c b/src/libide/terminal/ide-terminal.c
index 185fc2007..12b6eca67 100644
--- a/src/libide/terminal/ide-terminal.c
+++ b/src/libide/terminal/ide-terminal.c
@@ -43,6 +43,12 @@ typedef struct
   GdkEvent   *event;
 } PopupInfo;
 
+typedef struct
+{
+  gint line;
+  gint column;
+} Position;
+
 G_DEFINE_TYPE_WITH_PRIVATE (IdeTerminal, ide_terminal, VTE_TYPE_TERMINAL)
 
 enum {
@@ -57,9 +63,11 @@ enum {
 /* From vteapp.c */
 #define DINGUS1 
"(((gopher|news|telnet|nntp|file|http|ftp|https)://)|(www|ftp)[-A-Za-z0-9]*\\.)[-A-Za-z0-9\\.]+(:[0-9]*)?"
 #define DINGUS2 DINGUS1 "/[-A-Za-z0-9_\\$\\.\\+\\!\\*\\(\\),;:@&=\\?/~\\#\\%]*[^]'\\.}>\\) ,\\\"]"
+#define FILENAME_PLUS_LOCATION "(?<filename>[a-zA-Z0-9\\+\\-\\.\\/_]+):(?<line>\\d+):(?<column>\\d+)"
 
 static guint signals[N_SIGNALS];
-static const gchar *url_regexes[] = { DINGUS1, DINGUS2 };
+static const gchar *url_regexes[] = { DINGUS1, DINGUS2, FILENAME_PLUS_LOCATION };
+static GRegex *filename_regex;
 static const GdkRGBA solarized_palette[] = {
   /*
    * Solarized palette (1.0.0beta2):
@@ -215,6 +223,7 @@ ide_terminal_button_press_event (GtkWidget      *widget,
                                  GdkEventButton *button)
 {
   IdeTerminal *self = (IdeTerminal *)widget;
+  IdeTerminalPrivate *priv = ide_terminal_get_instance_private (self);
 
   g_assert (IDE_IS_TERMINAL (self));
   g_assert (button != NULL);
@@ -237,18 +246,16 @@ ide_terminal_button_press_event (GtkWidget      *widget,
 
       if (pattern != NULL)
         {
-          GtkApplication *app;
-          GtkWindow *focused_window;
+          gboolean ret = FALSE;
 
-          if (NULL != (app = GTK_APPLICATION (g_application_get_default ())) &&
-              NULL != (focused_window = gtk_application_get_active_window (app)))
-            gtk_show_uri_on_window (focused_window,
-                                    pattern,
-                                    gtk_get_current_event_time (),
-                                    NULL);
+          g_free (priv->url);
+          priv->url = g_steal_pointer (&pattern);
+          g_signal_emit (self, signals [OPEN_LINK], 0, &ret);
 
-          return GDK_EVENT_STOP;
+          return ret;
         }
+
+      return GDK_EVENT_STOP;
     }
 
   return GTK_WIDGET_CLASS (ide_terminal_parent_class)->button_press_event (widget, button);
@@ -283,10 +290,36 @@ ide_terminal_copy_link_address (IdeTerminal *self)
   return TRUE;
 }
 
+static void
+ide_terminal_open_link_resolve_cb (GObject      *object,
+                                   GAsyncResult *result,
+                                   gpointer      user_data)
+{
+  IdeWorkbench *workbench = (IdeWorkbench *)object;
+  g_autoptr(GFile) file = NULL;
+  Position *pos = user_data;
+
+  g_assert (IDE_IS_MAIN_THREAD ());
+  g_assert (IDE_IS_WORKBENCH (workbench));
+  g_assert (G_IS_ASYNC_RESULT (result));
+
+  if ((file = ide_workbench_resolve_file_finish (workbench, result, NULL)))
+    ide_workbench_open_at_async (workbench,
+                                 file,
+                                 "editor",
+                                 pos->line,
+                                 pos->column,
+                                 IDE_BUFFER_OPEN_FLAGS_NONE,
+                                 NULL, NULL, NULL);
+
+  g_slice_free (Position, pos);
+}
+
 static gboolean
 ide_terminal_open_link (IdeTerminal *self)
 {
   IdeTerminalPrivate *priv = ide_terminal_get_instance_private (self);
+  g_autoptr(GMatchInfo) match = NULL;
   GtkApplication *app;
   GtkWindow *focused_window;
 
@@ -296,6 +329,27 @@ ide_terminal_open_link (IdeTerminal *self)
   if (ide_str_empty0 (priv->url))
     return FALSE;
 
+  if (g_regex_match (filename_regex, priv->url, 0, &match))
+    {
+      g_autofree gchar *filename = g_match_info_fetch (match, 1);
+      g_autofree gchar *line = g_match_info_fetch (match, 2);
+      g_autofree gchar *column = g_match_info_fetch (match, 3);
+      gint64 lineno = g_ascii_strtoull (line, NULL, 10);
+      gint64 columnno = g_ascii_strtoull (column, NULL, 10);
+      IdeWorkbench *workbench;
+      Position pos = { lineno - 1, columnno - 1 };
+
+      workbench = ide_widget_get_workbench (GTK_WIDGET (self));
+
+      ide_workbench_resolve_file_async (workbench,
+                                        filename,
+                                        NULL,
+                                        ide_terminal_open_link_resolve_cb,
+                                        g_slice_dup (Position, &pos));
+
+      return TRUE;
+    }
+
   if (NULL != (app = GTK_APPLICATION (g_application_get_default ())) &&
       NULL != (focused_window = gtk_application_get_active_window (app)))
     return gtk_show_uri_on_window (focused_window,
@@ -404,6 +458,9 @@ ide_terminal_class_init (IdeTerminalClass *klass)
   klass->select_all = ide_terminal_real_select_all;
   klass->search_reveal = ide_terminal_real_search_reveal;
 
+  filename_regex = g_regex_new (FILENAME_PLUS_LOCATION, 0, 0, NULL);
+  g_assert (filename_regex != NULL);
+
   signals [COPY_LINK_ADDRESS] =
     g_signal_new ("copy-link-address",
                   G_TYPE_FROM_CLASS (klass),


[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]