]> git.donarmstrong.com Git - perltidy.git/commitdiff
improved vertical alignment when just two lines
authorSteve Hancock <perltidy@users.sourceforge.net>
Tue, 18 Jun 2019 17:56:37 +0000 (10:56 -0700)
committerSteve Hancock <perltidy@users.sourceforge.net>
Tue, 18 Jun 2019 17:56:37 +0000 (10:56 -0700)
lib/Perl/Tidy/VerticalAligner.pm
t/snippets/align26.in
t/snippets/align30.in
t/snippets/expect/align26.def
t/snippets/expect/align30.def
t/snippets/expect/kgb3.def
t/snippets/expect/kgb3.kgb
t/snippets13.t
t/snippets14.t
t/snippets15.t

index 2a3edc44cf533f8730d9b3bbd33bff3ba209a7f1..c768bab147a86b009c8cb0c4d1d2dbf26d79690b 100644 (file)
@@ -2337,13 +2337,13 @@ sub delete_unmatched_tokens {
     my @i_equals;
     my @min_levels;
 
-    my %token_line_count;
+    my $jmax = @{$rnew_lines}-1;
+
     my %is_good_tok;
 
-    # Step 1A: create a hash of tokens for each line
+    # create a hash of tokens for each line
     my $rline_hashes = [];
     foreach my $line ( @{$rnew_lines} ) {
-       my %seen;
         my $rhash   = {};
         my $rtokens = $line->get_rtokens();
         my $i       = 0;
@@ -2354,10 +2354,6 @@ sub delete_unmatched_tokens {
            my $raw_tok="";
            my $desc="";
            if ($tok =~ /^(\D+)(\d+)(.*)/) { $raw_tok=$1; $lev = $2; $desc=$3}
-            if ( !$seen{$tok} ) {
-                $seen{$tok}++;
-                $token_line_count{$tok}++;
-            }
            if (!defined($lev_min) || $lev < $lev_min) {$lev_min=$lev}
 
             $rhash->{$tok} = [ $i, undef, undef, $lev ];
@@ -2373,13 +2369,16 @@ sub delete_unmatched_tokens {
         push @min_levels, $lev_min;
     }
 
-    # Step 1B: compare each line pair and record matches
+    # compare each line pair and record matches
     my $rtok_hash = {};
-    for ( my $jl = 0 ; $jl < @{$rline_hashes} - 1 ; $jl++ ) {
+    my $nr        = 0;
+    for ( my $jl = 0 ; $jl < $jmax ; $jl++ ) {
+       my $nl = $nr;
+       $nr = 0;
         my $jr      = $jl + 1;
         my $rhash_l = $rline_hashes->[$jl];
         my $rhash_r = $rline_hashes->[$jr];
-        my $count   = 0;
+        my $count   = 0; # UNUSED NOW?
         my $ntoks   = 0;
         foreach my $tok ( keys %{$rhash_l} ) {
             $ntoks++;
@@ -2391,78 +2390,104 @@ sub delete_unmatched_tokens {
                 $rhash_r->{$tok}->[1] = $il;
                 if ( $tok ne '#' ) {
                     push @{ $rtok_hash->{$tok} }, ( $jl, $jr );
+                   $nr++;
                 }
             }
         }
-    }
 
-    # Step 1C: Look for if/else/elsif and ternary blocks
-    my $is_full_block; 
-    my $nlines = @{$rnew_lines};
-    my $jmax = $nlines - 1;
-    foreach my $tok ( keys %token_line_count ) {
-        if ( $token_line_count{$tok} == $nlines ) {
-            if ( $tok =~ /^\?/ || $tok =~ /^\{\d+if/ ) {
-               $is_full_block = 1;
-            }
+       # Set a line break if no matching tokens between these lines
+        if ( $nr == 0 && $nl > 0 ) {
+            $rnew_lines->[$jl]->{_end_group} = 1;
         }
     }
 
-    # Step 1D: remove unwanted alignment tokens
-    my $jj   = 0;
-    foreach my $line ( @{$rnew_lines} ) {
-        my $rtokens = $line->get_rtokens();
-        my $rhash   = $rline_hashes->[$jj];
-        my $i       = 0;
-        my $nl      = 0;
-        my $nr      = 0;
-        my $i_eq    = $i_equals[$jj];
-        my @idel;
-        my $imax = @{$rtokens} - 2;
-
-        for ( my $i = 0 ; $i <= $imax ; $i++ ) {
-            my $tok = $rtokens->[$i];
-            next if ( $tok eq '#' );    # shouldn't happen
-            my ( $il, $ir ) = @{ $rhash->{$tok} }[ 1, 2 ];
-            $nl++ if defined($il);
-            $nr++ if defined($ir);
-
-           # always remove unmatched tokens
-            my $delete_me = !defined($il) && !defined($ir);
-
-           # also, if this is a complete ternary or if/elsif/else block,
-           # remove all alignments which are not also in every line
-            $delete_me ||=
-              ( $is_full_block && $token_line_count{$tok} < $nlines );
+    # find subgroups
+    my @subgroups;
+    push @subgroups, [ 0, $jmax ];
+    for ( my $jl = 0 ; $jl < $jmax ; $jl++ ) {
+        if ( $rnew_lines->[$jl]->{_end_group} ) {
+            $subgroups[-1]->[1] = $jl;
+            push @subgroups, [ $jl + 1, $jmax ];
+        }
+    }
 
-            if (
-               $delete_me
-                && is_deletable_token( $tok, $i, $imax, $jj, $i_eq )
+    # Loop to process each subgroups
+    foreach my $item (@subgroups) {
+        my ( $jbeg, $jend ) = @{$item};
 
-                # Patch: do not touch the first line of a terminal match,
-                # such as below, because j_terminal has already been set.
-                #    if ($tag) { $tago = "<$tag>"; $tagc = "</$tag>"; }
-                #    else      { $tago = $tagc = ''; }
-                # But see snippets 'else1.t' and 'else2.t'
-                && !( $jj == 0 && $has_terminal_match && $jmax == 1 )
+        # look for complete ternary or if/elsif/else blocks
+        my $nlines = $jend - $jbeg + 1;
+        my %token_line_count;
+        for ( my $jj = $jbeg ; $jj <= $jend ; $jj++ ) {
+            my %seen;
+            my $line    = $rnew_lines->[$jj];
+            my $rtokens = $line->get_rtokens();
+            foreach my $tok ( @{$rtokens} ) {
+                if ( !$seen{$tok} ) {
+                    $seen{$tok}++;
+                    $token_line_count{$tok}++;
+                }
+            }
+        }
 
-              )
-            {
-                push @idel, $i;
+        # Look for if/else/elsif and ternary blocks
+        my $is_full_block; 
+        foreach my $tok ( keys %token_line_count ) {
+            if ( $token_line_count{$tok} == $nlines ) {
+                if ( $tok =~ /^\?/ || $tok =~ /^\{\d+if/ ) {
+                   $is_full_block = 1;
+                }
             }
         }
 
-        if (@idel) { delete_selected_tokens( $line, \@idel ) }
+        # Leave two lines alone unless they are an if/else or ternary pair.
+        # Alignment of just two lines can be annoying, so it is best to let the
+        # two-line rules decide if they should be aligned.
+        next if ( $nlines <= 2 && !$is_full_block );
+
+        # remove unwanted alignment tokens
+        for ( my $jj = $jbeg ; $jj <= $jend ; $jj++ ) {
+            my $line    = $rnew_lines->[$jj];
+            my $rtokens = $line->get_rtokens();
+            my $rhash   = $rline_hashes->[$jj];
+            my $i       = 0;
+            my $i_eq    = $i_equals[$jj];
+            my @idel;
+            my $imax = @{$rtokens} - 2;
+
+            for ( my $i = 0 ; $i <= $imax ; $i++ ) {
+                my $tok = $rtokens->[$i];
+                next if ( $tok eq '#' );    # shouldn't happen
+                my ( $il, $ir ) = @{ $rhash->{$tok} }[ 1, 2 ];
+
+                # always remove unmatched tokens
+                my $delete_me = !defined($il) && !defined($ir);
+
+                # also, if this is a complete ternary or if/elsif/else block,
+                # remove all alignments which are not also in every line
+                $delete_me ||=
+                  ( $is_full_block && $token_line_count{$tok} < $nlines );
+
+                if (
+                    $delete_me
+                    && is_deletable_token( $tok, $i, $imax, $jj, $i_eq )
+
+                    # Patch: do not touch the first line of a terminal match,
+                    # such as below, because j_terminal has already been set.
+                    #    if ($tag) { $tago = "<$tag>"; $tagc = "</$tag>"; }
+                    #    else      { $tago = $tagc = ''; }
+                    # But see snippets 'else1.t' and 'else2.t'
+                    && !( $jj == $jbeg && $has_terminal_match && $nlines == 2 )
+
+                  )
+                {
+                    push @idel, $i;
+                }
+            }
 
-        # set a break if this is an interior line with possible left matches
-        # but no matches to the right.  We do not do this for the last line
-        # because it could be followed by hanging side comments filtered out
-        # above.
-        if ( $nr == 0 && $nl > 0 && $jj < @{$rnew_lines} - 1 ) {
-            $rnew_lines->[$jj]->{_end_group} = 1;
+            if (@idel) { delete_selected_tokens( $line, \@idel ) }
         }
-        $jj++;
-    }
+    }    # End loop over subgroups
 
     return; 
 }
index f8a5db8b83cd4e955658fa9b74d690564e5510b0..5490bd7d1f4e94fc79c0102275b6a442bd478ce8 100644 (file)
@@ -1,3 +1,4 @@
 #  align first of multiple equals
-$SIG{PIPE}=sub{die"writingtoaclosedpipe"};#1=
-$SIG{HUP}=$SIG{BREAK}=$SIG{INT}=$SIG{TERM};#3=
+$SIG{PIPE}=sub{die"writingtoaclosedpipe"};
+$SIG{BREAK}=$SIG{INT}=$SIG{TERM};
+$SIG{HUP}=\&some_handler;
index 74b64e3eaddd063926dd2de9f4b75eca8954fe9b..3768f7a40c8cbf00d0afd05c8f952045f2b239b7 100644 (file)
@@ -1,3 +1,8 @@
 # commas on lhs align, commas on rhs do not (different subs)
 ($x,$y,$z)=spherical_to_cartesian($rho,$theta,$phi);
 ($rho_c,$theta,$z)=spherical_to_cylindrical($rho_s,$theta,$phi);
+( $r2, $theta2, $z2 )=cartesian_to_cylindrical( $x1, $y1, $z1 );
+
+# two-line if/elsif gets aligned 
+if($i==$depth){$_++;}
+elsif($i>$depth){$_=0;}
index 8e0ceef0cc4a75549c0c39532ddf838a73dbadd1..f75cdeec29e3ce8ee6a009b03d67d87d47947d13 100644 (file)
@@ -1,3 +1,4 @@
 #  align first of multiple equals
-$SIG{PIPE} = sub { die "writingtoaclosedpipe" };      #1=
-$SIG{HUP}  = $SIG{BREAK} = $SIG{INT} = $SIG{TERM};    #3=
+$SIG{PIPE}  = sub { die "writingtoaclosedpipe" };
+$SIG{BREAK} = $SIG{INT} = $SIG{TERM};
+$SIG{HUP}   = \&some_handler;
index 39cd8af099aba3c42892a397da342de1a879644e..ab4b1b6dbb4d03b6844535f5500a3712fe4a3dae 100644 (file)
@@ -1,3 +1,8 @@
 # commas on lhs align, commas on rhs do not (different subs)
-( $x,     $y,     $z ) = spherical_to_cartesian( $rho, $theta, $phi );
-( $rho_c, $theta, $z ) = spherical_to_cylindrical( $rho_s, $theta, $phi );
+( $x,     $y,      $z )  = spherical_to_cartesian( $rho, $theta, $phi );
+( $rho_c, $theta,  $z )  = spherical_to_cylindrical( $rho_s, $theta, $phi );
+( $r2,    $theta2, $z2 ) = cartesian_to_cylindrical( $x1, $y1, $z1 );
+
+# two-line if/elsif gets aligned
+if    ( $i == $depth ) { $_++; }
+elsif ( $i > $depth )  { $_ = 0; }
index 5cdbe88c55c5ce22a5143d609e7e7bee9d326b43..0f805444ee63b95cba475500582d76f81c1fb333 100644 (file)
@@ -1,5 +1,5 @@
 #!/usr/bin/perl -w
-use strict;                # with -kgb, no break after hash bang
+use strict;    # with -kgb, no break after hash bang
 our ( @Changed, $TAP );    # break after isolated 'our'
 use File::Compare;
 use Symbol;
index 159b0c265e635dc99b3cb753c743847a578ce16f..61e1c6d567efc8dc6570dbd77e63c367c52c0257 100644 (file)
@@ -1,5 +1,5 @@
 #!/usr/bin/perl -w
-use strict;                # with -kgb, no break after hash bang
+use strict;    # with -kgb, no break after hash bang
 our ( @Changed, $TAP );    # break after isolated 'our'
 
 use File::Compare;
index eef4c949d02a33cfd0effc18c4f6a1a9a4d6f623..b575f1030f41258e67bf9092ebd9e750ff8ac1be 100644 (file)
@@ -150,8 +150,9 @@ is_deeply( [ \$a,       \$a ], [ \$b,             \$c ] );
 
         'align26' => <<'----------',
 #  align first of multiple equals
-$SIG{PIPE}=sub{die"writingtoaclosedpipe"};#1=
-$SIG{HUP}=$SIG{BREAK}=$SIG{INT}=$SIG{TERM};#3=
+$SIG{PIPE}=sub{die"writingtoaclosedpipe"};
+$SIG{BREAK}=$SIG{INT}=$SIG{TERM};
+$SIG{HUP}=\&some_handler;
 ----------
 
         'align27' => <<'----------',
@@ -389,8 +390,9 @@ is_deeply( [ \$a, \$a ], [ \$b, \$c ] );
             params => "def",
             expect => <<'#18...........',
 #  align first of multiple equals
-$SIG{PIPE} = sub { die "writingtoaclosedpipe" };      #1=
-$SIG{HUP}  = $SIG{BREAK} = $SIG{INT} = $SIG{TERM};    #3=
+$SIG{PIPE}  = sub { die "writingtoaclosedpipe" };
+$SIG{BREAK} = $SIG{INT} = $SIG{TERM};
+$SIG{HUP}   = \&some_handler;
 #18...........
         },
 
index 207683f9760946361d93ca431c81a31467fc197f..72126a68099228063c5e1096b1eb8c4e971a5238 100644 (file)
@@ -750,7 +750,7 @@ sub next_sibling {
             params => "def",
             expect => <<'#10...........',
 #!/usr/bin/perl -w
-use strict;                # with -kgb, no break after hash bang
+use strict;    # with -kgb, no break after hash bang
 our ( @Changed, $TAP );    # break after isolated 'our'
 use File::Compare;
 use Symbol;
@@ -773,7 +773,7 @@ print "break before this line\n";
             params => "kgb",
             expect => <<'#11...........',
 #!/usr/bin/perl -w
-use strict;                # with -kgb, no break after hash bang
+use strict;    # with -kgb, no break after hash bang
 our ( @Changed, $TAP );    # break after isolated 'our'
 
 use File::Compare;
index 388213e2c658ea88fbb85bc15d63ee84c32763df..7998152d1c00e7e086d64345753878f8b3ea8988 100644 (file)
@@ -73,6 +73,11 @@ is( log10(1),  0, "Basic log10(1) test" );
 # commas on lhs align, commas on rhs do not (different subs)
 ($x,$y,$z)=spherical_to_cartesian($rho,$theta,$phi);
 ($rho_c,$theta,$z)=spherical_to_cylindrical($rho_s,$theta,$phi);
+( $r2, $theta2, $z2 )=cartesian_to_cylindrical( $x1, $y1, $z1 );
+
+# two-line if/elsif gets aligned 
+if($i==$depth){$_++;}
+elsif($i>$depth){$_=0;}
 ----------
 
         'bom1' => <<'----------',
@@ -332,8 +337,13 @@ is( log10(1),              0,       "Basic log10(1) test" );
             params => "def",
             expect => <<'#12...........',
 # commas on lhs align, commas on rhs do not (different subs)
-( $x,     $y,     $z ) = spherical_to_cartesian( $rho, $theta, $phi );
-( $rho_c, $theta, $z ) = spherical_to_cylindrical( $rho_s, $theta, $phi );
+( $x,     $y,      $z )  = spherical_to_cartesian( $rho, $theta, $phi );
+( $rho_c, $theta,  $z )  = spherical_to_cylindrical( $rho_s, $theta, $phi );
+( $r2,    $theta2, $z2 ) = cartesian_to_cylindrical( $x1, $y1, $z1 );
+
+# two-line if/elsif gets aligned
+if    ( $i == $depth ) { $_++; }
+elsif ( $i > $depth )  { $_ = 0; }
 #12...........
         },