Category: |
Utility Scripts |
Author/Contact Info |
Dr.P <coder@neeley.org> |
Description: |
Takes messy perl code and makes it beautiful. Doesn't matter if former indentation existed, or was done with spaces or tabs. Indent character is a space and indent size is set to 2 by default. These are easy to change near the top of the script.
WARNING: Don't use on anything other than Perl code. Unawanted results will most likely occur.
|
#!/usr/bin/perl -w
use strict;
#
my $SCRIPT_FILE = "indent-perl.pl";
my $SCRIPT_NAME = "Indent-Perl";
my $VERSION = "1.1";
#
# Indent-Perl -- A script to make beautiful any messy perl script.
#
# Created by Dr.P <coder@neeley.org>.
# Birthed of necessity on 01.16.2005.
# Last scrutinized heavily on 02.16.2005.
#
# USAGE: perl indent-perl.pl file_name(s) [-a]
#
# "-a" option makes the program indent empty lines. Use "-h" for usel
+ess help.
#
# Appends ".indented" to file names. This script is meant only to be
+used on
# scripts written in Perl. Using it on any other language will most l
+ikely
# cause unexpected results.
#
# Next version is planned to included modularized handling for the scr
+ipt
# parsing and checking. Should be cool ;)
#
# ~ dr.p
my @files = ();
my $new_fext = ".indented";
my $indent_size = 2;
my $indent_char = ' ';
my %OPTS = (
'help' => 0,
'indent-all' => 0,
'show_fn' => 1,
);
foreach my $fn (@ARGV) {
if ($fn ne '') {
if ($fn eq '-h' || $fn eq '--help') {
$OPTS{'help'} = 1;
}
elsif ($fn eq '-a' || $fn eq '--idnent-all') {
$OPTS{'indent-all'} = 1;
}
elsif (-f $fn) {
push @files, $fn;
}
}
}
if ($OPTS{'help'}) {
print "\n$SCRIPT_NAME $VERSION by Patrick Neeley 2005 <coder\@neeley
+.org>\n";
}
if ($OPTS{'help'} == 1) {
print "\nUSAGE: perl $SCRIPT_NAME [-h|file names] [-a]\n\n".
"-a --indent-all output all lines (even empty ones) with i
+ndent\n".
"-h --help print this help stuff\n".
"\n";
exit(1);
}
if ($#files == -1) {
print "\nNo valid files passed.\nDone.\n";
exit(1);
}
print "\nProcessing files...\n\n";
for (my $i = 0; $i <= $#files; $i++) {
my $fn = $files[$i];
if ($OPTS{'show_fn'}) {
print "$fn\n";
}
if (!(-f $fn)) {
print "File does not exist. Skipping.\n";
}
elsif (!open(NEWFH, ">$fn".$new_fext)) {
print "Could not open file: $!\n";
}
elsif (!open(OLDFH, $fn)) {
print "Could not open file: $!\n";
close(NEWFH);
} else {
my $indent = 0;
my @bracket_stack = ();
my $in_quotes = 0;
my $in_text = 0;
my $text_marker = "";
my @stdregexs = ("\\{[^\\{\\}]*\\}", "\\([^\\(\\)]*\\)");
while (my $orig_line = <OLDFH>)
{
$orig_line =~ s/[\n\r]+//g;
my $line = $orig_line;
# prep the line by removing all unwanted enclosures
# note that the order of the following lines are important, so d
+on't change it
$line =~ s/[\s\t]+//; # no more whitespace, at all
$line =~ s/\\.//g; # no escaped characters
$line =~ s/\"[^\"]*\"//g; # nothing in double quotes
$line =~ s/\'[^\']*\'//g; # single quotes
$line =~ s/\`[^\`]*\`//g; # or back-ticks
$line =~ s/(q[qwxr]?)\{[^\}]*\}//g; # or generic quotes or bra
+ced enclosures
$line =~ s/(q[qwxr]?)\([^\)]*\)//g; # no gq with parens or par
+en enclosures
$line =~ s/(q[qwxr]?)\/[^\/]*\///g; # no gq with slahses or sl
+ashed enclosures
$line =~ s/(q[qwxr]?)\#[^\#]*\#//g; # no gq with pounds or pou
+nd enclosures
$line =~ s/(q[qwxr]?)\|[^\|]*\|//g; # no gq with pipes or pipe
+d enclosures
$line =~ s/(s|m|tr)\/[^\/]*\/[^\/]*\/[gimosx]*//g;
$line =~ s/(s|m|tr)\#[^\#]*\#[^\#]*\#[gimosx]*//g;
$line =~ s/(s|m|tr)\,[^\,]*\,[^\,]*\,[gimosx]*//g;
foreach my $regexp (@stdregexs) {
while ($line =~ /$regexp/) {
$line =~ s/$regexp//g;
}
}
$line =~ s/\/[^\/]*\///g; # lastly, no comments
$line =~ s/\#.*$//g; # lastly, no comments
my $do_indent = 1;
my $skip_processing = 0;
# if we're in a large textual print out ("print <<YADA"), we don
+'t want
# to touch the original lines at all until we're out of it
if ($in_text) {
if ($orig_line eq $text_marker) {
$in_text = 0;
$text_marker = "";
}
$do_indent = 0;
$skip_processing = 1;
}
# similarly, we don't want indentation if we're in quoted text t
+hat takes
# up multiple lines
if (!$in_quotes && ($orig_line =~ /print .*?<< *(\"[^\"]+\"|\'[^
+\']+\'|[^\"\';]+);$/)) {
$text_marker = $1;
$text_marker =~ s/[\"\']//g;
$in_text = 1;
$skip_processing = 1;
}
if ($in_quotes) {
$do_indent = 0;
}
# if we aren't dealing with quoted text of any kind, so we need
+to check
# to see if the line starts off with an ending bracket so that w
+e can
# decrease the indent immediately.
my $did_lbc_undent = 0;
if (!$skip_processing && $#bracket_stack > -1) {
my $lbc = $bracket_stack[-1];
if ($line =~ /^\Q$lbc\E/) {
--$indent;
$did_lbc_undent = 1;
$in_quotes = 0;
$skip_processing = 0;
}
}
# check the indent all command line option
if ($orig_line eq '' && !$OPTS{'indent-all'}) {
$do_indent = 0;
}
# set the current indent string
my $cur_indent = $do_indent ? ($indent_char x ($indent_size * $i
+ndent)): "";
if ($do_indent) {
$orig_line =~ s/^[\t\s]*//;
}
# print the original line with current indentation
print NEWFH $cur_indent.$orig_line."\n";
# if you want to see the mutilated line:
#print NEWFH $cur_indent.$line."\n";
# nothing to do if the mutilated line is empty or $skip_processi
+ng is set
if ($skip_processing || $line eq '') {
next;
}
# this is where I'll stop commenting for now :)
my $pushed = 0;
my $popped = 0;
my @chars = split(//,$line);
for (my $n = 0; $n <= $#chars; $n++) {
my $c = $chars[$n];
if ($c eq '') {
next;
}
if ($#bracket_stack > -1 && $c eq $bracket_stack[-1]) {
pop(@bracket_stack);
$popped = 1;
$in_quotes = 0;
next;
}
if ($n > 1) {
my $c3 = join('', @chars[int($n-2)..int($n)]);
if ($c3 =~ /((qq|qx|qw|qr|tr)[\{\(\|])/) {
push @bracket_stack, &determine_ec($c);
$pushed = 1;
$in_quotes = 1;
next;
}
}
if ($n > 0) {
my $c2 = join('', @chars[int($n-1)..int($n)]);
if ($c2 =~ /((m|s|q)[\{\(\|])/) {
push @bracket_stack, &determine_ec($c);
$pushed = 1;
$in_quotes = 1;
next;
}
}
# now check $c if we got this far
if ($c =~ /[\{\(\"\']/) {
push @bracket_stack, &determine_ec($c);
$pushed = 1;
if ($c =~ /[\"\']/) {
$in_quotes = 1;
}
next;
}
}
if ($popped && !$did_lbc_undent) {
--$indent;
}
if ($pushed) {
++$indent;
}
} # end while
close(OLDFH);
close(NEWFH);
if ($#bracket_stack > -1) {
my $en = ($#bracket_stack + 1);
print " ERROR -- ".$en." unmatched entr".(($en==1)?"y":"ies")."
+: ".join(', ',@bracket_stack)."\n";
}
}
}
print "\nFile list exhausted. Done.\n\n";
exit(1);
sub determine_ec (\$) {
return ($_[0] eq '{')? '}': (($_[0] eq '(')? ')': $_[0]);
}
|
Re: Indent Perl
by dbwiz (Curate) on Jan 17, 2005 at 07:47 UTC
|
| [reply] [Watch: Dir/Any] |
|
Or GNU Emacs cperl-mode, with its nice indent feature?
| [reply] [Watch: Dir/Any] |
|
No, actually, I hadn't. Thanks.
| [reply] [Watch: Dir/Any] |
|
PerlTidy's -fws and -fnl opts don't seem to work on Windows with the latest ActivePerl. That script I pasted does nothing more than indent the code, leaving quoted text that spans multiple lines as-is.
| [reply] [Watch: Dir/Any] |
Re: Indent Perl
by zentara (Archbishop) on Jan 17, 2005 at 12:55 UTC
|
This is what I use after cut'n'pasting code, to tidy it up.
It will leave a *.ERR file if there are syntax errors.
#!/usr/bin/perl -w
use strict;
my $infile = shift;
my $outfile = "$infile.tmp";
open my $infh, '<', $infile or die "Cannot open $infile: $!\n";
open my $outfh, '>>', $outfile or die "Cannot open $outfile: $!\n";
while (<$infh>) {
s/^\s+//g;
s/\s+$//g;
print $outfh $_, "\n" or die "Cannot write to $outfile: $!\n";
}
close $outfh or die "Cannot close $outfile: $!\n";
close $infh or die "Cannot close $infile: $!\n";
system('perltidy', $outfile) == 0 or die "Perltidy failed\n";
rename "$outfile.tdy", $infile or die "Cannot rename $outfile.tdy: $!\
+n";
unlink $outfile or die "Cannot unlink $outfile: $!\n";
chmod 0755, $infile or die "Cannot chmod $infile: $!\n";
I'm not really a human, but I play one on earth.
flash japh
| [reply] [Watch: Dir/Any] [d/l] |
Re: Indent Perl
by Mago (Parson) on Jan 22, 2005 at 07:03 UTC
|
* 4-column indent.
* Opening curly on same line as keyword, if possible, otherwise line up.
* Space before the opening curly of a multi-line BLOCK.
* One-line BLOCK may be put on one line, including curlies.
* No space before the semicolon.
* Semicolon omitted in "short" one-line BLOCK.
* Space around most operators.
* Space around a "complex" subscript (inside brackets).
* Blank lines between chunks that do different things.
* Uncuddled elses.
* No space between function name and its opening parenthesis.
* Space after each comma.
* Long lines broken after an operator (except "and" and "or").
* Space after last parenthesis matching on current line.
* Line up corresponding items vertically.
* Omit redundant punctuation as long as clarity doesn't suffer.
Mago
mago@rio.pm.org
| [reply] [Watch: Dir/Any] |
|
|