Skip to content

Instantly share code, notes, and snippets.

@Naddiseo
Last active December 20, 2015 19:58
Show Gist options
  • Save Naddiseo/6187045 to your computer and use it in GitHub Desktop.
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
#!/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