From: Steve Hancock Date: Mon, 12 Nov 2018 20:20:07 +0000 (-0800) Subject: minor improvements to two-line equality matches X-Git-Tag: 20181117~24 X-Git-Url: https://git.donarmstrong.com/?a=commitdiff_plain;h=8d90d7b66c900c4b0302a1258c7ed7a421c4b6ee;p=perltidy.git minor improvements to two-line equality matches --- diff --git a/lib/Perl/Tidy/VerticalAligner.pm b/lib/Perl/Tidy/VerticalAligner.pm index 5a823bb8..9c89efd1 100644 --- a/lib/Perl/Tidy/VerticalAligner.pm +++ b/lib/Perl/Tidy/VerticalAligner.pm @@ -361,16 +361,6 @@ sub valign_input { # side comments. Tabs in these fields can mess up the column counting. # The log file warns the user if there are any such tabs. -## my ( -## $level, $level_end, -## $indentation, $rfields, -## $rtokens, $rpatterns, -## $is_forced_break, $outdent_long_lines, -## $is_terminal_ternary, $is_terminal_statement, -## $do_not_pad, $rvertical_tightness_flags, -## $level_jump, -## ) = @_; - my ( $rline_hash, $rfields, $rtokens, $rpatterns ) = @_; my $level = $rline_hash->{level}; my $level_end = $rline_hash->{level_end}; @@ -1595,11 +1585,110 @@ sub fix_terminal_else { NO_MATCH: ##print "no match jmax=$jmax max=$maximum_field_index $group_list_type lines=$maximum_line_index token=$old_rtokens->[0]\n"; - my_flush(); + + # Make one last effort to retain a match of certain statements + my $match = salvage_equality_matches($new_line, $old_line); + my_flush() unless($match); return; } } +sub salvage_equality_matches { + my ( $new_line, $old_line ) = @_; + + # Reduce the complexity of the two lines if it will allow us to retain + # alignment of some common alignments, including '=' and '=>'. We will + # convert both lines to have just two matching tokens, the equality and the + # side comment. + + # return 0 or undef if unsuccessful + # return 1 if successful + + # We only do this if there is one old line + return unless ($maximum_line_index == 0 ); + return if ($is_matching_terminal_line); + + # We are only looking for equality type statements + my $old_rtokens = $old_line->get_rtokens(); + my $rtokens = $new_line->get_rtokens(); + my $is_equals = + ( $rtokens->[0] =~ /=/ && ( $old_rtokens->[0] eq $rtokens->[0] ) ); + return unless ($is_equals); + + # The leading patterns must match + my $old_rpatterns = $old_line->get_rpatterns(); + my $rpatterns = $new_line->get_rpatterns(); + return if ( $old_rpatterns->[0] ne $rpatterns->[0] ); + + # Both should have side comment fields (should always be true) + my $jmax_old = $old_line->get_jmax(); + my $jmax_new = $new_line->get_jmax(); + my $end_tok_old = $old_rtokens->[$jmax_old-1]; + my $end_tok_new = $rtokens->[$jmax_new-1]; + my $have_side_comments = + defined($end_tok_old) + && $end_tok_old eq '#' + && defined($end_tok_new) + && $end_tok_new eq '#'; + if ( !$have_side_comments ) { return; } + + # Do not match if any remaining tokens in new line include '?', 'if', + # 'unless','||', '&&'. The reason is that (1) this isn't a great match, and + # (2) we will prevent possibly better matchs to follow. Here is an + # example. The match of the first two lines is rejected, and this allows + # the second and third lines to match. + # my $type = shift || "o"; + # my $fname = ( $type eq 'oo' ? 'orte_city' : 'orte' ); + # my $suffix = ( $coord_system eq 'standard' ? '' : '-orig' ); + # This logic can cause some unwanted losses of alignments, but it can retain + # long runs of multiple-token alignments, so overall it is worthwhile. + # If we had a peek at the subsequent line we could make a much better + # decision here, but for now this is not available. + for ( my $j = 1 ; $j < $jmax_new-1 ; $j++ ) { + my $new_tok = $rtokens->[$j]; + my $is_good_alignment = ( $new_tok =~ /^(=|\?|if|unless|\|\||\&\&)/ ); + return if ($is_good_alignment); + } + + my $squeeze_line = sub { + my ($line_obj) = @_; + + # reduce a line down to the three fields surrounding + # the two tokens, an '=' of some sort and a '#' at the end + + my $jmax = $line_obj->get_jmax(); + my $jmax_new = 2; + return unless $jmax > $jmax_new; + my $rfields = $line_obj->get_rfields(); + my $rpatterns = $line_obj->get_rpatterns(); + my $rtokens = $line_obj->get_rtokens(); + my $rfields_new = [ + $rfields->[0], join( '', @{$rfields}[ 1 .. $jmax - 1 ] ), + $rfields->[$jmax] + ]; + my $rpatterns_new = [ + $rpatterns->[0], join( '', @{$rpatterns}[ 1 .. $jmax - 1 ] ), + $rpatterns->[$jmax] + ]; + my $rtokens_new = [ $rtokens->[0], $rtokens->[ $jmax - 1 ] ]; + $line_obj->{_rfields} = $rfields_new; + $line_obj->{_rpatterns} = $rpatterns_new; + $line_obj->{_rtokens} = $rtokens_new; + $line_obj->set_jmax($jmax_new); + }; + + # Okay, we will force a match at the equals-like token. We will fix both + # lines to have just 2 tokens and 3 fields: + $squeeze_line->($new_line); + $squeeze_line->($old_line); + + # start over with a new group + initialize_for_new_group(); + add_to_group($old_line); + $current_line = $old_line; + return 1; +} + sub check_fit { my ( $new_line, $old_line ) = @_;