From: Steve Hancock Date: Tue, 18 Jun 2019 17:56:37 +0000 (-0700) Subject: improved vertical alignment when just two lines X-Git-Tag: 20190915~16 X-Git-Url: https://git.donarmstrong.com/?a=commitdiff_plain;h=19a647977f5c0ec5135fd21474b61e654b12bf74;p=perltidy.git improved vertical alignment when just two lines --- diff --git a/lib/Perl/Tidy/VerticalAligner.pm b/lib/Perl/Tidy/VerticalAligner.pm index 2a3edc44..c768bab1 100644 --- a/lib/Perl/Tidy/VerticalAligner.pm +++ b/lib/Perl/Tidy/VerticalAligner.pm @@ -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 = ""; } - # 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 = ""; } + # 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; } diff --git a/t/snippets/align26.in b/t/snippets/align26.in index f8a5db8b..5490bd7d 100644 --- a/t/snippets/align26.in +++ b/t/snippets/align26.in @@ -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; diff --git a/t/snippets/align30.in b/t/snippets/align30.in index 74b64e3e..3768f7a4 100644 --- a/t/snippets/align30.in +++ b/t/snippets/align30.in @@ -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;} diff --git a/t/snippets/expect/align26.def b/t/snippets/expect/align26.def index 8e0ceef0..f75cdeec 100644 --- a/t/snippets/expect/align26.def +++ b/t/snippets/expect/align26.def @@ -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; diff --git a/t/snippets/expect/align30.def b/t/snippets/expect/align30.def index 39cd8af0..ab4b1b6d 100644 --- a/t/snippets/expect/align30.def +++ b/t/snippets/expect/align30.def @@ -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; } diff --git a/t/snippets/expect/kgb3.def b/t/snippets/expect/kgb3.def index 5cdbe88c..0f805444 100644 --- a/t/snippets/expect/kgb3.def +++ b/t/snippets/expect/kgb3.def @@ -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; diff --git a/t/snippets/expect/kgb3.kgb b/t/snippets/expect/kgb3.kgb index 159b0c26..61e1c6d5 100644 --- a/t/snippets/expect/kgb3.kgb +++ b/t/snippets/expect/kgb3.kgb @@ -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; diff --git a/t/snippets13.t b/t/snippets13.t index eef4c949..b575f103 100644 --- a/t/snippets13.t +++ b/t/snippets13.t @@ -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........... }, diff --git a/t/snippets14.t b/t/snippets14.t index 207683f9..72126a68 100644 --- a/t/snippets14.t +++ b/t/snippets14.t @@ -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; diff --git a/t/snippets15.t b/t/snippets15.t index 388213e2..7998152d 100644 --- a/t/snippets15.t +++ b/t/snippets15.t @@ -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........... },