3

I'm looking for a terminal plugin/extension that would allow me to detect files path in terminal output and open them in a text editor by clicking on them. The perfect solution would open the file at the given line.

/home/dell/pcl/2d/include/pcl/2d/impl/keypoint.hpp:233: warning: no uniquely matching class member found for void pcl::keypoint::imageElementMultiply(ImageType &output, ImageType &input1, ImageType &input2)

In the example above I would be able to click on /home/dell/pcl/2d/include/pcl/2d/impl/keypoint.hpp:233 and I would open the file with Gedit (or whatever) at line 233.

  • what's wrong with cd and nano ? – Alvar Apr 15 '14 at 10:23
  • When you just have to change 2/3 characters in a file for X files at a given line; copy/paste and nano is not productive. – Victor Lamoine Apr 15 '14 at 10:43
  • 1
    If you are more interested in batch replacing the same 2/3 characters in X files then your problem has several (automated) solutions. If it's your case, please open a new question detailing the pattern to look for and the type of files. – Sylvain Pineau Apr 15 '14 at 12:52
3

I though, I may need such option myself. AFAIK, gnome-terminal does not support plug-ins.

I'm using Ubuntu 14.04, gnome-terminal 3.6.2. I didn't test for enough time, expect bugs.

  1. Download source & build dependencies

    sudo apt-get build-dep gnome-terminal
    apt-get source gnome-terminal
    
  2. Add support for paths

    src/terminal-screen.h, add FLAVOR_DEFAULT_TO_FILE enum type for file paths

    typedef enum {
      FLAVOR_AS_IS,
      FLAVOR_DEFAULT_TO_HTTP,
      FLAVOR_VOIP_CALL,
      FLAVOR_EMAIL,
      FLAVOR_LP,
      FLAVOR_DEFAULT_TO_FILE
    } TerminalURLFlavour;
    

    src/terminal-screen.c, add path regex (it's not perfect, may need some tuning)

    static const TerminalRegexPattern url_regex_patterns[] = {
      { SCHEME "//(?:" USERPASS "\\@)?" HOST PORT URLPATH, FLAVOR_AS_IS, G_REGEX_CASELESS },
      { "(?:www|ftp)" HOSTCHARS_CLASS "*\\." HOST PORT URLPATH , FLAVOR_DEFAULT_TO_HTTP, G_REGEX_CASELESS  },
      { "(?:callto:|h323:|sip:)" USERCHARS_CLASS "[" USERCHARS ".]*(?:" PORT "/[a-z0-9]+)?\\@" HOST, FLAVOR_VOIP_CALL, G_REGEX_CASELESS  },
      { "(?:mailto:)?" USERCHARS_CLASS "[" USERCHARS ".]*\\@" HOSTCHARS_CLASS "+\\." HOST, FLAVOR_EMAIL, G_REGEX_CASELESS  },
      { "(?:news:|man:|info:)[[:alnum:]\\Q^_{|}~!\"#$%&'()*+,./;:=?`\\E]+", FLAVOR_AS_IS, G_REGEX_CASELESS  },
      { "(?:lp: #)[[:digit:]]+", FLAVOR_LP, G_REGEX_CASELESS  },
      { "((~/)|(\\.\\./)|(\\./)|(/))+[^\\n\\t\\r\\v\\0 !$`&*()+:]+[^\\n\\t\\r\\v\\0 !$`&*()+:?.,;\"'\\]\\[<>#{}(]", FLAVOR_DEFAULT_TO_FILE, G_REGEX_CASELESS },
    };
    

    src/terminal-util.c, compose correct URL by adding file:// prefix

      switch (flavor)
        {
        case FLAVOR_DEFAULT_TO_HTTP:
          uri = g_strdup_printf ("http://%s", orig_url);
          break;
        case FLAVOR_EMAIL:
          if (g_ascii_strncasecmp ("mailto:", orig_url, 7) != 0)
        uri = g_strdup_printf ("mailto:%s", orig_url);
          else
        uri = g_strdup (orig_url);
          break;
        case FLAVOR_VOIP_CALL:
        case FLAVOR_AS_IS:
          uri = g_strdup (orig_url);
          break;
        case FLAVOR_LP:
          uri = terminal_util_get_lp_url (orig_url);
          break;
        case FLAVOR_DEFAULT_TO_FILE:
          uri = g_strdup_printf ("file://%s", orig_url);
          break;    
        default:
          uri = NULL;
          g_assert_not_reached ();
        }
    

    src/terminal-window.c, resolve ~ and relative paths (./ & ../)

    static void
    popup_open_url_callback (GtkAction *action,
                             TerminalWindow *window)
    {
      TerminalWindowPrivate *priv = window->priv;
      TerminalScreenPopupInfo *info = priv->popup_info;
    
      if (info == NULL)
        return;
    
      if (info->flavour==FLAVOR_DEFAULT_TO_FILE){
        if (info->string[0]=='~') {
          char* current_dir_full=terminal_util_resolve_relative_path (g_get_home_dir(), &(info->string)[2]);
          terminal_util_open_url (GTK_WIDGET (window), current_dir_full, info->flavour,
                                gtk_get_current_event_time ());
        } else {
          char* current_dir=terminal_screen_get_current_dir_with_fallback (info->screen);
          char* current_dir_full=terminal_util_resolve_relative_path (current_dir, info->string);
          terminal_util_open_url (GTK_WIDGET (window), current_dir_full, info->flavour,
                                gtk_get_current_event_time ());
        }
      }
      else {
        terminal_util_open_url (GTK_WIDGET (window), info->string, info->flavour,
                              gtk_get_current_event_time ());
      }
    }
    

    ...

      show_link = info->string != NULL && (info->flavour == FLAVOR_AS_IS ||
                                           info->flavour == FLAVOR_DEFAULT_TO_HTTP ||
                                           info->flavour == FLAVOR_LP ||
                                           info->flavour == FLAVOR_DEFAULT_TO_FILE );
    

    ...

    static gboolean
    screen_match_clicked_cb (TerminalScreen *screen,
                             const char *match,
                             int flavour,
                             guint state,
                             TerminalWindow *window)
    {
      TerminalWindowPrivate *priv = window->priv;
    
      if (screen != priv->active_screen)
        return FALSE;
    
      gtk_widget_grab_focus (GTK_WIDGET (screen));
    
      if (flavour==FLAVOR_DEFAULT_TO_FILE){
        if (match[0]=='~') {
          char* current_dir_full=terminal_util_resolve_relative_path (g_get_home_dir(), &(match)[2]);
          terminal_util_open_url (GTK_WIDGET (window), current_dir_full, flavour,
                                gtk_get_current_event_time ());
        } else {
          char* current_dir=terminal_screen_get_current_dir_with_fallback (screen);
          char* current_dir_full=terminal_util_resolve_relative_path (current_dir, match);
          terminal_util_open_url (GTK_WIDGET (window), current_dir_full, flavour,
                                gtk_get_current_event_time ());
        }
      }
      else {
        terminal_util_open_url (GTK_WIDGET (window), match, flavour,
                                gtk_get_current_event_time ());
      }
    
      return TRUE;
    }
    
  3. Build & install

    cd gnome-terminal-3.6.2/
    ./configure
    make
    make install
    
  • 1
    3. Build & install: ./configure first :) Thanks a lot for the work invovled, it works great! – Victor Lamoine Oct 27 '14 at 10:40
2

Only links can be opened from a terminal (right-click -> Open Link), basically you'd need to prefix your file path with the full URI:

/home/dell/pcl/2d/include/pcl/2d/impl/keypoint.hpp

becoming (just add the file:// prefix):

file:///home/dell/pcl/2d/include/pcl/2d/impl/keypoint.hpp

enter image description here

Note: This command will give you the absolute path URI to a file:

echo file://$(readlink -f <your file>)

Personally gedit /home/dell/pcl/2d/include/pcl/2d/impl/keypoint.hpp is probably the best option.

  • I just found a little bit better: gedit +233 /home/dell/pcl/2d/include/pcl/2d/impl/keypoint.hpp I would like an integrated solution to avoid copy/paste etc. – Victor Lamoine Apr 15 '14 at 9:48
  • I don't think that what you're requesting is actually supported in a terminal. As I said only plain URI are click-able. – Sylvain Pineau Apr 15 '14 at 10:01
  • 3
    @VictorL as Sylavain told you this is a ridiculously complex way. If you want to change specific characters on specific lines, you should never need to actually open the file in an editor. Please post a new question asking how to do what you actually need to do. What you describe is trivial to automate in a way that you can process thousands of files in just a couple of seconds. – terdon Apr 15 '14 at 16:41
  • 1
    The topic is related to compiling & doxygen. I mostly need to open .hpp files and correct tags etc. for a huge documentation. Human reading of surrounding code + intervention is irreplaceable here. – Victor Lamoine Apr 16 '14 at 8:21

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.