Home > Software engineering >  Using regexp with etags to parse customized definitions
Using regexp with etags to parse customized definitions

Time:10-28

I have a perl file where some functions are defined using special syntax (Mojolicious):

$app->helper('helper1' => sub {
            print "Hello 1";
        });

$app->helper("helper2" => sub {
            print "Hello 2";
        });

$app->helper(helper3 => sub {
            print "Hello 3";
        });

helper1();
helper2();
helper3();

I managed to create the Perl regexp to capture these definitions:

#!/usr/bin/perl

use strict;
use warnings;
use File::Slurp 'read_file';

my $code = read_file('helpers.pl');

my @matches = $code =~ /\$app\->helper\(['"]?(.*?)['"]? => sub/g;
foreach(@matches)
{
    print "$_\n";
}

Output:

helper1
helper2
helper3

But my attempt to use it in etags failed;

etags -l perl --regex="/\$app\->helper\\\(['\"]\(.*?\)['\"] => sub/" ./helpers.pl

Gives an empty TAGS file. What's wrong?

CodePudding user response:

One of your problems is your shell escapes, eg:

  • "\$xxx" will end up being to $xxx which means EOL in regex.
  • "\-" will in a POSIX shell expand to \-.

You should use single quoted string to hold your pattern, as the only special character in single quotes are single quotes. If the pattern should be:

/\$app->helper\(['"](.*?)['"] => sub/

Then the single quote string would be:

'/\$app->helper\(['\''"](.*?)['\''"] => sub/'

I don't use exuberant-ctags, but Universal Ctags which is never. In Universal Ctags one would need to write:

/\$app->helper\(['"](.*)['"] => sub/\1/

Notice how the non-greedy modifier isn't supported, and how I provided the keyword creation part: \1/ after the pattern.

I'll leave it as an exercise to the reader to enclose the above pattern in single quotes.

CodePudding user response:

Universal Ctags just introduced pcre2 as an optional regular expression engine. If you build a ctags executable from the latest code in the git repository (git clone https://github.com/universal-ctags/ctags.git) with pcre2, you can use non-greedy match. That means the command line Andreas Louv showed may work well.

$ cat /tmp/foo.pl                                                                                                                                                                             
$app->helper('helper1' => sub {                                                                                                                                                               
            print "Hello 1";                                                                                                                                                                  
        });                                                                                                                                                                                   
                                                                                                                                                                                              
$app->helper("helper2" => sub {                                                                                                                                                               
            print "Hello 2";                                                                                                                                                                  
        });                                                                                                                                                                                   
                                                                                                                                                                                              
$app->helper(helper3 => sub {                                                                                                                                                                 
            print "Hello 3";                                                                                                                                                                  
        });                                                                                                                                                                                   
                                                                                                                                                                                              
helper1();                                                                                                                                                                                    
helper2();                                                                                                                                                                                    
helper3();                                                                                                                                                                                    
                                                                                                                                                                                              
$ ./ctags -o - --regex-perl='/\$app->helper\(['\''"]?(.*?)['\''"]? => sub/\1/s/{pcre2}' /tmp/foo.pl                                                                                           
helper1 /tmp/foo.pl     /^$app->helper('helper1' => sub {$/;"   s                                                                                                                             
helper2 /tmp/foo.pl     /^$app->helper("helper2" => sub {$/;"   s                                                                                                                             
helper3 /tmp/foo.pl     /^$app->helper(helper3 => sub {$/;"     s                                                                                                                             
$ ./ctags -e --regex-perl='/\$app->helper\(['\''"]?(.*?)['\''"]? => sub/\1/s/{pcre2}' /tmp/foo.pl                                                                                             
$ cat TAGS                                                                                                                                                                                    
^L                                                                                                                                                                                            
/tmp/foo.pl,133                                                                                                                                                                               
$app->helper('helper1' => sub {^?helper1^A1,0                                                                                                                                                 
$app->helper("helper2" => sub {^?helper2^A5,74                                                                                                                                                
$app->helper(helper3 => sub {^?helper3^A9,148                                                                                                                                                 
$                                                                                             

You can verify you whether pcre2 is linked to your ctags or not.

$ ./ctags --list-features | grep pcre2
pcre2             has pcre2 regex engine
$
  • Related