Last active
December 20, 2015 19:58
-
-
Save Naddiseo/6187045 to your computer and use it in GitHub Desktop.
$ cat .gitattributes *.py filter=pyspace
$ cat .gitconfig
[filter "pyspace"] smudge = cat clean = pyspace.pl --file %f required
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#!/usr/bin/perl | |
use strict; | |
use warnings; | |
use 5.10.0; | |
use Getopt::Long; | |
use Data::Dumper; | |
my $filename; | |
my $line_count = 0; | |
my @lines = (); | |
my @tmp = (); | |
my $reported_filename; | |
GetOptions("file=s", => \$reported_filename) or die("Error in command line args $!"); | |
$filename = shift @ARGV; | |
if ($filename) { | |
print "opening $filename"; | |
open my $fp, $filename or die "Failed to open '$filename': $!"; | |
while (<$fp>) { chomp; push @lines, $_; } | |
close $fp; | |
$reported_filename = $filename if not $reported_filename; | |
} | |
else { | |
$filename = '<STDIN>'; | |
while (<>) { chomp; push @lines, $_; } | |
} | |
=pod | |
Preprocessing: if a line ends in a backslash, then the following line does not | |
follow the same tabbing patterns | |
=cut | |
my $in_string = 0; | |
my $qq = ''; | |
my $last_was_continuuing = 0; | |
sub check_str { | |
my $q = shift @_; | |
if ($qq ne '' && $q eq $qq && !$in_string) { | |
$in_string = 0; | |
} | |
elsif ($q ne '' && !$in_string) { | |
$qq = $q; | |
$in_string = 1; | |
} | |
} | |
for my $line (@lines) { | |
my $i = 0; | |
my ($c1, $c2, $c3); | |
if ($in_string) { | |
$line = "\2$line"; | |
} | |
elsif ($last_was_continuuing) { | |
$line = "\1$line"; | |
} | |
while ($i < length $line) { | |
$c1 = substr $line, $i, 1; | |
if ($c1 eq '"' or $c1 eq "'") { | |
$c2 = substr $line, $i+1, 1; | |
if ($c2 eq $c1) { | |
$c3 = substr $line, $i+2, 1; | |
if ($c3 eq $c1) { | |
# triple quotes | |
check_str($c1 x 3); | |
$i += 2 | |
} | |
else { | |
# double quotes | |
check_str($c1 x 2); | |
$i += 1 | |
} | |
} | |
else { | |
# single quotes | |
check_str($c1); | |
} | |
} | |
$i++; | |
} | |
$last_was_continuuing = $line =~ /^.*?\\\s*(?:#.*)?$/; | |
#print("continue=$last_was_continuuing, in_string=$in_string, line=\"$line\"\n"); | |
unshift @tmp, $line; | |
} | |
@lines = @tmp; | |
@tmp = (); | |
$line_count = scalar @lines; | |
=pod | |
Our tabbing rules follow a simple rule: | |
If a line is completely whitespace, then it should be indented the same as | |
the following non-whitespace-only line. | |
Algorithm: | |
for each line in file from end to beginning: | |
if line is not whitespace: | |
set ntabs = get_indent(line) | |
else: | |
line = '\t' * ntabs + nontabs | |
=cut | |
my $ntabs = 0; | |
my $last_was_empty = 0; | |
my $l = 0; | |
for my $line (@lines) { | |
$l++; | |
if (substr($line, 0, 1) eq "\2") { | |
# a string | |
unshift @tmp, substr $line, 1; | |
$last_was_empty = 0; | |
} | |
elsif ($line =~ m/^\x01?\s*$/) { | |
if (!$last_was_empty) { | |
unshift @tmp, ("\t" x $ntabs); | |
} | |
$last_was_empty = 1; | |
} | |
elsif ($line =~ m/^(\x01)?([ ]*)((?:.*)|(?:#.*))$/) { | |
my ($continuation, $indent, $content) = ($1, $2, $3); | |
if ($continuation) { | |
my $alignment = ''; | |
# Just assume that the tabber is correct in these cases | |
=pod | |
if ($indent =~ m/^\t*$/) { | |
# All tabs | |
if (length($indent) > $ntabs) { | |
$alignment = "\t" x (length($indent) - $ntabs); | |
} | |
} | |
elsif ($indent =~ m/^\t+(\s*)$/) { | |
# tab indent, space alignment | |
$alignment = $1; | |
} | |
elsif ($indent =~ m/^\s*$/) { | |
# All spaces, assume 4 spaces/tab | |
$alignment = " " x (length($indent) - ($ntabs * 4)); | |
} | |
=cut | |
unshift @tmp, $indent . $content; | |
} | |
else { | |
$ntabs = estimateTabs($indent, $line_count - $l + 1, $content); | |
unshift @tmp, ("\t" x $ntabs) . $content; | |
} | |
$last_was_empty = 0; | |
} | |
else { | |
die "Unknown line '$line'"; | |
} | |
} | |
if ($filename and $filename ne '<STDIN>') { | |
open my $fh, '>', "$filename.tmp" or die $!; | |
print $fh join "\n", @tmp, ''; | |
close $fh; | |
} | |
else { | |
print join "\n", @tmp, ''; | |
} | |
sub estimateTabs { | |
my $indent = shift; | |
my $lineno = shift; | |
my $content = shift; | |
if ($indent =~ m/[^\t]/) { | |
my $spaces = length($indent); | |
if ($spaces % 4 == 0) { | |
return $spaces / 4; | |
} | |
elsif ($spaces % 8 == 0) { | |
return $spaces / 8; | |
} | |
elsif ($spaces % 6 == 0) { | |
return $spaces / 6; | |
} | |
elsif ($spaces % 2 == 0) { | |
return $spaces / 2; | |
} | |
elsif ($spaces == 0) { | |
return 0; | |
} | |
else { | |
die "Unknown indent size '$indent' in $reported_filename:$lineno, content=\"$content\""; | |
} | |
} | |
return length($indent); | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment