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,

Replies are listed 'Best First'.
Re: Etags for Emacs and Moose
by zakame (Pilgrim) on Sep 14, 2016 at 10:59 UTC

    I can't judge if this one would suit you, but I've been using ggtags+GNU Global instead of {c,e}tags, and it seems smarter in the case of multiple variables/functions of same name.

Re: Etags for Emacs and Moose
by LanX (Saint) on Aug 30, 2016 at 10:23 UTC
    > (Similar tool exists for vim, but I'm not familiar with the output format enough to make my script support both the editors.)

    As a side note: it has been a while since I used tags but IIRC does emacs also support ctags (the vi format) =)

    update

    but project management is certainly a thing I have to look into again, I used to store session files per project, but this needs more elaboration.

    Cheers Rolf
    (addicted to the Perl Programming Language and ☆☆☆☆ :)
    Je suis Charlie!