—#!/usr/bin/env perl
use
strict;
use
warnings;
GetOptions(
\
my
%opt
,
qw/
lib|I=s
filename|f=s
verbose|v
help|h
/
) or pod2usage(1);
pod2usage(
-exitval
=> 1,
-verbose
=> 2)
if
$opt
{help};
pod2usage(2)
if
grep
{ !
exists
$opt
{
$_
} }
qw/filename/
;
STDIN->blocking(0);
my
$script_text
=
do
{
local
$/; <STDIN> };
my
(
$script_fh
,
$script
) = tempfile();
if
(
defined
$script_text
) {
$script_fh
->
(
$script_text
);
}
else
{
copy
$opt
{filename} =>
$script_fh
;
}
$script_fh
->
close
;
chdir
dirname
$opt
{filename};
chomp
(
my
$git_root
= `git rev-parse --show-toplevel`);
chdir
$git_root
if
-d
$git_root
;
my
(
$runner_fh
,
$runner
) = tempfile();
my
(
$shebang
) =
do
{
open
my
$fh
,
'<'
,
$script
or
die
$!;
local
$/;
<
$fh
>;
};
my
$bin
;
(
$bin
) =
$shebang
=~ /^
#!(\S*)/ if defined $shebang;
# $bin is NOT `env`, use the binary itself
if
(
defined
$bin
&& basename(
$bin
) ne
'env'
) {
$runner_fh
->
(
<<EOS);
export PERL5LIB=@{[$opt{lib} // '']}:\$PERL5LIB
$bin -c $script
EOS
# Otherwise, it should use perl resolved by $PATH and plenv.
}
else
{
$runner_fh
->
(
<<EOS);
#!/bin/bash
if which plenv > /dev/null; then
eval "\$(plenv init -)"
fi
if which direnv > /dev/null; then
eval "\$(direnv export bash)"
fi
export PERL5LIB=@{[$opt{lib} // '']}:\$PERL5LIB
perl -c $script
EOS
}
$runner_fh
->
close
;
my
$error
=
qr{^(.*)\sat\s(.*)\sline\s(\d+)(\.|,\snear\s\".*\"?)$}
;
open
my
$fh
,
"sh $runner 2>&1 |"
or
die
$!;
while
(<
$fh
>) {
if
$opt
{verbose};
chomp
;
if
(
my
(
$message
,
$extracted_file
,
$lineno
,
$rest
) = /
$error
/) {
next
unless
$extracted_file
eq
$script
;
$message
.=
$rest
if
$rest
=~ s/^,//;
"$script:$lineno:$message\n"
;
}
}
close
$fh
;
__END__
=head1 NAME
efm-perl - perl -c executable with errorformat friendly outputs.
=head1 SYNOPSIS
efm-perl [options]
Options:
--filename, -f [filename] Filename to lint. This is mandatory.
--lib, -I [paths] Additional paths for $PERL5LIB.
--verbose, -v Print all outputs.
--help, -h Show help message.
# load the script from -f option
efm-perl -f /path/to/script.pl
# load the script from STDIN but filter out by filename from -f option
cat /tmp/script.pl | efm-perl -f /path/to/script.pl
=head1 OPTIONS
=over 4
=item B<--lib>, B<-I>
Additional paths for C<PERL5LIB>
=item B<--filename>, B<-f>
Filename to lint. This is mandatory.
=item B<--verbose>, B<-v>
Print out all outputs. Without this, it shows errors only.
=item B<--help>, B<-h>
Print a help message.
=back
=head1 DESCRIPTION
This is a tiny script to use with L<mattn/efm-langserver|https://github.com/mattn/efm-langserver>.
It parses C<perl -c> outputs and arrange them to errorformat-friendly ones.
For efm-langserver, set config.yaml as below.
tools:
efm-perl: &efm-perl
lint-command: efm-perl -f ${INPUT}
lint-ignore-exit-code: true
lint-stdin: true
lint-formats:
- '%f:%l:%m'
languages:
perl:
- <<: *efm-perl
=head1 LICENSE
Copyright (C) delphinus.
This library is free software; you can redistribute it and/or modify
it under the same terms as Perl itself.
=head1 AUTHOR
delphinus <me@delphinus.dev>