When working on a larger project (50k+ lines), I usually can't remember the structure of the packages and I need some kind of a tool to help me. The simplest but still quite a powerful solution is etags (yes, I use Emacs). It generates a TAGS file that Emacs can use to show where a given subroutine is declared, etc. (Similar tool exists for vim, but I'm not familiar with the output format enough to make my script support both the editors.)

The problem is that the default setting for Perl reports not only all the subroutine declarations, but also declarations of lexical variables (my). I don't need to know where a lexical variable was declared: normally, it's in the same block where the cursor is, maybe one level higher. What I'd like to have, though, are the attributes' accesors that Moo(se) provides; they're declared with has which etags can't handle.

I haven't found a way how to persuade etags to handle multiline declarations, neither have I found any other solution. So, I created a simple script that creates the TAGS file that's more useful for me than the default. It still doesn't handle all the possibilities (different names for setters/getters, builders, delegation, etc.) - you can check the END section for all the constructs it can parse.

The current version of the code is here, but you can find it at GitHub where it might change as I (or you!) add new features.

#!/usr/bin/perl use warnings; use strict; use feature qw{ say }; use List::MoreUtils qw{ any }; use Path::Tiny qw{ path }; sub wanted { my ($path, $state) = @_; return if $path->is_dir || $path !~ /\.p[lm]$/; my $code = $path->slurp; my %found; for my $regex ( qr/^(\s* (sub | method) \s+ (\w+)) /xm, qr/^(\s* (alias) \s+ (\w+)) /xm, qr/^(\s* (has) \s+ (?:["']\+?)? (\w+)) /xm, qr/^(\s* (has) \s+ \[ \s* qw \s* . \s* ([^)\]\/>]+) +) /xm, ) { while ($code =~ /$regex/g) { my ($full, $keyword, $funcs) = ($1, $2, $3); for my $func (split ' ', $funcs) { my $pos = pos($code) - length $full; my $nl_count = substr($code, 0, $pos) =~ tr/\n//; my ($single_line) = $full =~ /(.*\Q$func\E.*)/g; $found{$keyword}{$func} = [$nl_count + 1, $pos, $singl +e_line]; } } } return unless keys %found; say "\cl"; my $string = join "\n", map { my $keyword = $_; map "$found{$keyword}{$_}[2]\x7f\x01" . "$found{$keyword}{$_}[0],$found{$keyword}{$ +_}[1]", keys %{ $found{$keyword} } } keys %found; say $path, ',', 1 + length $string; say $string; } sub main { path('.')->visit(\&wanted, { recurse => 1 }); } main(); =head1 NAME perl-etags.pl =head1 SYNOPSIS cd /project/root && perl-etags.pl > TAGS =head1 DESCRIPTION Creates TAGS file similar to what the command C<etags> produces, but tries to handle C<Moose> keywords as well (C<has>, C<alias>). =head1 AUTHOR (c) 2016 E. Choroba =cut __END__ # Tested on the following: # ------------------------ #!/usr/bin/perl use warnings; use strict; package Etags::Test; use Moose; use MooseX::Aliases; has bare => (is => 'rw'); has 'quoted' => (is => 'rw'); has "double_quoted" => (is => 'rw'); has [qw[ list1 list2 ]] => (is => 'ro'); has [qw[ multi line ]] => (is => 'ro'); sub method {} sub method2 {} alias m2 => 'method2'; use MooseX::Declare; class Etags::Test2 { method method3 (Num $count) {} }

($q=q:Sq=~/;[c](.)(.)/;chr(-||-|5+lengthSq)`"S|oS2"`map{chr |+ord }map{substrSq`S_+|`|}3E|-|`7**2-3:)=~y+S|`+$1,++print+eval$q,q,a,

In reply to Etags for Emacs and Moose by choroba

Title:
Use:  <p> text here (a paragraph) </p>
and:  <code> code here </code>
to format your post, it's "PerlMonks-approved HTML":



  • Posts are HTML formatted. Put <p> </p> tags around your paragraphs. Put <code> </code> tags around your code and data!
  • Titles consisting of a single word are discouraged, and in most cases are disallowed outright.
  • Read Where should I post X? if you're not absolutely sure you're posting in the right place.
  • Please read these before you post! —
  • Posts may use any of the Perl Monks Approved HTML tags:
    a, abbr, b, big, blockquote, br, caption, center, col, colgroup, dd, del, details, div, dl, dt, em, font, h1, h2, h3, h4, h5, h6, hr, i, ins, li, ol, p, pre, readmore, small, span, spoiler, strike, strong, sub, summary, sup, table, tbody, td, tfoot, th, thead, tr, tt, u, ul, wbr
  • You may need to use entities for some characters, as follows. (Exception: Within code tags, you can put the characters literally.)
            For:     Use:
    & &amp;
    < &lt;
    > &gt;
    [ &#91;
    ] &#93;
  • Link using PerlMonks shortcuts! What shortcuts can I use for linking?
  • See Writeup Formatting Tips and other pages linked from there for more info.