| line | stmt | bran | cond | sub | pod | time | code | 
| 1 |  |  |  |  |  |  | package Perl::Tidy::VerticalAligner; | 
| 2 | 39 |  |  | 39 |  | 299 | use strict; | 
|  | 39 |  |  |  |  | 90 |  | 
|  | 39 |  |  |  |  | 1496 |  | 
| 3 | 39 |  |  | 39 |  | 212 | use warnings; | 
|  | 39 |  |  |  |  | 93 |  | 
|  | 39 |  |  |  |  | 1328 |  | 
| 4 | 39 |  |  | 39 |  | 219 | use Carp; | 
|  | 39 |  |  |  |  | 74 |  | 
|  | 39 |  |  |  |  | 2879 |  | 
| 5 | 39 |  |  | 39 |  | 277 | use English qw( -no_match_vars ); | 
|  | 39 |  |  |  |  | 88 |  | 
|  | 39 |  |  |  |  | 365 |  | 
| 6 |  |  |  |  |  |  | our $VERSION = '20230909'; | 
| 7 | 39 |  |  | 39 |  | 30807 | use Perl::Tidy::VerticalAligner::Alignment; | 
|  | 39 |  |  |  |  | 110 |  | 
|  | 39 |  |  |  |  | 1386 |  | 
| 8 | 39 |  |  | 39 |  | 16051 | use Perl::Tidy::VerticalAligner::Line; | 
|  | 39 |  |  |  |  | 114 |  | 
|  | 39 |  |  |  |  | 1404 |  | 
| 9 |  |  |  |  |  |  |  | 
| 10 | 39 |  |  | 39 |  | 265 | use constant DEVEL_MODE   => 0; | 
|  | 39 |  |  |  |  | 91 |  | 
|  | 39 |  |  |  |  | 2397 |  | 
| 11 | 39 |  |  | 39 |  | 247 | use constant EMPTY_STRING => q{}; | 
|  | 39 |  |  |  |  | 97 |  | 
|  | 39 |  |  |  |  | 1760 |  | 
| 12 | 39 |  |  | 39 |  | 212 | use constant SPACE        => q{ }; | 
|  | 39 |  |  |  |  | 115 |  | 
|  | 39 |  |  |  |  | 17671 |  | 
| 13 |  |  |  |  |  |  |  | 
| 14 |  |  |  |  |  |  | # The Perl::Tidy::VerticalAligner package collects output lines and | 
| 15 |  |  |  |  |  |  | # attempts to line up certain common tokens, such as => and #, which are | 
| 16 |  |  |  |  |  |  | # identified by the calling routine. | 
| 17 |  |  |  |  |  |  | # | 
| 18 |  |  |  |  |  |  | # Usage: | 
| 19 |  |  |  |  |  |  | #   - Initiate an object with a call to new(). | 
| 20 |  |  |  |  |  |  | #   - Write lines one-by-one with calls to valign_input(). | 
| 21 |  |  |  |  |  |  | #   - Make a final call to flush() to empty the pipeline. | 
| 22 |  |  |  |  |  |  | # | 
| 23 |  |  |  |  |  |  | # The sub valign_input collects lines into groups.  When a group reaches | 
| 24 |  |  |  |  |  |  | # the maximum possible size it is processed for alignment and output. | 
| 25 |  |  |  |  |  |  | # The maximum group size is reached whenever there is a change in indentation | 
| 26 |  |  |  |  |  |  | # level, a blank line, a block comment, or an external flush call.  The calling | 
| 27 |  |  |  |  |  |  | # routine may also force a break in alignment at any time. | 
| 28 |  |  |  |  |  |  | # | 
| 29 |  |  |  |  |  |  | # If the calling routine needs to interrupt the output and send other text to | 
| 30 |  |  |  |  |  |  | # the output, it must first call flush() to empty the output pipeline.  This | 
| 31 |  |  |  |  |  |  | # might occur for example if a block of pod text needs to be sent to the output | 
| 32 |  |  |  |  |  |  | # between blocks of code. | 
| 33 |  |  |  |  |  |  |  | 
| 34 |  |  |  |  |  |  | # It is essential that a final call to flush() be made. Otherwise some | 
| 35 |  |  |  |  |  |  | # final lines of text will be lost. | 
| 36 |  |  |  |  |  |  |  | 
| 37 |  |  |  |  |  |  | # Index... | 
| 38 |  |  |  |  |  |  | # CODE SECTION 1: Preliminary code, global definitions and sub new | 
| 39 |  |  |  |  |  |  | #                 sub new | 
| 40 |  |  |  |  |  |  | # CODE SECTION 2: Some Basic Utilities | 
| 41 |  |  |  |  |  |  | # CODE SECTION 3: Code to accept input and form groups | 
| 42 |  |  |  |  |  |  | #                 sub valign_input | 
| 43 |  |  |  |  |  |  | # CODE SECTION 4: Code to process comment lines | 
| 44 |  |  |  |  |  |  | #                 sub _flush_comment_lines | 
| 45 |  |  |  |  |  |  | # CODE SECTION 5: Code to process groups of code lines | 
| 46 |  |  |  |  |  |  | #                 sub _flush_group_lines | 
| 47 |  |  |  |  |  |  | # CODE SECTION 6: Output Step A | 
| 48 |  |  |  |  |  |  | #                 sub valign_output_step_A | 
| 49 |  |  |  |  |  |  | # CODE SECTION 7: Output Step B | 
| 50 |  |  |  |  |  |  | #                 sub valign_output_step_B | 
| 51 |  |  |  |  |  |  | # CODE SECTION 8: Output Step C | 
| 52 |  |  |  |  |  |  | #                 sub valign_output_step_C | 
| 53 |  |  |  |  |  |  | # CODE SECTION 9: Output Step D | 
| 54 |  |  |  |  |  |  | #                 sub valign_output_step_D | 
| 55 |  |  |  |  |  |  | # CODE SECTION 10: Summary | 
| 56 |  |  |  |  |  |  | #                 sub report_anything_unusual | 
| 57 |  |  |  |  |  |  |  | 
| 58 |  |  |  |  |  |  | ################################################################## | 
| 59 |  |  |  |  |  |  | # CODE SECTION 1: Preliminary code, global definitions and sub new | 
| 60 |  |  |  |  |  |  | ################################################################## | 
| 61 |  |  |  |  |  |  |  | 
| 62 |  |  |  |  |  |  | sub AUTOLOAD { | 
| 63 |  |  |  |  |  |  |  | 
| 64 |  |  |  |  |  |  | # Catch any undefined sub calls so that we are sure to get | 
| 65 |  |  |  |  |  |  | # some diagnostic information.  This sub should never be called | 
| 66 |  |  |  |  |  |  | # except for a programming error. | 
| 67 | 0 |  |  | 0 |  | 0 | our $AUTOLOAD; | 
| 68 | 0 | 0 |  |  |  | 0 | return if ( $AUTOLOAD =~ /\bDESTROY$/ ); | 
| 69 | 0 |  |  |  |  | 0 | my ( $pkg, $fname, $lno ) = caller(); | 
| 70 | 0 |  |  |  |  | 0 | my $my_package = __PACKAGE__; | 
| 71 | 0 |  |  |  |  | 0 | print {*STDERR} <<EOM; | 
|  | 0 |  |  |  |  | 0 |  | 
| 72 |  |  |  |  |  |  | ====================================================================== | 
| 73 |  |  |  |  |  |  | Error detected in package '$my_package', version $VERSION | 
| 74 |  |  |  |  |  |  | Received unexpected AUTOLOAD call for sub '$AUTOLOAD' | 
| 75 |  |  |  |  |  |  | Called from package: '$pkg' | 
| 76 |  |  |  |  |  |  | Called from File '$fname'  at line '$lno' | 
| 77 |  |  |  |  |  |  | This error is probably due to a recent programming change | 
| 78 |  |  |  |  |  |  | ====================================================================== | 
| 79 |  |  |  |  |  |  | EOM | 
| 80 | 0 |  |  |  |  | 0 | exit 1; | 
| 81 |  |  |  |  |  |  | } ## end sub AUTOLOAD | 
| 82 |  |  |  |  |  |  |  | 
| 83 |  |  |  | 0 |  |  | sub DESTROY { | 
| 84 |  |  |  |  |  |  |  | 
| 85 |  |  |  |  |  |  | # required to avoid call to AUTOLOAD in some versions of perl | 
| 86 |  |  |  |  |  |  | } | 
| 87 |  |  |  |  |  |  |  | 
| 88 |  |  |  |  |  |  | sub Die { | 
| 89 | 0 |  |  | 0 | 0 | 0 | my ($msg) = @_; | 
| 90 | 0 |  |  |  |  | 0 | Perl::Tidy::Die($msg); | 
| 91 | 0 |  |  |  |  | 0 | croak "unexpected return from Perl::Tidy::Die"; | 
| 92 |  |  |  |  |  |  | } | 
| 93 |  |  |  |  |  |  |  | 
| 94 |  |  |  |  |  |  | sub Fault { | 
| 95 | 0 |  |  | 0 | 0 | 0 | my ($msg) = @_; | 
| 96 |  |  |  |  |  |  |  | 
| 97 |  |  |  |  |  |  | # This routine is called for errors that really should not occur | 
| 98 |  |  |  |  |  |  | # except if there has been a bug introduced by a recent program change. | 
| 99 |  |  |  |  |  |  | # Please add comments at calls to Fault to explain why the call | 
| 100 |  |  |  |  |  |  | # should not occur, and where to look to fix it. | 
| 101 | 0 |  |  |  |  | 0 | my ( $package0, $filename0, $line0, $subroutine0 ) = caller(0); | 
| 102 | 0 |  |  |  |  | 0 | my ( $package1, $filename1, $line1, $subroutine1 ) = caller(1); | 
| 103 | 0 |  |  |  |  | 0 | my ( $package2, $filename2, $line2, $subroutine2 ) = caller(2); | 
| 104 | 0 |  |  |  |  | 0 | my $pkg = __PACKAGE__; | 
| 105 |  |  |  |  |  |  |  | 
| 106 | 0 |  |  |  |  | 0 | my $input_stream_name = get_input_stream_name(); | 
| 107 |  |  |  |  |  |  |  | 
| 108 | 0 |  |  |  |  | 0 | Die(<<EOM); | 
| 109 |  |  |  |  |  |  | ============================================================================== | 
| 110 |  |  |  |  |  |  | While operating on input stream with name: '$input_stream_name' | 
| 111 |  |  |  |  |  |  | A fault was detected at line $line0 of sub '$subroutine1' | 
| 112 |  |  |  |  |  |  | in file '$filename1' | 
| 113 |  |  |  |  |  |  | which was called from line $line1 of sub '$subroutine2' | 
| 114 |  |  |  |  |  |  | Message: '$msg' | 
| 115 |  |  |  |  |  |  | This is probably an error introduced by a recent programming change. | 
| 116 |  |  |  |  |  |  | $pkg reports VERSION='$VERSION'. | 
| 117 |  |  |  |  |  |  | ============================================================================== | 
| 118 |  |  |  |  |  |  | EOM | 
| 119 |  |  |  |  |  |  |  | 
| 120 |  |  |  |  |  |  | # We shouldn't get here, but this return is to keep Perl-Critic from | 
| 121 |  |  |  |  |  |  | # complaining. | 
| 122 | 0 |  |  |  |  | 0 | return; | 
| 123 |  |  |  |  |  |  | } ## end sub Fault | 
| 124 |  |  |  |  |  |  |  | 
| 125 |  |  |  |  |  |  | my %valid_LINE_keys; | 
| 126 |  |  |  |  |  |  |  | 
| 127 |  |  |  |  |  |  | BEGIN { | 
| 128 |  |  |  |  |  |  |  | 
| 129 |  |  |  |  |  |  | # define valid keys in a line object | 
| 130 | 39 |  |  | 39 |  | 330 | my @q = qw( | 
| 131 |  |  |  |  |  |  | jmax | 
| 132 |  |  |  |  |  |  | rtokens | 
| 133 |  |  |  |  |  |  | rfields | 
| 134 |  |  |  |  |  |  | rfield_lengths | 
| 135 |  |  |  |  |  |  | rpatterns | 
| 136 |  |  |  |  |  |  | indentation | 
| 137 |  |  |  |  |  |  | leading_space_count | 
| 138 |  |  |  |  |  |  | outdent_long_lines | 
| 139 |  |  |  |  |  |  | list_type | 
| 140 |  |  |  |  |  |  | list_seqno | 
| 141 |  |  |  |  |  |  | is_hanging_side_comment | 
| 142 |  |  |  |  |  |  | maximum_line_length | 
| 143 |  |  |  |  |  |  | rvertical_tightness_flags | 
| 144 |  |  |  |  |  |  | is_terminal_ternary | 
| 145 |  |  |  |  |  |  | j_terminal_match | 
| 146 |  |  |  |  |  |  | end_group | 
| 147 |  |  |  |  |  |  | Kend | 
| 148 |  |  |  |  |  |  | ci_level | 
| 149 |  |  |  |  |  |  | level | 
| 150 |  |  |  |  |  |  | level_end | 
| 151 |  |  |  |  |  |  | imax_pair | 
| 152 |  |  |  |  |  |  |  | 
| 153 |  |  |  |  |  |  | ralignments | 
| 154 |  |  |  |  |  |  | ); | 
| 155 |  |  |  |  |  |  |  | 
| 156 | 39 |  |  |  |  | 5889 | @valid_LINE_keys{@q} = (1) x scalar(@q); | 
| 157 |  |  |  |  |  |  | } ## end BEGIN | 
| 158 |  |  |  |  |  |  |  | 
| 159 |  |  |  |  |  |  | BEGIN { | 
| 160 |  |  |  |  |  |  |  | 
| 161 |  |  |  |  |  |  | # Define the fixed indexes for variables in $self, which is an array | 
| 162 |  |  |  |  |  |  | # reference.  Note the convention of leading and trailing underscores to | 
| 163 |  |  |  |  |  |  | # keep them unique. | 
| 164 |  |  |  |  |  |  | # Do not combine with other BEGIN blocks (c101). | 
| 165 | 39 |  |  | 39 |  | 192 | my $i = 0; | 
| 166 |  |  |  |  |  |  | use constant { | 
| 167 | 39 |  |  |  |  | 11217 | _file_writer_object_ => $i++, | 
| 168 |  |  |  |  |  |  | _logger_object_      => $i++, | 
| 169 |  |  |  |  |  |  | _diagnostics_object_ => $i++, | 
| 170 |  |  |  |  |  |  |  | 
| 171 |  |  |  |  |  |  | _rOpts_                             => $i++, | 
| 172 |  |  |  |  |  |  | _rOpts_indent_columns_              => $i++, | 
| 173 |  |  |  |  |  |  | _rOpts_tabs_                        => $i++, | 
| 174 |  |  |  |  |  |  | _rOpts_entab_leading_whitespace_    => $i++, | 
| 175 |  |  |  |  |  |  | _rOpts_fixed_position_side_comment_ => $i++, | 
| 176 |  |  |  |  |  |  | _rOpts_minimum_space_to_comment_    => $i++, | 
| 177 |  |  |  |  |  |  | _rOpts_valign_code_                 => $i++, | 
| 178 |  |  |  |  |  |  | _rOpts_valign_block_comments_       => $i++, | 
| 179 |  |  |  |  |  |  | _rOpts_valign_side_comments_        => $i++, | 
| 180 |  |  |  |  |  |  |  | 
| 181 |  |  |  |  |  |  | _last_level_written_            => $i++, | 
| 182 |  |  |  |  |  |  | _last_side_comment_column_      => $i++, | 
| 183 |  |  |  |  |  |  | _last_side_comment_line_number_ => $i++, | 
| 184 |  |  |  |  |  |  | _last_side_comment_length_      => $i++, | 
| 185 |  |  |  |  |  |  | _last_side_comment_level_       => $i++, | 
| 186 |  |  |  |  |  |  | _outdented_line_count_          => $i++, | 
| 187 |  |  |  |  |  |  | _first_outdented_line_at_       => $i++, | 
| 188 |  |  |  |  |  |  | _last_outdented_line_at_        => $i++, | 
| 189 |  |  |  |  |  |  | _consecutive_block_comments_    => $i++, | 
| 190 |  |  |  |  |  |  |  | 
| 191 |  |  |  |  |  |  | _rgroup_lines_                => $i++, | 
| 192 |  |  |  |  |  |  | _group_level_                 => $i++, | 
| 193 |  |  |  |  |  |  | _group_type_                  => $i++, | 
| 194 |  |  |  |  |  |  | _group_maximum_line_length_   => $i++, | 
| 195 |  |  |  |  |  |  | _zero_count_                  => $i++, | 
| 196 |  |  |  |  |  |  | _last_leading_space_count_    => $i++, | 
| 197 |  |  |  |  |  |  | _comment_leading_space_count_ => $i++, | 
| 198 | 39 |  |  | 39 |  | 338 | }; | 
|  | 39 |  |  |  |  | 86 |  | 
| 199 |  |  |  |  |  |  |  | 
| 200 |  |  |  |  |  |  | # Debug flag. This is a relic from the original program development | 
| 201 |  |  |  |  |  |  | # looking for problems with tab characters.  Caution: this debug flag can | 
| 202 |  |  |  |  |  |  | # produce a lot of output It should be 0 except when debugging small | 
| 203 |  |  |  |  |  |  | # scripts. | 
| 204 |  |  |  |  |  |  |  | 
| 205 | 39 |  |  | 39 |  | 290 | use constant DEBUG_TABS => 0; | 
|  | 39 |  |  |  |  | 76 |  | 
|  | 39 |  |  |  |  | 4731 |  | 
| 206 |  |  |  |  |  |  |  | 
| 207 |  |  |  |  |  |  | my $debug_warning = sub { | 
| 208 | 0 |  |  |  |  | 0 | print {*STDOUT} "VALIGN_DEBUGGING with key $_[0]\n"; | 
|  | 0 |  |  |  |  | 0 |  | 
| 209 | 0 |  |  |  |  | 0 | return; | 
| 210 | 39 |  |  |  |  | 500 | }; | 
| 211 |  |  |  |  |  |  |  | 
| 212 | 39 |  |  |  |  | 53473 | DEBUG_TABS && $debug_warning->('TABS'); | 
| 213 |  |  |  |  |  |  | } ## end BEGIN | 
| 214 |  |  |  |  |  |  |  | 
| 215 |  |  |  |  |  |  | # GLOBAL variables | 
| 216 |  |  |  |  |  |  | my ( | 
| 217 |  |  |  |  |  |  |  | 
| 218 |  |  |  |  |  |  | %valign_control_hash, | 
| 219 |  |  |  |  |  |  | $valign_control_default, | 
| 220 |  |  |  |  |  |  |  | 
| 221 |  |  |  |  |  |  | ); | 
| 222 |  |  |  |  |  |  |  | 
| 223 |  |  |  |  |  |  | sub check_options { | 
| 224 |  |  |  |  |  |  |  | 
| 225 |  |  |  |  |  |  | # This routine is called to check the user-supplied run parameters | 
| 226 |  |  |  |  |  |  | # and to configure the control hashes to them. | 
| 227 | 559 |  |  | 559 | 0 | 1843 | my ($rOpts) = @_; | 
| 228 |  |  |  |  |  |  |  | 
| 229 |  |  |  |  |  |  | # All alignments are done by default | 
| 230 | 559 |  |  |  |  | 1586 | %valign_control_hash    = (); | 
| 231 | 559 |  |  |  |  | 1350 | $valign_control_default = 1; | 
| 232 |  |  |  |  |  |  |  | 
| 233 |  |  |  |  |  |  | # If -vil=s is entered without -vxl, assume -vxl='*' | 
| 234 | 559 | 50 | 66 |  |  | 4642 | if (  !$rOpts->{'valign-exclusion-list'} | 
| 235 |  |  |  |  |  |  | && $rOpts->{'valign-inclusion-list'} ) | 
| 236 |  |  |  |  |  |  | { | 
| 237 | 0 |  |  |  |  | 0 | $rOpts->{'valign-exclusion-list'} = '*'; | 
| 238 |  |  |  |  |  |  | } | 
| 239 |  |  |  |  |  |  |  | 
| 240 |  |  |  |  |  |  | # See if the user wants to exclude any alignment types ... | 
| 241 | 559 | 100 |  |  |  | 2386 | if ( $rOpts->{'valign-exclusion-list'} ) { | 
| 242 |  |  |  |  |  |  |  | 
| 243 |  |  |  |  |  |  | # The inclusion list is only relevant if there is an exclusion list | 
| 244 | 3 | 100 |  |  |  | 18 | if ( $rOpts->{'valign-inclusion-list'} ) { | 
| 245 | 1 |  |  |  |  | 7 | my @vil = split /\s+/, $rOpts->{'valign-inclusion-list'}; | 
| 246 | 1 |  |  |  |  | 6 | @valign_control_hash{@vil} = (1) x scalar(@vil); | 
| 247 |  |  |  |  |  |  | } | 
| 248 |  |  |  |  |  |  |  | 
| 249 |  |  |  |  |  |  | # Note that the -vxl list is done after -vil, so -vxl has priority | 
| 250 |  |  |  |  |  |  | # in the event of duplicate entries. | 
| 251 | 3 |  |  |  |  | 18 | my @vxl = split /\s+/, $rOpts->{'valign-exclusion-list'}; | 
| 252 | 3 |  |  |  |  | 18 | @valign_control_hash{@vxl} = (0) x scalar(@vxl); | 
| 253 |  |  |  |  |  |  |  | 
| 254 |  |  |  |  |  |  | # Optimization: revert to defaults if no exclusions. | 
| 255 |  |  |  |  |  |  | # This could happen with -vxl='  ' and any -vil list | 
| 256 | 3 | 50 |  |  |  | 17 | if ( !@vxl ) { | 
| 257 | 0 |  |  |  |  | 0 | %valign_control_hash = (); | 
| 258 |  |  |  |  |  |  | } | 
| 259 |  |  |  |  |  |  |  | 
| 260 |  |  |  |  |  |  | # '$valign_control_default' applies to types not in the hash: | 
| 261 |  |  |  |  |  |  | # - If a '*' was entered then set it to be that default type | 
| 262 |  |  |  |  |  |  | # - Otherwise, leave it set it to 1 | 
| 263 | 3 | 100 |  |  |  | 18 | if ( defined( $valign_control_hash{'*'} ) ) { | 
| 264 | 1 |  |  |  |  | 3 | $valign_control_default = $valign_control_hash{'*'}; | 
| 265 |  |  |  |  |  |  | } | 
| 266 |  |  |  |  |  |  |  | 
| 267 |  |  |  |  |  |  | # Side comments are controlled separately and must be removed | 
| 268 |  |  |  |  |  |  | # if given in a list. | 
| 269 | 3 | 50 |  |  |  | 12 | if (%valign_control_hash) { | 
| 270 | 3 |  |  |  |  | 12 | $valign_control_hash{'#'} = 1; | 
| 271 |  |  |  |  |  |  | } | 
| 272 |  |  |  |  |  |  | } | 
| 273 |  |  |  |  |  |  |  | 
| 274 | 559 |  |  |  |  | 1414 | return; | 
| 275 |  |  |  |  |  |  | } ## end sub check_options | 
| 276 |  |  |  |  |  |  |  | 
| 277 |  |  |  |  |  |  | sub check_keys { | 
| 278 | 0 |  |  | 0 | 0 | 0 | my ( $rtest, $rvalid, $msg, $exact_match ) = @_; | 
| 279 |  |  |  |  |  |  |  | 
| 280 |  |  |  |  |  |  | # Check the keys of a hash: | 
| 281 |  |  |  |  |  |  | # $rtest   = ref to hash to test | 
| 282 |  |  |  |  |  |  | # $rvalid  = ref to hash with valid keys | 
| 283 |  |  |  |  |  |  |  | 
| 284 |  |  |  |  |  |  | # $msg = a message to write in case of error | 
| 285 |  |  |  |  |  |  | # $exact_match defines the type of check: | 
| 286 |  |  |  |  |  |  | #     = false: test hash must not have unknown key | 
| 287 |  |  |  |  |  |  | #     = true:  test hash must have exactly same keys as known hash | 
| 288 |  |  |  |  |  |  | my @unknown_keys = | 
| 289 | 0 |  |  |  |  | 0 | grep { !exists $rvalid->{$_} } keys %{$rtest}; | 
|  | 0 |  |  |  |  | 0 |  | 
|  | 0 |  |  |  |  | 0 |  | 
| 290 |  |  |  |  |  |  | my @missing_keys = | 
| 291 | 0 |  |  |  |  | 0 | grep { !exists $rtest->{$_} } keys %{$rvalid}; | 
|  | 0 |  |  |  |  | 0 |  | 
|  | 0 |  |  |  |  | 0 |  | 
| 292 | 0 |  |  |  |  | 0 | my $error = @unknown_keys; | 
| 293 | 0 | 0 | 0 |  |  | 0 | if ($exact_match) { $error ||= @missing_keys } | 
|  | 0 |  |  |  |  | 0 |  | 
| 294 | 0 | 0 |  |  |  | 0 | if ($error) { | 
| 295 | 0 |  |  |  |  | 0 | local $LIST_SEPARATOR = ')('; | 
| 296 | 0 |  |  |  |  | 0 | my @expected_keys = sort keys %{$rvalid}; | 
|  | 0 |  |  |  |  | 0 |  | 
| 297 | 0 |  |  |  |  | 0 | @unknown_keys = sort @unknown_keys; | 
| 298 | 0 |  |  |  |  | 0 | Fault(<<EOM); | 
| 299 |  |  |  |  |  |  | ------------------------------------------------------------------------ | 
| 300 |  |  |  |  |  |  | Program error detected checking hash keys | 
| 301 |  |  |  |  |  |  | Message is: '$msg' | 
| 302 |  |  |  |  |  |  | Expected keys: (@expected_keys) | 
| 303 |  |  |  |  |  |  | Unknown key(s): (@unknown_keys) | 
| 304 |  |  |  |  |  |  | Missing key(s): (@missing_keys) | 
| 305 |  |  |  |  |  |  | ------------------------------------------------------------------------ | 
| 306 |  |  |  |  |  |  | EOM | 
| 307 |  |  |  |  |  |  | } | 
| 308 | 0 |  |  |  |  | 0 | return; | 
| 309 |  |  |  |  |  |  | } ## end sub check_keys | 
| 310 |  |  |  |  |  |  |  | 
| 311 |  |  |  |  |  |  | sub new { | 
| 312 |  |  |  |  |  |  |  | 
| 313 | 560 |  |  | 560 | 0 | 2844 | my ( $class, @args ) = @_; | 
| 314 |  |  |  |  |  |  |  | 
| 315 | 560 |  |  |  |  | 3774 | my %defaults = ( | 
| 316 |  |  |  |  |  |  | rOpts              => undef, | 
| 317 |  |  |  |  |  |  | file_writer_object => undef, | 
| 318 |  |  |  |  |  |  | logger_object      => undef, | 
| 319 |  |  |  |  |  |  | diagnostics_object => undef, | 
| 320 |  |  |  |  |  |  | ); | 
| 321 | 560 |  |  |  |  | 3703 | my %args = ( %defaults, @args ); | 
| 322 |  |  |  |  |  |  |  | 
| 323 |  |  |  |  |  |  | # Initialize other caches and buffers | 
| 324 | 560 |  |  |  |  | 3696 | initialize_step_B_cache(); | 
| 325 | 560 |  |  |  |  | 3042 | initialize_valign_buffer(); | 
| 326 | 560 |  |  |  |  | 3020 | initialize_decode(); | 
| 327 | 560 |  |  |  |  | 3244 | set_logger_object( $args{logger_object} ); | 
| 328 |  |  |  |  |  |  |  | 
| 329 |  |  |  |  |  |  | # Initialize all variables in $self. | 
| 330 |  |  |  |  |  |  | # To add an item to $self, first define a new constant index in the BEGIN | 
| 331 |  |  |  |  |  |  | # section. | 
| 332 | 560 |  |  |  |  | 1669 | my $self = []; | 
| 333 |  |  |  |  |  |  |  | 
| 334 |  |  |  |  |  |  | # objects | 
| 335 | 560 |  |  |  |  | 2082 | $self->[_file_writer_object_] = $args{file_writer_object}; | 
| 336 | 560 |  |  |  |  | 1809 | $self->[_logger_object_]      = $args{logger_object}; | 
| 337 | 560 |  |  |  |  | 1505 | $self->[_diagnostics_object_] = $args{diagnostics_object}; | 
| 338 |  |  |  |  |  |  |  | 
| 339 |  |  |  |  |  |  | # shortcuts to user options | 
| 340 | 560 |  |  |  |  | 1382 | my $rOpts = $args{rOpts}; | 
| 341 |  |  |  |  |  |  |  | 
| 342 | 560 |  |  |  |  | 1515 | $self->[_rOpts_]                = $rOpts; | 
| 343 | 560 |  |  |  |  | 1743 | $self->[_rOpts_indent_columns_] = $rOpts->{'indent-columns'}; | 
| 344 | 560 |  |  |  |  | 1712 | $self->[_rOpts_tabs_]           = $rOpts->{'tabs'}; | 
| 345 |  |  |  |  |  |  | $self->[_rOpts_entab_leading_whitespace_] = | 
| 346 | 560 |  |  |  |  | 1581 | $rOpts->{'entab-leading-whitespace'}; | 
| 347 |  |  |  |  |  |  | $self->[_rOpts_fixed_position_side_comment_] = | 
| 348 | 560 |  |  |  |  | 1401 | $rOpts->{'fixed-position-side-comment'}; | 
| 349 |  |  |  |  |  |  | $self->[_rOpts_minimum_space_to_comment_] = | 
| 350 | 560 |  |  |  |  | 1635 | $rOpts->{'minimum-space-to-comment'}; | 
| 351 | 560 |  |  |  |  | 1546 | $self->[_rOpts_valign_code_]           = $rOpts->{'valign-code'}; | 
| 352 | 560 |  |  |  |  | 1488 | $self->[_rOpts_valign_block_comments_] = $rOpts->{'valign-block-comments'}; | 
| 353 | 560 |  |  |  |  | 1572 | $self->[_rOpts_valign_side_comments_]  = $rOpts->{'valign-side-comments'}; | 
| 354 |  |  |  |  |  |  |  | 
| 355 |  |  |  |  |  |  | # Batch of lines being collected | 
| 356 | 560 |  |  |  |  | 1724 | $self->[_rgroup_lines_]                = []; | 
| 357 | 560 |  |  |  |  | 1451 | $self->[_group_level_]                 = 0; | 
| 358 | 560 |  |  |  |  | 1441 | $self->[_group_type_]                  = EMPTY_STRING; | 
| 359 | 560 |  |  |  |  | 1584 | $self->[_group_maximum_line_length_]   = undef; | 
| 360 | 560 |  |  |  |  | 1495 | $self->[_zero_count_]                  = 0; | 
| 361 | 560 |  |  |  |  | 1442 | $self->[_comment_leading_space_count_] = 0; | 
| 362 | 560 |  |  |  |  | 1365 | $self->[_last_leading_space_count_]    = 0; | 
| 363 |  |  |  |  |  |  |  | 
| 364 |  |  |  |  |  |  | # Memory of what has been processed | 
| 365 | 560 |  |  |  |  | 1294 | $self->[_last_level_written_]            = -1; | 
| 366 | 560 |  |  |  |  | 1236 | $self->[_last_side_comment_column_]      = 0; | 
| 367 | 560 |  |  |  |  | 1266 | $self->[_last_side_comment_line_number_] = 0; | 
| 368 | 560 |  |  |  |  | 1287 | $self->[_last_side_comment_length_]      = 0; | 
| 369 | 560 |  |  |  |  | 1226 | $self->[_last_side_comment_level_]       = -1; | 
| 370 | 560 |  |  |  |  | 1220 | $self->[_outdented_line_count_]          = 0; | 
| 371 | 560 |  |  |  |  | 1290 | $self->[_first_outdented_line_at_]       = 0; | 
| 372 | 560 |  |  |  |  | 1263 | $self->[_last_outdented_line_at_]        = 0; | 
| 373 | 560 |  |  |  |  | 1251 | $self->[_consecutive_block_comments_]    = 0; | 
| 374 |  |  |  |  |  |  |  | 
| 375 | 560 |  |  |  |  | 1439 | bless $self, $class; | 
| 376 | 560 |  |  |  |  | 3021 | return $self; | 
| 377 |  |  |  |  |  |  | } ## end sub new | 
| 378 |  |  |  |  |  |  |  | 
| 379 |  |  |  |  |  |  | ################################# | 
| 380 |  |  |  |  |  |  | # CODE SECTION 2: Basic Utilities | 
| 381 |  |  |  |  |  |  | ################################# | 
| 382 |  |  |  |  |  |  |  | 
| 383 |  |  |  |  |  |  | sub flush { | 
| 384 |  |  |  |  |  |  |  | 
| 385 |  |  |  |  |  |  | # flush() is the external call to completely empty the pipeline. | 
| 386 | 1817 |  |  | 1817 | 0 | 3864 | my ($self) = @_; | 
| 387 |  |  |  |  |  |  |  | 
| 388 |  |  |  |  |  |  | # push things out the pipeline... | 
| 389 |  |  |  |  |  |  |  | 
| 390 |  |  |  |  |  |  | # push out any current group lines | 
| 391 | 1817 |  |  |  |  | 5818 | $self->_flush_group_lines(); | 
| 392 |  |  |  |  |  |  |  | 
| 393 |  |  |  |  |  |  | # then anything left in the cache of step_B | 
| 394 | 1817 |  |  |  |  | 7300 | $self->_flush_step_B_cache(); | 
| 395 |  |  |  |  |  |  |  | 
| 396 |  |  |  |  |  |  | # then anything left in the buffer of step_C | 
| 397 | 1817 |  |  |  |  | 5806 | $self->dump_valign_buffer(); | 
| 398 |  |  |  |  |  |  |  | 
| 399 | 1817 |  |  |  |  | 3692 | return; | 
| 400 |  |  |  |  |  |  | } ## end sub flush | 
| 401 |  |  |  |  |  |  |  | 
| 402 |  |  |  |  |  |  | sub initialize_for_new_group { | 
| 403 | 2236 |  |  | 2236 | 0 | 4922 | my ($self) = @_; | 
| 404 |  |  |  |  |  |  |  | 
| 405 | 2236 |  |  |  |  | 5203 | $self->[_rgroup_lines_]                = []; | 
| 406 | 2236 |  |  |  |  | 4699 | $self->[_group_type_]                  = EMPTY_STRING; | 
| 407 | 2236 |  |  |  |  | 4158 | $self->[_zero_count_]                  = 0; | 
| 408 | 2236 |  |  |  |  | 3617 | $self->[_comment_leading_space_count_] = 0; | 
| 409 | 2236 |  |  |  |  | 3605 | $self->[_last_leading_space_count_]    = 0; | 
| 410 | 2236 |  |  |  |  | 3868 | $self->[_group_maximum_line_length_]   = undef; | 
| 411 |  |  |  |  |  |  |  | 
| 412 |  |  |  |  |  |  | # Note that the value for _group_level_ is | 
| 413 |  |  |  |  |  |  | # handled separately in sub valign_input | 
| 414 | 2236 |  |  |  |  | 3746 | return; | 
| 415 |  |  |  |  |  |  | } ## end sub initialize_for_new_group | 
| 416 |  |  |  |  |  |  |  | 
| 417 |  |  |  |  |  |  | sub group_line_count { | 
| 418 | 73 |  |  | 73 | 0 | 118 | return +@{ $_[0]->[_rgroup_lines_] }; | 
|  | 73 |  |  |  |  | 368 |  | 
| 419 |  |  |  |  |  |  | } | 
| 420 |  |  |  |  |  |  |  | 
| 421 |  |  |  |  |  |  | # interface to Perl::Tidy::Diagnostics routines | 
| 422 |  |  |  |  |  |  | # For debugging; not currently used | 
| 423 |  |  |  |  |  |  | sub write_diagnostics { | 
| 424 | 0 |  |  | 0 | 0 | 0 | my ( $self, $msg ) = @_; | 
| 425 | 0 |  |  |  |  | 0 | my $diagnostics_object = $self->[_diagnostics_object_]; | 
| 426 | 0 | 0 |  |  |  | 0 | if ($diagnostics_object) { | 
| 427 | 0 |  |  |  |  | 0 | $diagnostics_object->write_diagnostics($msg); | 
| 428 |  |  |  |  |  |  | } | 
| 429 | 0 |  |  |  |  | 0 | return; | 
| 430 |  |  |  |  |  |  | } ## end sub write_diagnostics | 
| 431 |  |  |  |  |  |  |  | 
| 432 |  |  |  |  |  |  | {    ## begin closure for logger routines | 
| 433 |  |  |  |  |  |  | my $logger_object; | 
| 434 |  |  |  |  |  |  |  | 
| 435 |  |  |  |  |  |  | # Called once per file to initialize the logger object | 
| 436 |  |  |  |  |  |  | sub set_logger_object { | 
| 437 | 560 |  |  | 560 | 0 | 21704 | $logger_object = shift; | 
| 438 | 560 |  |  |  |  | 1610 | return; | 
| 439 |  |  |  |  |  |  | } | 
| 440 |  |  |  |  |  |  |  | 
| 441 |  |  |  |  |  |  | sub get_logger_object { | 
| 442 | 0 |  |  | 0 | 0 | 0 | return $logger_object; | 
| 443 |  |  |  |  |  |  | } | 
| 444 |  |  |  |  |  |  |  | 
| 445 |  |  |  |  |  |  | sub get_input_stream_name { | 
| 446 | 0 |  |  | 0 | 0 | 0 | my $input_stream_name = EMPTY_STRING; | 
| 447 | 0 | 0 |  |  |  | 0 | if ($logger_object) { | 
| 448 | 0 |  |  |  |  | 0 | $input_stream_name = $logger_object->get_input_stream_name(); | 
| 449 |  |  |  |  |  |  | } | 
| 450 | 0 |  |  |  |  | 0 | return $input_stream_name; | 
| 451 |  |  |  |  |  |  | } ## end sub get_input_stream_name | 
| 452 |  |  |  |  |  |  |  | 
| 453 |  |  |  |  |  |  | sub warning { | 
| 454 | 0 |  |  | 0 | 0 | 0 | my ($msg) = @_; | 
| 455 | 0 | 0 |  |  |  | 0 | if ($logger_object) { | 
| 456 | 0 |  |  |  |  | 0 | $logger_object->warning($msg); | 
| 457 |  |  |  |  |  |  | } | 
| 458 | 0 |  |  |  |  | 0 | return; | 
| 459 |  |  |  |  |  |  | } ## end sub warning | 
| 460 |  |  |  |  |  |  |  | 
| 461 |  |  |  |  |  |  | sub write_logfile_entry { | 
| 462 | 91 |  |  | 91 | 0 | 189 | my ($msg) = @_; | 
| 463 | 91 | 50 |  |  |  | 220 | if ($logger_object) { | 
| 464 | 91 |  |  |  |  | 210 | $logger_object->write_logfile_entry($msg); | 
| 465 |  |  |  |  |  |  | } | 
| 466 | 91 |  |  |  |  | 205 | return; | 
| 467 |  |  |  |  |  |  | } ## end sub write_logfile_entry | 
| 468 |  |  |  |  |  |  | } | 
| 469 |  |  |  |  |  |  |  | 
| 470 |  |  |  |  |  |  | sub get_cached_line_count { | 
| 471 | 1 |  |  | 1 | 0 | 3 | my $self = shift; | 
| 472 | 1 | 50 |  |  |  | 5 | return $self->group_line_count() + ( get_cached_line_type() ? 1 : 0 ); | 
| 473 |  |  |  |  |  |  | } | 
| 474 |  |  |  |  |  |  |  | 
| 475 |  |  |  |  |  |  | sub get_recoverable_spaces { | 
| 476 |  |  |  |  |  |  |  | 
| 477 |  |  |  |  |  |  | # return the number of spaces (+ means shift right, - means shift left) | 
| 478 |  |  |  |  |  |  | # that we would like to shift a group of lines with the same indentation | 
| 479 |  |  |  |  |  |  | # to get them to line up with their opening parens | 
| 480 | 4113 |  |  | 4113 | 0 | 6954 | my $indentation = shift; | 
| 481 | 4113 | 100 |  |  |  | 14874 | return ref($indentation) ? $indentation->get_recoverable_spaces() : 0; | 
| 482 |  |  |  |  |  |  | } ## end sub get_recoverable_spaces | 
| 483 |  |  |  |  |  |  |  | 
| 484 |  |  |  |  |  |  | ###################################################### | 
| 485 |  |  |  |  |  |  | # CODE SECTION 3: Code to accept input and form groups | 
| 486 |  |  |  |  |  |  | ###################################################### | 
| 487 |  |  |  |  |  |  |  | 
| 488 | 39 |  |  | 39 |  | 415 | use constant DEBUG_VALIGN      => 0; | 
|  | 39 |  |  |  |  | 118 |  | 
|  | 39 |  |  |  |  | 2617 |  | 
| 489 | 39 |  |  | 39 |  | 282 | use constant SC_LONG_LINE_DIFF => 12; | 
|  | 39 |  |  |  |  | 114 |  | 
|  | 39 |  |  |  |  | 3575 |  | 
| 490 |  |  |  |  |  |  |  | 
| 491 |  |  |  |  |  |  | my %is_closing_token; | 
| 492 |  |  |  |  |  |  |  | 
| 493 |  |  |  |  |  |  | BEGIN { | 
| 494 | 39 |  |  | 39 |  | 252 | my @q = qw< } ) ] >; | 
| 495 | 39 |  |  |  |  | 65308 | @is_closing_token{@q} = (1) x scalar(@q); | 
| 496 |  |  |  |  |  |  | } | 
| 497 |  |  |  |  |  |  |  | 
| 498 |  |  |  |  |  |  | #-------------------------------------------- | 
| 499 |  |  |  |  |  |  | # VTFLAGS: Vertical tightness types and flags | 
| 500 |  |  |  |  |  |  | #-------------------------------------------- | 
| 501 |  |  |  |  |  |  | # Vertical tightness is controlled by a 'type' and associated 'flags' for each | 
| 502 |  |  |  |  |  |  | # line.  These values are set by sub Formatter::set_vertical_tightness_flags. | 
| 503 |  |  |  |  |  |  | # These are defined as follows: | 
| 504 |  |  |  |  |  |  |  | 
| 505 |  |  |  |  |  |  | # Vertical Tightness Line Type Codes: | 
| 506 |  |  |  |  |  |  | # Type 0, no vertical tightness condition | 
| 507 |  |  |  |  |  |  | # Type 1, last token of this line is a non-block opening token | 
| 508 |  |  |  |  |  |  | # Type 2, first token of next line is a non-block closing | 
| 509 |  |  |  |  |  |  | # Type 3, isolated opening block brace | 
| 510 |  |  |  |  |  |  | # type 4, isolated closing block brace | 
| 511 |  |  |  |  |  |  |  | 
| 512 |  |  |  |  |  |  | # Opening token flag values are the vertical tightness flags | 
| 513 |  |  |  |  |  |  | # 0 do not join with next line | 
| 514 |  |  |  |  |  |  | # 1 just one join per line | 
| 515 |  |  |  |  |  |  | # 2 any number of joins | 
| 516 |  |  |  |  |  |  |  | 
| 517 |  |  |  |  |  |  | # Closing token flag values indicate spacing: | 
| 518 |  |  |  |  |  |  | # 0 = no space added before closing token | 
| 519 |  |  |  |  |  |  | # 1 = single space added before closing token | 
| 520 |  |  |  |  |  |  |  | 
| 521 |  |  |  |  |  |  | sub valign_input { | 
| 522 |  |  |  |  |  |  |  | 
| 523 |  |  |  |  |  |  | #--------------------------------------------------------------------- | 
| 524 |  |  |  |  |  |  | # This is the front door of the vertical aligner.  On each call | 
| 525 |  |  |  |  |  |  | # we receive one line of specially marked text for vertical alignment. | 
| 526 |  |  |  |  |  |  | # We compare the line with the current group, and either: | 
| 527 |  |  |  |  |  |  | # - the line joins the current group if alignments match, or | 
| 528 |  |  |  |  |  |  | # - the current group is flushed and a new group is started otherwise | 
| 529 |  |  |  |  |  |  | #--------------------------------------------------------------------- | 
| 530 |  |  |  |  |  |  | # | 
| 531 |  |  |  |  |  |  | # The key input parameters describing each line are: | 
| 532 |  |  |  |  |  |  | #     $level          = indentation level of this line | 
| 533 |  |  |  |  |  |  | #     $rfields        = ref to array of fields | 
| 534 |  |  |  |  |  |  | #     $rpatterns      = ref to array of patterns, one per field | 
| 535 |  |  |  |  |  |  | #     $rtokens        = ref to array of tokens starting fields 1,2,.. | 
| 536 |  |  |  |  |  |  | #     $rfield_lengths = ref to array of field display widths | 
| 537 |  |  |  |  |  |  | # | 
| 538 |  |  |  |  |  |  | # Here is an example of what this package does.  In this example, | 
| 539 |  |  |  |  |  |  | # we are trying to line up both the '=>' and the '#'. | 
| 540 |  |  |  |  |  |  | # | 
| 541 |  |  |  |  |  |  | #         '18' => 'grave',    #   \` | 
| 542 |  |  |  |  |  |  | #         '19' => 'acute',    #   `' | 
| 543 |  |  |  |  |  |  | #         '20' => 'caron',    #   \v | 
| 544 |  |  |  |  |  |  | # <-tabs-><f1-><--field 2 ---><-f3-> | 
| 545 |  |  |  |  |  |  | # |            |              |    | | 
| 546 |  |  |  |  |  |  | # |            |              |    | | 
| 547 |  |  |  |  |  |  | # col1        col2         col3 col4 | 
| 548 |  |  |  |  |  |  | # | 
| 549 |  |  |  |  |  |  | # The calling routine has already broken the entire line into 3 fields as | 
| 550 |  |  |  |  |  |  | # indicated.  (So the work of identifying promising common tokens has | 
| 551 |  |  |  |  |  |  | # already been done). | 
| 552 |  |  |  |  |  |  | # | 
| 553 |  |  |  |  |  |  | # In this example, there will be 2 tokens being matched: '=>' and '#'. | 
| 554 |  |  |  |  |  |  | # They are the leading parts of fields 2 and 3, but we do need to know | 
| 555 |  |  |  |  |  |  | # what they are so that we can dump a group of lines when these tokens | 
| 556 |  |  |  |  |  |  | # change. | 
| 557 |  |  |  |  |  |  | # | 
| 558 |  |  |  |  |  |  | # The fields contain the actual characters of each field.  The patterns | 
| 559 |  |  |  |  |  |  | # are like the fields, but they contain mainly token types instead | 
| 560 |  |  |  |  |  |  | # of tokens, so they have fewer characters.  They are used to be | 
| 561 |  |  |  |  |  |  | # sure we are matching fields of similar type. | 
| 562 |  |  |  |  |  |  | # | 
| 563 |  |  |  |  |  |  | # In this example, there will be 4 column indexes being adjusted.  The | 
| 564 |  |  |  |  |  |  | # first one is always at zero.  The interior columns are at the start of | 
| 565 |  |  |  |  |  |  | # the matching tokens, and the last one tracks the maximum line length. | 
| 566 |  |  |  |  |  |  | # | 
| 567 |  |  |  |  |  |  | # Each time a new line comes in, it joins the current vertical | 
| 568 |  |  |  |  |  |  | # group if possible.  Otherwise it causes the current group to be flushed | 
| 569 |  |  |  |  |  |  | # and a new group is started. | 
| 570 |  |  |  |  |  |  | # | 
| 571 |  |  |  |  |  |  | # For each new group member, the column locations are increased, as | 
| 572 |  |  |  |  |  |  | # necessary, to make room for the new fields.  When the group is finally | 
| 573 |  |  |  |  |  |  | # output, these column numbers are used to compute the amount of spaces of | 
| 574 |  |  |  |  |  |  | # padding needed for each field. | 
| 575 |  |  |  |  |  |  | # | 
| 576 |  |  |  |  |  |  | # Programming note: the fields are assumed not to have any tab characters. | 
| 577 |  |  |  |  |  |  | # Tabs have been previously removed except for tabs in quoted strings and | 
| 578 |  |  |  |  |  |  | # side comments.  Tabs in these fields can mess up the column counting. | 
| 579 |  |  |  |  |  |  | # The log file warns the user if there are any such tabs. | 
| 580 |  |  |  |  |  |  |  | 
| 581 | 7376 |  |  | 7376 | 0 | 16254 | my ( $self, $rcall_hash ) = @_; | 
| 582 |  |  |  |  |  |  |  | 
| 583 |  |  |  |  |  |  | # Unpack the call args. This form is significantly faster than getting them | 
| 584 |  |  |  |  |  |  | # one-by-one. | 
| 585 |  |  |  |  |  |  | my ( | 
| 586 |  |  |  |  |  |  |  | 
| 587 |  |  |  |  |  |  | $Kend, | 
| 588 |  |  |  |  |  |  | $break_alignment_after, | 
| 589 |  |  |  |  |  |  | $break_alignment_before, | 
| 590 |  |  |  |  |  |  | $ci_level, | 
| 591 |  |  |  |  |  |  | $forget_side_comment, | 
| 592 |  |  |  |  |  |  | $indentation, | 
| 593 |  |  |  |  |  |  | $is_terminal_ternary, | 
| 594 |  |  |  |  |  |  | $level, | 
| 595 |  |  |  |  |  |  | $level_end, | 
| 596 |  |  |  |  |  |  | $list_seqno, | 
| 597 |  |  |  |  |  |  | $maximum_line_length, | 
| 598 |  |  |  |  |  |  | $outdent_long_lines, | 
| 599 |  |  |  |  |  |  | $rline_alignment, | 
| 600 |  |  |  |  |  |  | $rvertical_tightness_flags, | 
| 601 |  |  |  |  |  |  |  | 
| 602 |  |  |  |  |  |  | ) = | 
| 603 |  |  |  |  |  |  |  | 
| 604 | 7376 |  |  |  |  | 28592 | @{$rcall_hash}{ | 
| 605 | 7376 |  |  |  |  | 14181 | qw( | 
| 606 |  |  |  |  |  |  | Kend | 
| 607 |  |  |  |  |  |  | break_alignment_after | 
| 608 |  |  |  |  |  |  | break_alignment_before | 
| 609 |  |  |  |  |  |  | ci_level | 
| 610 |  |  |  |  |  |  | forget_side_comment | 
| 611 |  |  |  |  |  |  | indentation | 
| 612 |  |  |  |  |  |  | is_terminal_ternary | 
| 613 |  |  |  |  |  |  | level | 
| 614 |  |  |  |  |  |  | level_end | 
| 615 |  |  |  |  |  |  | list_seqno | 
| 616 |  |  |  |  |  |  | maximum_line_length | 
| 617 |  |  |  |  |  |  | outdent_long_lines | 
| 618 |  |  |  |  |  |  | rline_alignment | 
| 619 |  |  |  |  |  |  | rvertical_tightness_flags | 
| 620 |  |  |  |  |  |  | ) | 
| 621 |  |  |  |  |  |  | }; | 
| 622 |  |  |  |  |  |  |  | 
| 623 |  |  |  |  |  |  | my ( $rtokens, $rfields, $rpatterns, $rfield_lengths ) = | 
| 624 | 7376 |  |  |  |  | 12053 | @{$rline_alignment}; | 
|  | 7376 |  |  |  |  | 14268 |  | 
| 625 |  |  |  |  |  |  |  | 
| 626 |  |  |  |  |  |  | # The index '$Kend' is a value which passed along with the line text to sub | 
| 627 |  |  |  |  |  |  | # 'write_code_line' for a convergence check. | 
| 628 |  |  |  |  |  |  |  | 
| 629 |  |  |  |  |  |  | # number of fields is $jmax | 
| 630 |  |  |  |  |  |  | # number of tokens between fields is $jmax-1 | 
| 631 | 7376 |  |  |  |  | 10569 | my $jmax = @{$rfields} - 1; | 
|  | 7376 |  |  |  |  | 12435 |  | 
| 632 |  |  |  |  |  |  |  | 
| 633 | 7376 | 100 |  |  |  | 16221 | my $leading_space_count = | 
| 634 |  |  |  |  |  |  | ref($indentation) ? $indentation->get_spaces() : $indentation; | 
| 635 |  |  |  |  |  |  |  | 
| 636 |  |  |  |  |  |  | # set outdented flag to be sure we either align within statements or | 
| 637 |  |  |  |  |  |  | # across statement boundaries, but not both. | 
| 638 | 7376 |  |  |  |  | 13943 | my $is_outdented = | 
| 639 |  |  |  |  |  |  | $self->[_last_leading_space_count_] > $leading_space_count; | 
| 640 | 7376 |  |  |  |  | 12109 | $self->[_last_leading_space_count_] = $leading_space_count; | 
| 641 |  |  |  |  |  |  |  | 
| 642 |  |  |  |  |  |  | # Identify a hanging side comment.  Hanging side comments have an empty | 
| 643 |  |  |  |  |  |  | # initial field. | 
| 644 | 7376 |  | 100 |  |  | 25124 | my $is_hanging_side_comment = | 
| 645 |  |  |  |  |  |  | ( $jmax == 1 && $rtokens->[0] eq '#' && $rfields->[0] =~ /^\s*$/ ); | 
| 646 |  |  |  |  |  |  |  | 
| 647 |  |  |  |  |  |  | # Undo outdented flag for a hanging side comment | 
| 648 | 7376 | 100 |  |  |  | 14918 | $is_outdented = 0 if $is_hanging_side_comment; | 
| 649 |  |  |  |  |  |  |  | 
| 650 |  |  |  |  |  |  | # Identify a block comment. | 
| 651 | 7376 |  | 100 |  |  | 22925 | my $is_block_comment = $jmax == 0 && substr( $rfields->[0], 0, 1 ) eq '#'; | 
| 652 |  |  |  |  |  |  |  | 
| 653 |  |  |  |  |  |  | # Block comment .. update count | 
| 654 | 7376 | 100 |  |  |  | 14078 | if ($is_block_comment) { | 
| 655 | 632 |  |  |  |  | 1273 | $self->[_consecutive_block_comments_]++; | 
| 656 |  |  |  |  |  |  | } | 
| 657 |  |  |  |  |  |  |  | 
| 658 |  |  |  |  |  |  | # Not a block comment .. | 
| 659 |  |  |  |  |  |  | # Forget side comment column if we saw 2 or more block comments, | 
| 660 |  |  |  |  |  |  | # and reset the count | 
| 661 |  |  |  |  |  |  | else { | 
| 662 |  |  |  |  |  |  |  | 
| 663 | 6744 | 100 |  |  |  | 14899 | if ( $self->[_consecutive_block_comments_] > 1 ) { | 
| 664 | 67 |  |  |  |  | 396 | $self->forget_side_comment(); | 
| 665 |  |  |  |  |  |  | } | 
| 666 | 6744 |  |  |  |  | 11090 | $self->[_consecutive_block_comments_] = 0; | 
| 667 |  |  |  |  |  |  | } | 
| 668 |  |  |  |  |  |  |  | 
| 669 |  |  |  |  |  |  | # Reset side comment location if we are entering a new block from level 0. | 
| 670 |  |  |  |  |  |  | # This is intended to keep them from drifting too far to the right. | 
| 671 | 7376 | 100 |  |  |  | 14329 | if ($forget_side_comment) { | 
| 672 | 44 |  |  |  |  | 292 | $self->forget_side_comment(); | 
| 673 |  |  |  |  |  |  | } | 
| 674 |  |  |  |  |  |  |  | 
| 675 | 7376 |  |  |  |  | 12363 | my $is_balanced_line = $level_end == $level; | 
| 676 |  |  |  |  |  |  |  | 
| 677 | 7376 |  |  |  |  | 11860 | my $group_level               = $self->[_group_level_]; | 
| 678 | 7376 |  |  |  |  | 11632 | my $group_maximum_line_length = $self->[_group_maximum_line_length_]; | 
| 679 |  |  |  |  |  |  |  | 
| 680 | 7376 |  |  |  |  | 9960 | DEBUG_VALIGN && do { | 
| 681 |  |  |  |  |  |  | my $nlines = $self->group_line_count(); | 
| 682 |  |  |  |  |  |  | print {*STDOUT} | 
| 683 |  |  |  |  |  |  | "Entering valign_input: lines=$nlines new #fields= $jmax, leading_count=$leading_space_count, level=$level, group_level=$group_level, level_end=$level_end\n"; | 
| 684 |  |  |  |  |  |  | }; | 
| 685 |  |  |  |  |  |  |  | 
| 686 |  |  |  |  |  |  | # Validate cached line if necessary: If we can produce a container | 
| 687 |  |  |  |  |  |  | # with just 2 lines total by combining an existing cached opening | 
| 688 |  |  |  |  |  |  | # token with the closing token to follow, then we will mark both | 
| 689 |  |  |  |  |  |  | # cached flags as valid. | 
| 690 | 7376 |  |  |  |  | 17715 | my $cached_line_type = get_cached_line_type(); | 
| 691 | 7376 | 100 |  |  |  | 15571 | if ($cached_line_type) { | 
| 692 | 224 |  |  |  |  | 599 | my $cached_line_opening_flag = get_cached_line_opening_flag(); | 
| 693 | 224 | 50 |  |  |  | 587 | if ($rvertical_tightness_flags) { | 
| 694 | 224 |  |  |  |  | 590 | my $cached_seqno = get_cached_seqno(); | 
| 695 | 224 | 100 | 100 |  |  | 1088 | if (   $cached_seqno | 
|  |  |  | 100 |  |  |  |  | 
| 696 |  |  |  |  |  |  | && $rvertical_tightness_flags->{_vt_seqno} | 
| 697 |  |  |  |  |  |  | && $rvertical_tightness_flags->{_vt_seqno} == $cached_seqno ) | 
| 698 |  |  |  |  |  |  | { | 
| 699 |  |  |  |  |  |  |  | 
| 700 |  |  |  |  |  |  | # Fix for b1187 and b1188: Normally this step is only done | 
| 701 |  |  |  |  |  |  | # if the number of existing lines is 0 or 1.  But to prevent | 
| 702 |  |  |  |  |  |  | # blinking, this range can be controlled by the caller. | 
| 703 |  |  |  |  |  |  | # If zero values are given we fall back on the range 0 to 1. | 
| 704 | 4 |  |  |  |  | 22 | my $line_count = $self->group_line_count(); | 
| 705 | 4 |  |  |  |  | 9 | my $min_lines  = $rvertical_tightness_flags->{_vt_min_lines}; | 
| 706 | 4 |  |  |  |  | 10 | my $max_lines  = $rvertical_tightness_flags->{_vt_max_lines}; | 
| 707 | 4 | 50 |  |  |  | 22 | $min_lines = 0 if ( !$min_lines ); | 
| 708 | 4 | 50 |  |  |  | 16 | $max_lines = 1 if ( !$max_lines ); | 
| 709 | 4 | 100 | 66 |  |  | 29 | if (   ( $line_count >= $min_lines ) | 
| 710 |  |  |  |  |  |  | && ( $line_count <= $max_lines ) ) | 
| 711 |  |  |  |  |  |  | { | 
| 712 | 3 |  | 50 |  |  | 18 | $rvertical_tightness_flags->{_vt_valid_flag} ||= 1; | 
| 713 | 3 |  |  |  |  | 39 | set_cached_line_valid(1); | 
| 714 |  |  |  |  |  |  | } | 
| 715 |  |  |  |  |  |  | } | 
| 716 |  |  |  |  |  |  | } | 
| 717 |  |  |  |  |  |  |  | 
| 718 |  |  |  |  |  |  | # do not join an opening block brace (type 3, see VTFLAGS) | 
| 719 |  |  |  |  |  |  | # with an unbalanced line unless requested with a flag value of 2 | 
| 720 | 224 | 50 | 100 |  |  | 691 | if (   $cached_line_type == 3 | 
|  |  |  | 66 |  |  |  |  | 
|  |  |  | 66 |  |  |  |  | 
| 721 |  |  |  |  |  |  | && !$self->group_line_count() | 
| 722 |  |  |  |  |  |  | && $cached_line_opening_flag < 2 | 
| 723 |  |  |  |  |  |  | && !$is_balanced_line ) | 
| 724 |  |  |  |  |  |  | { | 
| 725 | 0 |  |  |  |  | 0 | set_cached_line_valid(0); | 
| 726 |  |  |  |  |  |  | } | 
| 727 |  |  |  |  |  |  | } | 
| 728 |  |  |  |  |  |  |  | 
| 729 |  |  |  |  |  |  | # shouldn't happen: | 
| 730 | 7376 | 50 |  |  |  | 15819 | if ( $level < 0 ) { $level = 0 } | 
|  | 0 |  |  |  |  | 0 |  | 
| 731 |  |  |  |  |  |  |  | 
| 732 |  |  |  |  |  |  | # do not align code across indentation level changes | 
| 733 |  |  |  |  |  |  | # or changes in the maximum line length | 
| 734 |  |  |  |  |  |  | # or if vertical alignment is turned off | 
| 735 | 7376 | 100 | 66 |  |  | 57626 | if ( | 
|  |  |  | 66 |  |  |  |  | 
|  |  |  | 66 |  |  |  |  | 
|  |  |  | 100 |  |  |  |  | 
|  |  |  | 100 |  |  |  |  | 
|  |  |  | 100 |  |  |  |  | 
|  |  |  | 100 |  |  |  |  | 
| 736 |  |  |  |  |  |  | $level != $group_level | 
| 737 |  |  |  |  |  |  | || (   $group_maximum_line_length | 
| 738 |  |  |  |  |  |  | && $maximum_line_length != $group_maximum_line_length ) | 
| 739 |  |  |  |  |  |  | || $is_outdented | 
| 740 |  |  |  |  |  |  | || ( $is_block_comment && !$self->[_rOpts_valign_block_comments_] ) | 
| 741 |  |  |  |  |  |  | || (   !$is_block_comment | 
| 742 |  |  |  |  |  |  | && !$self->[_rOpts_valign_side_comments_] | 
| 743 |  |  |  |  |  |  | && !$self->[_rOpts_valign_code_] ) | 
| 744 |  |  |  |  |  |  | ) | 
| 745 |  |  |  |  |  |  | { | 
| 746 |  |  |  |  |  |  |  | 
| 747 | 2837 |  |  |  |  | 11282 | $self->_flush_group_lines( $level - $group_level ); | 
| 748 |  |  |  |  |  |  |  | 
| 749 | 2837 |  |  |  |  | 5170 | $group_level                         = $level; | 
| 750 | 2837 |  |  |  |  | 5094 | $self->[_group_level_]               = $group_level; | 
| 751 | 2837 |  |  |  |  | 4646 | $self->[_group_maximum_line_length_] = $maximum_line_length; | 
| 752 |  |  |  |  |  |  |  | 
| 753 |  |  |  |  |  |  | # Update leading spaces after the above flush because the leading space | 
| 754 |  |  |  |  |  |  | # count may have been changed if the -icp flag is in effect | 
| 755 | 2837 | 100 |  |  |  | 6460 | $leading_space_count = | 
| 756 |  |  |  |  |  |  | ref($indentation) ? $indentation->get_spaces() : $indentation; | 
| 757 |  |  |  |  |  |  | } | 
| 758 |  |  |  |  |  |  |  | 
| 759 |  |  |  |  |  |  | # -------------------------------------------------------------------- | 
| 760 |  |  |  |  |  |  | # Collect outdentable block COMMENTS | 
| 761 |  |  |  |  |  |  | # -------------------------------------------------------------------- | 
| 762 | 7376 | 100 |  |  |  | 17178 | if ( $self->[_group_type_] eq 'COMMENT' ) { | 
| 763 | 558 | 100 | 66 |  |  | 3146 | if (   $is_block_comment | 
|  |  |  | 66 |  |  |  |  | 
| 764 |  |  |  |  |  |  | && $outdent_long_lines | 
| 765 |  |  |  |  |  |  | && $leading_space_count == $self->[_comment_leading_space_count_] ) | 
| 766 |  |  |  |  |  |  | { | 
| 767 |  |  |  |  |  |  |  | 
| 768 |  |  |  |  |  |  | # Note that for a comment group we are not storing a line | 
| 769 |  |  |  |  |  |  | # but rather just the text and its length. | 
| 770 | 77 |  |  |  |  | 173 | push @{ $self->[_rgroup_lines_] }, | 
|  | 77 |  |  |  |  | 345 |  | 
| 771 |  |  |  |  |  |  | [ $rfields->[0], $rfield_lengths->[0], $Kend ]; | 
| 772 | 77 |  |  |  |  | 273 | return; | 
| 773 |  |  |  |  |  |  | } | 
| 774 |  |  |  |  |  |  | else { | 
| 775 | 481 |  |  |  |  | 1973 | $self->_flush_group_lines(); | 
| 776 |  |  |  |  |  |  | } | 
| 777 |  |  |  |  |  |  | } | 
| 778 |  |  |  |  |  |  |  | 
| 779 | 7299 |  |  |  |  | 11605 | my $rgroup_lines = $self->[_rgroup_lines_]; | 
| 780 | 7299 | 100 | 100 |  |  | 16854 | if ( $break_alignment_before && @{$rgroup_lines} ) { | 
|  | 111 |  |  |  |  | 537 |  | 
| 781 | 27 |  |  |  |  | 91 | $rgroup_lines->[-1]->{'end_group'} = 1; | 
| 782 |  |  |  |  |  |  | } | 
| 783 |  |  |  |  |  |  |  | 
| 784 |  |  |  |  |  |  | # -------------------------------------------------------------------- | 
| 785 |  |  |  |  |  |  | # add dummy fields for terminal ternary | 
| 786 |  |  |  |  |  |  | # -------------------------------------------------------------------- | 
| 787 | 7299 |  |  |  |  | 10690 | my $j_terminal_match; | 
| 788 |  |  |  |  |  |  |  | 
| 789 | 7299 | 100 | 100 |  |  | 16147 | if ( $is_terminal_ternary && @{$rgroup_lines} ) { | 
|  | 16 |  |  |  |  | 96 |  | 
| 790 | 13 |  |  |  |  | 124 | $j_terminal_match = | 
| 791 |  |  |  |  |  |  | fix_terminal_ternary( $rgroup_lines->[-1], $rfields, $rtokens, | 
| 792 |  |  |  |  |  |  | $rpatterns, $rfield_lengths, $group_level, ); | 
| 793 | 13 |  |  |  |  | 29 | $jmax = @{$rfields} - 1; | 
|  | 13 |  |  |  |  | 37 |  | 
| 794 |  |  |  |  |  |  | } | 
| 795 |  |  |  |  |  |  |  | 
| 796 |  |  |  |  |  |  | # -------------------------------------------------------------------- | 
| 797 |  |  |  |  |  |  | # add dummy fields for else statement | 
| 798 |  |  |  |  |  |  | # -------------------------------------------------------------------- | 
| 799 |  |  |  |  |  |  |  | 
| 800 |  |  |  |  |  |  | # Note the trailing space after 'else' here. If there were no space between | 
| 801 |  |  |  |  |  |  | # the else and the next '{' then we would not be able to do vertical | 
| 802 |  |  |  |  |  |  | # alignment of the '{'. | 
| 803 | 7299 | 100 | 100 |  |  | 18420 | if (   $rfields->[0] eq 'else ' | 
|  |  |  | 66 |  |  |  |  | 
| 804 | 12 |  |  |  |  | 124 | && @{$rgroup_lines} | 
| 805 |  |  |  |  |  |  | && $is_balanced_line ) | 
| 806 |  |  |  |  |  |  | { | 
| 807 |  |  |  |  |  |  |  | 
| 808 | 9 |  |  |  |  | 194 | $j_terminal_match = | 
| 809 |  |  |  |  |  |  | fix_terminal_else( $rgroup_lines->[-1], $rfields, $rtokens, | 
| 810 |  |  |  |  |  |  | $rpatterns, $rfield_lengths ); | 
| 811 | 9 |  |  |  |  | 19 | $jmax = @{$rfields} - 1; | 
|  | 9 |  |  |  |  | 24 |  | 
| 812 |  |  |  |  |  |  | } | 
| 813 |  |  |  |  |  |  |  | 
| 814 |  |  |  |  |  |  | # -------------------------------------------------------------------- | 
| 815 |  |  |  |  |  |  | # Handle simple line of code with no fields to match. | 
| 816 |  |  |  |  |  |  | # -------------------------------------------------------------------- | 
| 817 | 7299 | 100 |  |  |  | 14681 | if ( $jmax <= 0 ) { | 
| 818 | 4278 |  |  |  |  | 7785 | $self->[_zero_count_]++; | 
| 819 |  |  |  |  |  |  |  | 
| 820 | 4278 | 100 | 100 |  |  | 6079 | if ( @{$rgroup_lines} | 
|  | 4278 |  |  |  |  | 12857 |  | 
| 821 |  |  |  |  |  |  | && !get_recoverable_spaces( $rgroup_lines->[0]->{'indentation'} ) ) | 
| 822 |  |  |  |  |  |  | { | 
| 823 |  |  |  |  |  |  |  | 
| 824 |  |  |  |  |  |  | # flush the current group if it has some aligned columns.. | 
| 825 |  |  |  |  |  |  | # or we haven't seen a comment lately | 
| 826 | 337 | 100 | 100 |  |  | 1738 | if (   $rgroup_lines->[0]->{'jmax'} > 1 | 
| 827 |  |  |  |  |  |  | || $self->[_zero_count_] > 3 ) | 
| 828 |  |  |  |  |  |  | { | 
| 829 | 308 |  |  |  |  | 1238 | $self->_flush_group_lines(); | 
| 830 |  |  |  |  |  |  |  | 
| 831 |  |  |  |  |  |  | # Update '$rgroup_lines' - it will become a ref to empty array. | 
| 832 |  |  |  |  |  |  | # This allows avoiding a call to get_group_line_count below. | 
| 833 | 308 |  |  |  |  | 967 | $rgroup_lines = $self->[_rgroup_lines_]; | 
| 834 |  |  |  |  |  |  | } | 
| 835 |  |  |  |  |  |  | } | 
| 836 |  |  |  |  |  |  |  | 
| 837 |  |  |  |  |  |  | # start new COMMENT group if this comment may be outdented | 
| 838 | 4278 | 100 | 100 |  |  | 12419 | if (   $is_block_comment | 
|  |  |  | 66 |  |  |  |  | 
| 839 |  |  |  |  |  |  | && $outdent_long_lines | 
| 840 | 531 |  |  |  |  | 1936 | && !@{$rgroup_lines} ) | 
| 841 |  |  |  |  |  |  | { | 
| 842 | 531 |  |  |  |  | 1350 | $self->[_group_type_]                  = 'COMMENT'; | 
| 843 | 531 |  |  |  |  | 1117 | $self->[_comment_leading_space_count_] = $leading_space_count; | 
| 844 | 531 |  |  |  |  | 1015 | $self->[_group_maximum_line_length_]   = $maximum_line_length; | 
| 845 | 531 |  |  |  |  | 949 | push @{$rgroup_lines}, | 
|  | 531 |  |  |  |  | 1933 |  | 
| 846 |  |  |  |  |  |  | [ $rfields->[0], $rfield_lengths->[0], $Kend ]; | 
| 847 | 531 |  |  |  |  | 1994 | return; | 
| 848 |  |  |  |  |  |  | } | 
| 849 |  |  |  |  |  |  |  | 
| 850 |  |  |  |  |  |  | # just write this line directly if no current group, no side comment, | 
| 851 |  |  |  |  |  |  | # and no space recovery is needed. | 
| 852 | 3747 | 100 | 100 |  |  | 5623 | if (   !@{$rgroup_lines} | 
|  | 3747 |  |  |  |  | 13042 |  | 
| 853 |  |  |  |  |  |  | && !get_recoverable_spaces($indentation) ) | 
| 854 |  |  |  |  |  |  | { | 
| 855 |  |  |  |  |  |  |  | 
| 856 | 3703 |  |  |  |  | 33677 | $self->valign_output_step_B( | 
| 857 |  |  |  |  |  |  | { | 
| 858 |  |  |  |  |  |  | leading_space_count       => $leading_space_count, | 
| 859 |  |  |  |  |  |  | line                      => $rfields->[0], | 
| 860 |  |  |  |  |  |  | line_length               => $rfield_lengths->[0], | 
| 861 |  |  |  |  |  |  | side_comment_length       => 0, | 
| 862 |  |  |  |  |  |  | outdent_long_lines        => $outdent_long_lines, | 
| 863 |  |  |  |  |  |  | rvertical_tightness_flags => $rvertical_tightness_flags, | 
| 864 |  |  |  |  |  |  | level                     => $level, | 
| 865 |  |  |  |  |  |  | level_end                 => $level_end, | 
| 866 |  |  |  |  |  |  | Kend                      => $Kend, | 
| 867 |  |  |  |  |  |  | maximum_line_length       => $maximum_line_length, | 
| 868 |  |  |  |  |  |  | } | 
| 869 |  |  |  |  |  |  | ); | 
| 870 | 3703 |  |  |  |  | 16413 | return; | 
| 871 |  |  |  |  |  |  | } | 
| 872 |  |  |  |  |  |  | } | 
| 873 |  |  |  |  |  |  | else { | 
| 874 | 3021 |  |  |  |  | 5987 | $self->[_zero_count_] = 0; | 
| 875 |  |  |  |  |  |  | } | 
| 876 |  |  |  |  |  |  |  | 
| 877 |  |  |  |  |  |  | # -------------------------------------------------------------------- | 
| 878 |  |  |  |  |  |  | # It simplifies things to create a zero length side comment | 
| 879 |  |  |  |  |  |  | # if none exists. | 
| 880 |  |  |  |  |  |  | # -------------------------------------------------------------------- | 
| 881 | 3065 | 100 | 100 |  |  | 13558 | if ( ( $jmax == 0 ) || ( $rtokens->[ $jmax - 1 ] ne '#' ) ) { | 
| 882 | 2740 |  |  |  |  | 4678 | $jmax += 1; | 
| 883 | 2740 |  |  |  |  | 5804 | $rtokens->[ $jmax - 1 ]  = '#'; | 
| 884 | 2740 |  |  |  |  | 5419 | $rfields->[$jmax]        = EMPTY_STRING; | 
| 885 | 2740 |  |  |  |  | 4843 | $rfield_lengths->[$jmax] = 0; | 
| 886 | 2740 |  |  |  |  | 5208 | $rpatterns->[$jmax]      = '#'; | 
| 887 |  |  |  |  |  |  | } | 
| 888 |  |  |  |  |  |  |  | 
| 889 |  |  |  |  |  |  | # -------------------------------------------------------------------- | 
| 890 |  |  |  |  |  |  | # create an object to hold this line | 
| 891 |  |  |  |  |  |  | # -------------------------------------------------------------------- | 
| 892 |  |  |  |  |  |  |  | 
| 893 |  |  |  |  |  |  | # The hash keys below must match the list of keys in %valid_LINE_keys. | 
| 894 |  |  |  |  |  |  | # Values in this hash are accessed directly, except for 'ralignments', | 
| 895 |  |  |  |  |  |  | # rather than with get/set calls for efficiency. | 
| 896 | 3065 |  |  |  |  | 52191 | my $new_line = Perl::Tidy::VerticalAligner::Line->new( | 
| 897 |  |  |  |  |  |  | { | 
| 898 |  |  |  |  |  |  | jmax                      => $jmax, | 
| 899 |  |  |  |  |  |  | rtokens                   => $rtokens, | 
| 900 |  |  |  |  |  |  | rfields                   => $rfields, | 
| 901 |  |  |  |  |  |  | rpatterns                 => $rpatterns, | 
| 902 |  |  |  |  |  |  | rfield_lengths            => $rfield_lengths, | 
| 903 |  |  |  |  |  |  | indentation               => $indentation, | 
| 904 |  |  |  |  |  |  | leading_space_count       => $leading_space_count, | 
| 905 |  |  |  |  |  |  | outdent_long_lines        => $outdent_long_lines, | 
| 906 |  |  |  |  |  |  | list_seqno                => $list_seqno, | 
| 907 |  |  |  |  |  |  | list_type                 => EMPTY_STRING, | 
| 908 |  |  |  |  |  |  | is_hanging_side_comment   => $is_hanging_side_comment, | 
| 909 |  |  |  |  |  |  | rvertical_tightness_flags => $rvertical_tightness_flags, | 
| 910 |  |  |  |  |  |  | is_terminal_ternary       => $is_terminal_ternary, | 
| 911 |  |  |  |  |  |  | j_terminal_match          => $j_terminal_match, | 
| 912 |  |  |  |  |  |  | end_group                 => $break_alignment_after, | 
| 913 |  |  |  |  |  |  | Kend                      => $Kend, | 
| 914 |  |  |  |  |  |  | ci_level                  => $ci_level, | 
| 915 |  |  |  |  |  |  | level                     => $level, | 
| 916 |  |  |  |  |  |  | level_end                 => $level_end, | 
| 917 |  |  |  |  |  |  | imax_pair                 => -1, | 
| 918 |  |  |  |  |  |  | maximum_line_length       => $maximum_line_length, | 
| 919 |  |  |  |  |  |  |  | 
| 920 |  |  |  |  |  |  | ralignments => [], | 
| 921 |  |  |  |  |  |  | } | 
| 922 |  |  |  |  |  |  | ); | 
| 923 |  |  |  |  |  |  |  | 
| 924 | 3065 |  |  |  |  | 5408 | DEVEL_MODE | 
| 925 |  |  |  |  |  |  | && check_keys( $new_line, \%valid_LINE_keys, | 
| 926 |  |  |  |  |  |  | "Checking line keys at line definition", 1 ); | 
| 927 |  |  |  |  |  |  |  | 
| 928 |  |  |  |  |  |  | # -------------------------------------------------------------------- | 
| 929 |  |  |  |  |  |  | # Decide if this is a simple list of items. | 
| 930 |  |  |  |  |  |  | # We use this to be less restrictive in deciding what to align. | 
| 931 |  |  |  |  |  |  | # -------------------------------------------------------------------- | 
| 932 | 3065 | 100 |  |  |  | 8818 | decide_if_list($new_line) if ($list_seqno); | 
| 933 |  |  |  |  |  |  |  | 
| 934 |  |  |  |  |  |  | # -------------------------------------------------------------------- | 
| 935 |  |  |  |  |  |  | # Append this line to the current group (or start new group) | 
| 936 |  |  |  |  |  |  | # -------------------------------------------------------------------- | 
| 937 |  |  |  |  |  |  |  | 
| 938 | 3065 |  |  |  |  | 4812 | push @{ $self->[_rgroup_lines_] }, $new_line; | 
|  | 3065 |  |  |  |  | 7525 |  | 
| 939 | 3065 |  |  |  |  | 5919 | $self->[_group_maximum_line_length_] = $maximum_line_length; | 
| 940 |  |  |  |  |  |  |  | 
| 941 |  |  |  |  |  |  | # output this group if it ends in a terminal else or ternary line | 
| 942 | 3065 | 100 | 100 |  |  | 17553 | if ( defined($j_terminal_match) ) { | 
|  |  | 100 |  |  |  |  |  | 
| 943 | 20 |  |  |  |  | 119 | $self->_flush_group_lines(); | 
| 944 |  |  |  |  |  |  | } | 
| 945 |  |  |  |  |  |  |  | 
| 946 |  |  |  |  |  |  | # Force break after jump to lower level | 
| 947 |  |  |  |  |  |  | elsif ($level_end < $level | 
| 948 |  |  |  |  |  |  | || $is_closing_token{ substr( $rfields->[0], 0, 1 ) } ) | 
| 949 |  |  |  |  |  |  | { | 
| 950 | 119 |  |  |  |  | 524 | $self->_flush_group_lines(-1); | 
| 951 |  |  |  |  |  |  | } | 
| 952 |  |  |  |  |  |  |  | 
| 953 |  |  |  |  |  |  | else { | 
| 954 |  |  |  |  |  |  | ##ok: no output needed | 
| 955 |  |  |  |  |  |  | } | 
| 956 |  |  |  |  |  |  |  | 
| 957 |  |  |  |  |  |  | # -------------------------------------------------------------------- | 
| 958 |  |  |  |  |  |  | # Some old debugging stuff | 
| 959 |  |  |  |  |  |  | # -------------------------------------------------------------------- | 
| 960 | 3065 |  |  |  |  | 4798 | DEBUG_VALIGN && do { | 
| 961 |  |  |  |  |  |  | print {*STDOUT} "exiting valign_input fields:"; | 
| 962 |  |  |  |  |  |  | dump_array( @{$rfields} ); | 
| 963 |  |  |  |  |  |  | print {*STDOUT} "exiting valign_input tokens:"; | 
| 964 |  |  |  |  |  |  | dump_array( @{$rtokens} ); | 
| 965 |  |  |  |  |  |  | print {*STDOUT} "exiting valign_input patterns:"; | 
| 966 |  |  |  |  |  |  | dump_array( @{$rpatterns} ); | 
| 967 |  |  |  |  |  |  | }; | 
| 968 |  |  |  |  |  |  |  | 
| 969 | 3065 |  |  |  |  | 9450 | return; | 
| 970 |  |  |  |  |  |  | } ## end sub valign_input | 
| 971 |  |  |  |  |  |  |  | 
| 972 |  |  |  |  |  |  | sub join_hanging_comment { | 
| 973 |  |  |  |  |  |  |  | 
| 974 |  |  |  |  |  |  | # Add dummy fields to a hanging side comment to make it look | 
| 975 |  |  |  |  |  |  | # like the first line in its potential group.  This simplifies | 
| 976 |  |  |  |  |  |  | # the coding. | 
| 977 | 38 |  |  | 38 | 0 | 98 | my ( $new_line, $old_line ) = @_; | 
| 978 |  |  |  |  |  |  |  | 
| 979 | 38 |  |  |  |  | 91 | my $jmax = $new_line->{'jmax'}; | 
| 980 |  |  |  |  |  |  |  | 
| 981 |  |  |  |  |  |  | # must be 2 fields | 
| 982 | 38 | 50 |  |  |  | 116 | return 0 unless $jmax == 1; | 
| 983 | 38 |  |  |  |  | 82 | my $rtokens = $new_line->{'rtokens'}; | 
| 984 |  |  |  |  |  |  |  | 
| 985 |  |  |  |  |  |  | # the second field must be a comment | 
| 986 | 38 | 50 |  |  |  | 119 | return 0 unless $rtokens->[0] eq '#'; | 
| 987 | 38 |  |  |  |  | 82 | my $rfields = $new_line->{'rfields'}; | 
| 988 |  |  |  |  |  |  |  | 
| 989 |  |  |  |  |  |  | # the first field must be empty | 
| 990 | 38 | 50 |  |  |  | 215 | return 0 if ( $rfields->[0] !~ /^\s*$/ ); | 
| 991 |  |  |  |  |  |  |  | 
| 992 |  |  |  |  |  |  | # the current line must have fewer fields | 
| 993 | 38 |  |  |  |  | 92 | my $maximum_field_index = $old_line->{'jmax'}; | 
| 994 | 38 | 100 |  |  |  | 123 | return 0 | 
| 995 |  |  |  |  |  |  | if ( $maximum_field_index <= $jmax ); | 
| 996 |  |  |  |  |  |  |  | 
| 997 |  |  |  |  |  |  | # looks ok.. | 
| 998 | 3 |  |  |  |  | 8 | my $rpatterns      = $new_line->{'rpatterns'}; | 
| 999 | 3 |  |  |  |  | 10 | my $rfield_lengths = $new_line->{'rfield_lengths'}; | 
| 1000 |  |  |  |  |  |  |  | 
| 1001 | 3 |  |  |  |  | 8 | $new_line->{'is_hanging_side_comment'} = 1; | 
| 1002 |  |  |  |  |  |  |  | 
| 1003 | 3 |  |  |  |  | 6 | $jmax                     = $maximum_field_index; | 
| 1004 | 3 |  |  |  |  | 6 | $new_line->{'jmax'}       = $jmax; | 
| 1005 | 3 |  |  |  |  | 8 | $rfields->[$jmax]         = $rfields->[1]; | 
| 1006 | 3 |  |  |  |  | 8 | $rfield_lengths->[$jmax]  = $rfield_lengths->[1]; | 
| 1007 | 3 |  |  |  |  | 11 | $rtokens->[ $jmax - 1 ]   = $rtokens->[0]; | 
| 1008 | 3 |  |  |  |  | 8 | $rpatterns->[ $jmax - 1 ] = $rpatterns->[0]; | 
| 1009 |  |  |  |  |  |  |  | 
| 1010 | 3 |  |  |  |  | 11 | foreach my $j ( 1 .. $jmax - 1 ) { | 
| 1011 | 3 |  |  |  |  | 7 | $rfields->[$j]         = EMPTY_STRING; | 
| 1012 | 3 |  |  |  |  | 8 | $rfield_lengths->[$j]  = 0; | 
| 1013 | 3 |  |  |  |  | 7 | $rtokens->[ $j - 1 ]   = EMPTY_STRING; | 
| 1014 | 3 |  |  |  |  | 8 | $rpatterns->[ $j - 1 ] = EMPTY_STRING; | 
| 1015 |  |  |  |  |  |  | } | 
| 1016 | 3 |  |  |  |  | 8 | return 1; | 
| 1017 |  |  |  |  |  |  | } ## end sub join_hanging_comment | 
| 1018 |  |  |  |  |  |  |  | 
| 1019 |  |  |  |  |  |  | {    ## closure for sub decide_if_list | 
| 1020 |  |  |  |  |  |  |  | 
| 1021 |  |  |  |  |  |  | my %is_comma_token; | 
| 1022 |  |  |  |  |  |  |  | 
| 1023 |  |  |  |  |  |  | BEGIN { | 
| 1024 |  |  |  |  |  |  |  | 
| 1025 | 39 |  |  | 39 |  | 268 | my @q = qw( => ); | 
| 1026 | 39 |  |  |  |  | 147 | push @q, ','; | 
| 1027 | 39 |  |  |  |  | 10470 | @is_comma_token{@q} = (1) x scalar(@q); | 
| 1028 |  |  |  |  |  |  | } ## end BEGIN | 
| 1029 |  |  |  |  |  |  |  | 
| 1030 |  |  |  |  |  |  | sub decide_if_list { | 
| 1031 |  |  |  |  |  |  |  | 
| 1032 | 1032 |  |  | 1032 | 0 | 1971 | my $line = shift; | 
| 1033 |  |  |  |  |  |  |  | 
| 1034 |  |  |  |  |  |  | # A list will be taken to be a line with a forced break in which all | 
| 1035 |  |  |  |  |  |  | # of the field separators are commas or comma-arrows (except for the | 
| 1036 |  |  |  |  |  |  | # trailing #) | 
| 1037 |  |  |  |  |  |  |  | 
| 1038 | 1032 |  |  |  |  | 2131 | my $rtokens    = $line->{'rtokens'}; | 
| 1039 | 1032 |  |  |  |  | 2207 | my $test_token = $rtokens->[0]; | 
| 1040 | 1032 |  |  |  |  | 2759 | my ( $raw_tok, $lev, $tag, $tok_count ) = | 
| 1041 |  |  |  |  |  |  | decode_alignment_token($test_token); | 
| 1042 | 1032 | 100 |  |  |  | 3188 | if ( $is_comma_token{$raw_tok} ) { | 
| 1043 | 930 |  |  |  |  | 1736 | my $list_type = $test_token; | 
| 1044 | 930 |  |  |  |  | 1682 | my $jmax      = $line->{'jmax'}; | 
| 1045 |  |  |  |  |  |  |  | 
| 1046 | 930 |  |  |  |  | 2767 | foreach ( 1 .. $jmax - 2 ) { | 
| 1047 | 871 |  |  |  |  | 1742 | ( $raw_tok, $lev, $tag, $tok_count ) = | 
| 1048 |  |  |  |  |  |  | decode_alignment_token( $rtokens->[$_] ); | 
| 1049 | 871 | 100 |  |  |  | 2403 | if ( !$is_comma_token{$raw_tok} ) { | 
| 1050 | 26 |  |  |  |  | 1051 | $list_type = EMPTY_STRING; | 
| 1051 | 26 |  |  |  |  | 86 | last; | 
| 1052 |  |  |  |  |  |  | } | 
| 1053 |  |  |  |  |  |  | } | 
| 1054 | 930 |  |  |  |  | 2212 | $line->{'list_type'} = $list_type; | 
| 1055 |  |  |  |  |  |  | } | 
| 1056 | 1032 |  |  |  |  | 1979 | return; | 
| 1057 |  |  |  |  |  |  | } ## end sub decide_if_list | 
| 1058 |  |  |  |  |  |  | } | 
| 1059 |  |  |  |  |  |  |  | 
| 1060 |  |  |  |  |  |  | sub fix_terminal_ternary { | 
| 1061 |  |  |  |  |  |  |  | 
| 1062 |  |  |  |  |  |  | # Add empty fields as necessary to align a ternary term | 
| 1063 |  |  |  |  |  |  | # like this: | 
| 1064 |  |  |  |  |  |  | # | 
| 1065 |  |  |  |  |  |  | #  my $leapyear = | 
| 1066 |  |  |  |  |  |  | #      $year % 4   ? 0 | 
| 1067 |  |  |  |  |  |  | #    : $year % 100 ? 1 | 
| 1068 |  |  |  |  |  |  | #    : $year % 400 ? 0 | 
| 1069 |  |  |  |  |  |  | #    :               1; | 
| 1070 |  |  |  |  |  |  | # | 
| 1071 |  |  |  |  |  |  | # returns the index of the terminal question token, if any | 
| 1072 |  |  |  |  |  |  |  | 
| 1073 | 13 |  |  | 13 | 0 | 57 | my ( $old_line, $rfields, $rtokens, $rpatterns, $rfield_lengths, | 
| 1074 |  |  |  |  |  |  | $group_level ) | 
| 1075 |  |  |  |  |  |  | = @_; | 
| 1076 |  |  |  |  |  |  |  | 
| 1077 | 13 | 50 |  |  |  | 52 | return if ( !$old_line ); | 
| 1078 | 39 |  |  | 39 |  | 345 | use constant EXPLAIN_TERNARY => 0; | 
|  | 39 |  |  |  |  | 104 |  | 
|  | 39 |  |  |  |  | 55541 |  | 
| 1079 |  |  |  |  |  |  |  | 
| 1080 | 13 | 50 |  |  |  | 62 | if (%valign_control_hash) { | 
| 1081 | 0 |  |  |  |  | 0 | my $align_ok = $valign_control_hash{'?'}; | 
| 1082 | 0 | 0 |  |  |  | 0 | $align_ok = $valign_control_default unless defined($align_ok); | 
| 1083 | 0 | 0 |  |  |  | 0 | return if ( !$align_ok ); | 
| 1084 |  |  |  |  |  |  | } | 
| 1085 |  |  |  |  |  |  |  | 
| 1086 | 13 |  |  |  |  | 30 | my $jmax        = @{$rfields} - 1; | 
|  | 13 |  |  |  |  | 44 |  | 
| 1087 | 13 |  |  |  |  | 41 | my $rfields_old = $old_line->{'rfields'}; | 
| 1088 |  |  |  |  |  |  |  | 
| 1089 | 13 |  |  |  |  | 40 | my $rpatterns_old       = $old_line->{'rpatterns'}; | 
| 1090 | 13 |  |  |  |  | 33 | my $rtokens_old         = $old_line->{'rtokens'}; | 
| 1091 | 13 |  |  |  |  | 33 | my $maximum_field_index = $old_line->{'jmax'}; | 
| 1092 |  |  |  |  |  |  |  | 
| 1093 |  |  |  |  |  |  | # look for the question mark after the : | 
| 1094 | 13 |  |  |  |  | 42 | my ($jquestion); | 
| 1095 |  |  |  |  |  |  | my $depth_question; | 
| 1096 | 13 |  |  |  |  | 48 | my $pad        = EMPTY_STRING; | 
| 1097 | 13 |  |  |  |  | 29 | my $pad_length = 0; | 
| 1098 | 13 |  |  |  |  | 55 | foreach my $j ( 0 .. $maximum_field_index - 1 ) { | 
| 1099 | 14 |  |  |  |  | 52 | my $tok = $rtokens_old->[$j]; | 
| 1100 | 14 |  |  |  |  | 71 | my ( $raw_tok, $lev, $tag, $tok_count ) = decode_alignment_token($tok); | 
| 1101 | 14 | 100 |  |  |  | 63 | if ( $raw_tok eq '?' ) { | 
| 1102 | 13 |  |  |  |  | 33 | $depth_question = $lev; | 
| 1103 |  |  |  |  |  |  |  | 
| 1104 |  |  |  |  |  |  | # depth must be correct | 
| 1105 | 13 | 50 |  |  |  | 76 | next if ( $depth_question ne $group_level ); | 
| 1106 |  |  |  |  |  |  |  | 
| 1107 | 13 |  |  |  |  | 44 | $jquestion = $j; | 
| 1108 | 13 | 50 |  |  |  | 118 | if ( $rfields_old->[ $j + 1 ] =~ /^(\?\s*)/ ) { | 
| 1109 | 13 |  |  |  |  | 54 | $pad_length = length($1); | 
| 1110 | 13 |  |  |  |  | 55 | $pad        = SPACE x $pad_length; | 
| 1111 |  |  |  |  |  |  | } | 
| 1112 |  |  |  |  |  |  | else { | 
| 1113 | 0 |  |  |  |  | 0 | return;    # shouldn't happen | 
| 1114 |  |  |  |  |  |  | } | 
| 1115 | 13 |  |  |  |  | 41 | last; | 
| 1116 |  |  |  |  |  |  | } | 
| 1117 |  |  |  |  |  |  | } | 
| 1118 | 13 | 50 |  |  |  | 56 | return if ( !defined($jquestion) );    # shouldn't happen | 
| 1119 |  |  |  |  |  |  |  | 
| 1120 |  |  |  |  |  |  | # Now splice the tokens and patterns of the previous line | 
| 1121 |  |  |  |  |  |  | # into the else line to insure a match.  Add empty fields | 
| 1122 |  |  |  |  |  |  | # as necessary. | 
| 1123 | 13 |  |  |  |  | 29 | my $jadd = $jquestion; | 
| 1124 |  |  |  |  |  |  |  | 
| 1125 |  |  |  |  |  |  | # Work on copies of the actual arrays in case we have | 
| 1126 |  |  |  |  |  |  | # to return due to an error | 
| 1127 | 13 |  |  |  |  | 39 | my @fields        = @{$rfields}; | 
|  | 13 |  |  |  |  | 46 |  | 
| 1128 | 13 |  |  |  |  | 31 | my @patterns      = @{$rpatterns}; | 
|  | 13 |  |  |  |  | 46 |  | 
| 1129 | 13 |  |  |  |  | 39 | my @tokens        = @{$rtokens}; | 
|  | 13 |  |  |  |  | 46 |  | 
| 1130 | 13 |  |  |  |  | 31 | my @field_lengths = @{$rfield_lengths}; | 
|  | 13 |  |  |  |  | 39 |  | 
| 1131 |  |  |  |  |  |  |  | 
| 1132 | 13 |  |  |  |  | 28 | EXPLAIN_TERNARY && do { | 
| 1133 |  |  |  |  |  |  | local $LIST_SEPARATOR = '><'; | 
| 1134 |  |  |  |  |  |  | print {*STDOUT} "CURRENT FIELDS=<@{$rfields_old}>\n"; | 
| 1135 |  |  |  |  |  |  | print {*STDOUT} "CURRENT TOKENS=<@{$rtokens_old}>\n"; | 
| 1136 |  |  |  |  |  |  | print {*STDOUT} "CURRENT PATTERNS=<@{$rpatterns_old}>\n"; | 
| 1137 |  |  |  |  |  |  | print {*STDOUT} "UNMODIFIED FIELDS=<@{$rfields}>\n"; | 
| 1138 |  |  |  |  |  |  | print {*STDOUT} "UNMODIFIED TOKENS=<@{$rtokens}>\n"; | 
| 1139 |  |  |  |  |  |  | print {*STDOUT} "UNMODIFIED PATTERNS=<@{$rpatterns}>\n"; | 
| 1140 |  |  |  |  |  |  | }; | 
| 1141 |  |  |  |  |  |  |  | 
| 1142 |  |  |  |  |  |  | # handle cases of leading colon on this line | 
| 1143 | 13 | 50 |  |  |  | 93 | if ( $fields[0] =~ /^(:\s*)(.*)$/ ) { | 
| 1144 |  |  |  |  |  |  |  | 
| 1145 | 13 |  |  |  |  | 66 | my ( $colon, $therest ) = ( $1, $2 ); | 
| 1146 |  |  |  |  |  |  |  | 
| 1147 |  |  |  |  |  |  | # Handle sub-case of first field with leading colon plus additional code | 
| 1148 |  |  |  |  |  |  | # This is the usual situation as at the '1' below: | 
| 1149 |  |  |  |  |  |  | #  ... | 
| 1150 |  |  |  |  |  |  | #  : $year % 400 ? 0 | 
| 1151 |  |  |  |  |  |  | #  :               1; | 
| 1152 | 13 | 50 |  |  |  | 47 | if ($therest) { | 
| 1153 |  |  |  |  |  |  |  | 
| 1154 |  |  |  |  |  |  | # Split the first field after the leading colon and insert padding. | 
| 1155 |  |  |  |  |  |  | # Note that this padding will remain even if the terminal value goes | 
| 1156 |  |  |  |  |  |  | # out on a separate line.  This does not seem to look to bad, so no | 
| 1157 |  |  |  |  |  |  | # mechanism has been included to undo it. | 
| 1158 | 13 |  |  |  |  | 55 | my $field1        = shift @fields; | 
| 1159 | 13 |  |  |  |  | 48 | my $field_length1 = shift @field_lengths; | 
| 1160 | 13 |  |  |  |  | 57 | my $len_colon     = length($colon); | 
| 1161 | 13 |  |  |  |  | 60 | unshift @fields, ( $colon, $pad . $therest ); | 
| 1162 | 13 |  |  |  |  | 45 | unshift @field_lengths, | 
| 1163 |  |  |  |  |  |  | ( $len_colon, $pad_length + $field_length1 - $len_colon ); | 
| 1164 |  |  |  |  |  |  |  | 
| 1165 |  |  |  |  |  |  | # change the leading pattern from : to ? | 
| 1166 | 13 | 50 |  |  |  | 130 | return if ( $patterns[0] !~ s/^\:/?/ ); | 
| 1167 |  |  |  |  |  |  |  | 
| 1168 |  |  |  |  |  |  | # install leading tokens and patterns of existing line | 
| 1169 | 13 |  |  |  |  | 1140 | unshift( @tokens,   @{$rtokens_old}[ 0 .. $jquestion ] ); | 
|  | 13 |  |  |  |  | 64 |  | 
| 1170 | 13 |  |  |  |  | 53 | unshift( @patterns, @{$rpatterns_old}[ 0 .. $jquestion ] ); | 
|  | 13 |  |  |  |  | 46 |  | 
| 1171 |  |  |  |  |  |  |  | 
| 1172 |  |  |  |  |  |  | # insert appropriate number of empty fields | 
| 1173 | 13 | 100 |  |  |  | 53 | splice( @fields,        1, 0, (EMPTY_STRING) x $jadd ) if $jadd; | 
| 1174 | 13 | 100 |  |  |  | 63 | splice( @field_lengths, 1, 0, (0) x $jadd )            if $jadd; | 
| 1175 |  |  |  |  |  |  | } | 
| 1176 |  |  |  |  |  |  |  | 
| 1177 |  |  |  |  |  |  | # handle sub-case of first field just equal to leading colon. | 
| 1178 |  |  |  |  |  |  | # This can happen for example in the example below where | 
| 1179 |  |  |  |  |  |  | # the leading '(' would create a new alignment token | 
| 1180 |  |  |  |  |  |  | # : ( $name =~ /[]}]$/ ) ? ( $mname = $name ) | 
| 1181 |  |  |  |  |  |  | # :                        ( $mname = $name . '->' ); | 
| 1182 |  |  |  |  |  |  | else { | 
| 1183 |  |  |  |  |  |  |  | 
| 1184 | 0 | 0 | 0 |  |  | 0 | return if ( $jmax <= 0 || $tokens[0] eq '#' );    # shouldn't happen | 
| 1185 |  |  |  |  |  |  |  | 
| 1186 |  |  |  |  |  |  | # prepend a leading ? onto the second pattern | 
| 1187 | 0 |  |  |  |  | 0 | $patterns[1] = "?b" . $patterns[1]; | 
| 1188 |  |  |  |  |  |  |  | 
| 1189 |  |  |  |  |  |  | # pad the second field | 
| 1190 | 0 |  |  |  |  | 0 | $fields[1]        = $pad . $fields[1]; | 
| 1191 | 0 |  |  |  |  | 0 | $field_lengths[1] = $pad_length + $field_lengths[1]; | 
| 1192 |  |  |  |  |  |  |  | 
| 1193 |  |  |  |  |  |  | # install leading tokens and patterns of existing line, replacing | 
| 1194 |  |  |  |  |  |  | # leading token and inserting appropriate number of empty fields | 
| 1195 | 0 |  |  |  |  | 0 | splice( @tokens,   0, 1, @{$rtokens_old}[ 0 .. $jquestion ] ); | 
|  | 0 |  |  |  |  | 0 |  | 
| 1196 | 0 |  |  |  |  | 0 | splice( @patterns, 1, 0, @{$rpatterns_old}[ 1 .. $jquestion ] ); | 
|  | 0 |  |  |  |  | 0 |  | 
| 1197 | 0 | 0 |  |  |  | 0 | splice( @fields,        1, 0, (EMPTY_STRING) x $jadd ) if $jadd; | 
| 1198 | 0 | 0 |  |  |  | 0 | splice( @field_lengths, 1, 0, (0) x $jadd )            if $jadd; | 
| 1199 |  |  |  |  |  |  | } | 
| 1200 |  |  |  |  |  |  | } | 
| 1201 |  |  |  |  |  |  |  | 
| 1202 |  |  |  |  |  |  | # Handle case of no leading colon on this line.  This will | 
| 1203 |  |  |  |  |  |  | # be the case when -wba=':' is used.  For example, | 
| 1204 |  |  |  |  |  |  | #  $year % 400 ? 0 : | 
| 1205 |  |  |  |  |  |  | #                1; | 
| 1206 |  |  |  |  |  |  | else { | 
| 1207 |  |  |  |  |  |  |  | 
| 1208 |  |  |  |  |  |  | # install leading tokens and patterns of existing line | 
| 1209 | 0 |  |  |  |  | 0 | $patterns[0] = '?' . 'b' . $patterns[0]; | 
| 1210 | 0 |  |  |  |  | 0 | unshift( @tokens,   @{$rtokens_old}[ 0 .. $jquestion ] ); | 
|  | 0 |  |  |  |  | 0 |  | 
| 1211 | 0 |  |  |  |  | 0 | unshift( @patterns, @{$rpatterns_old}[ 0 .. $jquestion ] ); | 
|  | 0 |  |  |  |  | 0 |  | 
| 1212 |  |  |  |  |  |  |  | 
| 1213 |  |  |  |  |  |  | # insert appropriate number of empty fields | 
| 1214 | 0 |  |  |  |  | 0 | $jadd             = $jquestion + 1; | 
| 1215 | 0 |  |  |  |  | 0 | $fields[0]        = $pad . $fields[0]; | 
| 1216 | 0 |  |  |  |  | 0 | $field_lengths[0] = $pad_length + $field_lengths[0]; | 
| 1217 | 0 | 0 |  |  |  | 0 | splice( @fields,        0, 0, (EMPTY_STRING) x $jadd ) if $jadd; | 
| 1218 | 0 | 0 |  |  |  | 0 | splice( @field_lengths, 0, 0, (0) x $jadd )            if $jadd; | 
| 1219 |  |  |  |  |  |  | } | 
| 1220 |  |  |  |  |  |  |  | 
| 1221 | 13 |  |  |  |  | 28 | EXPLAIN_TERNARY && do { | 
| 1222 |  |  |  |  |  |  | local $LIST_SEPARATOR = '><'; | 
| 1223 |  |  |  |  |  |  | print {*STDOUT} "MODIFIED TOKENS=<@tokens>\n"; | 
| 1224 |  |  |  |  |  |  | print {*STDOUT} "MODIFIED PATTERNS=<@patterns>\n"; | 
| 1225 |  |  |  |  |  |  | print {*STDOUT} "MODIFIED FIELDS=<@fields>\n"; | 
| 1226 |  |  |  |  |  |  | }; | 
| 1227 |  |  |  |  |  |  |  | 
| 1228 |  |  |  |  |  |  | # all ok .. update the arrays | 
| 1229 | 13 |  |  |  |  | 38 | @{$rfields}        = @fields; | 
|  | 13 |  |  |  |  | 58 |  | 
| 1230 | 13 |  |  |  |  | 58 | @{$rtokens}        = @tokens; | 
|  | 13 |  |  |  |  | 51 |  | 
| 1231 | 13 |  |  |  |  | 28 | @{$rpatterns}      = @patterns; | 
|  | 13 |  |  |  |  | 51 |  | 
| 1232 | 13 |  |  |  |  | 33 | @{$rfield_lengths} = @field_lengths; | 
|  | 13 |  |  |  |  | 47 |  | 
| 1233 |  |  |  |  |  |  |  | 
| 1234 |  |  |  |  |  |  | # force a flush after this line | 
| 1235 | 13 |  |  |  |  | 52 | return $jquestion; | 
| 1236 |  |  |  |  |  |  | } ## end sub fix_terminal_ternary | 
| 1237 |  |  |  |  |  |  |  | 
| 1238 |  |  |  |  |  |  | sub fix_terminal_else { | 
| 1239 |  |  |  |  |  |  |  | 
| 1240 |  |  |  |  |  |  | # Add empty fields as necessary to align a balanced terminal | 
| 1241 |  |  |  |  |  |  | # else block to a previous if/elsif/unless block, | 
| 1242 |  |  |  |  |  |  | # like this: | 
| 1243 |  |  |  |  |  |  | # | 
| 1244 |  |  |  |  |  |  | #  if   ( 1 || $x ) { print "ok 13\n"; } | 
| 1245 |  |  |  |  |  |  | #  else             { print "not ok 13\n"; } | 
| 1246 |  |  |  |  |  |  | # | 
| 1247 |  |  |  |  |  |  | # returns a positive value if the else block should be indented | 
| 1248 |  |  |  |  |  |  | # | 
| 1249 | 9 |  |  | 9 | 0 | 39 | my ( $old_line, $rfields, $rtokens, $rpatterns, $rfield_lengths ) = @_; | 
| 1250 |  |  |  |  |  |  |  | 
| 1251 | 9 | 50 |  |  |  | 43 | return if ( !$old_line ); | 
| 1252 | 9 |  |  |  |  | 19 | my $jmax = @{$rfields} - 1; | 
|  | 9 |  |  |  |  | 33 |  | 
| 1253 | 9 | 50 |  |  |  | 48 | return if ( $jmax <= 0 ); | 
| 1254 |  |  |  |  |  |  |  | 
| 1255 | 9 | 50 |  |  |  | 37 | if (%valign_control_hash) { | 
| 1256 | 0 |  |  |  |  | 0 | my $align_ok = $valign_control_hash{'{'}; | 
| 1257 | 0 | 0 |  |  |  | 0 | $align_ok = $valign_control_default unless defined($align_ok); | 
| 1258 | 0 | 0 |  |  |  | 0 | return if ( !$align_ok ); | 
| 1259 |  |  |  |  |  |  | } | 
| 1260 |  |  |  |  |  |  |  | 
| 1261 |  |  |  |  |  |  | # check for balanced else block following if/elsif/unless | 
| 1262 | 9 |  |  |  |  | 32 | my $rfields_old = $old_line->{'rfields'}; | 
| 1263 |  |  |  |  |  |  |  | 
| 1264 |  |  |  |  |  |  | # TBD: add handling for 'case' | 
| 1265 | 9 | 100 |  |  |  | 94 | return if ( $rfields_old->[0] !~ /^(?:if|elsif|unless)\s*$/ ); | 
| 1266 |  |  |  |  |  |  |  | 
| 1267 |  |  |  |  |  |  | # look for the opening brace after the else, and extract the depth | 
| 1268 | 7 |  |  |  |  | 27 | my $tok_brace = $rtokens->[0]; | 
| 1269 | 7 |  |  |  |  | 12 | my $depth_brace; | 
| 1270 | 7 | 50 |  |  |  | 43 | if ( $tok_brace =~ /^\{(\d+)/ ) { $depth_brace = $1; } | 
|  | 7 |  |  |  |  | 38 |  | 
| 1271 |  |  |  |  |  |  |  | 
| 1272 |  |  |  |  |  |  | # probably:  "else # side_comment" | 
| 1273 | 0 |  |  |  |  | 0 | else { return } | 
| 1274 |  |  |  |  |  |  |  | 
| 1275 | 7 |  |  |  |  | 19 | my $rpatterns_old       = $old_line->{'rpatterns'}; | 
| 1276 | 7 |  |  |  |  | 20 | my $rtokens_old         = $old_line->{'rtokens'}; | 
| 1277 | 7 |  |  |  |  | 28 | my $maximum_field_index = $old_line->{'jmax'}; | 
| 1278 |  |  |  |  |  |  |  | 
| 1279 |  |  |  |  |  |  | # be sure the previous if/elsif is followed by an opening paren | 
| 1280 | 7 |  |  |  |  | 17 | my $jparen    = 0; | 
| 1281 | 7 |  |  |  |  | 19 | my $tok_paren = '(' . $depth_brace; | 
| 1282 | 7 |  |  |  |  | 18 | my $tok_test  = $rtokens_old->[$jparen]; | 
| 1283 | 7 | 50 |  |  |  | 26 | return if ( $tok_test ne $tok_paren );    # shouldn't happen | 
| 1284 |  |  |  |  |  |  |  | 
| 1285 |  |  |  |  |  |  | # Now find the opening block brace | 
| 1286 | 7 |  |  |  |  | 15 | my ($jbrace); | 
| 1287 | 7 |  |  |  |  | 28 | foreach my $j ( 1 .. $maximum_field_index - 1 ) { | 
| 1288 | 8 |  |  |  |  | 38 | my $tok = $rtokens_old->[$j]; | 
| 1289 | 8 | 100 |  |  |  | 43 | if ( $tok eq $tok_brace ) { | 
| 1290 | 7 |  |  |  |  | 17 | $jbrace = $j; | 
| 1291 | 7 |  |  |  |  | 16 | last; | 
| 1292 |  |  |  |  |  |  | } | 
| 1293 |  |  |  |  |  |  | } | 
| 1294 | 7 | 50 |  |  |  | 30 | return if ( !defined($jbrace) );          # shouldn't happen | 
| 1295 |  |  |  |  |  |  |  | 
| 1296 |  |  |  |  |  |  | # Now splice the tokens and patterns of the previous line | 
| 1297 |  |  |  |  |  |  | # into the else line to insure a match.  Add empty fields | 
| 1298 |  |  |  |  |  |  | # as necessary. | 
| 1299 | 7 |  |  |  |  | 29 | my $jadd = $jbrace - $jparen; | 
| 1300 | 7 |  |  |  |  | 17 | splice( @{$rtokens},   0, 0, @{$rtokens_old}[ $jparen .. $jbrace - 1 ] ); | 
|  | 7 |  |  |  |  | 32 |  | 
|  | 7 |  |  |  |  | 28 |  | 
| 1301 | 7 |  |  |  |  | 16 | splice( @{$rpatterns}, 1, 0, @{$rpatterns_old}[ $jparen + 1 .. $jbrace ] ); | 
|  | 7 |  |  |  |  | 25 |  | 
|  | 7 |  |  |  |  | 24 |  | 
| 1302 | 7 |  |  |  |  | 17 | splice( @{$rfields},        1, 0, (EMPTY_STRING) x $jadd ); | 
|  | 7 |  |  |  |  | 25 |  | 
| 1303 | 7 |  |  |  |  | 16 | splice( @{$rfield_lengths}, 1, 0, (0) x $jadd ); | 
|  | 7 |  |  |  |  | 21 |  | 
| 1304 |  |  |  |  |  |  |  | 
| 1305 |  |  |  |  |  |  | # force a flush after this line if it does not follow a case | 
| 1306 | 7 | 50 |  |  |  | 29 | if   ( $rfields_old->[0] =~ /^case\s*$/ ) { return } | 
|  | 0 |  |  |  |  | 0 |  | 
| 1307 | 7 |  |  |  |  | 26 | else                                      { return $jbrace } | 
| 1308 |  |  |  |  |  |  | } ## end sub fix_terminal_else | 
| 1309 |  |  |  |  |  |  |  | 
| 1310 |  |  |  |  |  |  | my %is_closing_block_type; | 
| 1311 |  |  |  |  |  |  |  | 
| 1312 |  |  |  |  |  |  | BEGIN { | 
| 1313 | 39 |  |  | 39 |  | 244 | my @q = qw< } ] >; | 
| 1314 | 39 |  |  |  |  | 1219 | @is_closing_block_type{@q} = (1) x scalar(@q); | 
| 1315 |  |  |  |  |  |  | } | 
| 1316 |  |  |  |  |  |  |  | 
| 1317 |  |  |  |  |  |  | # This is a flag for testing alignment by sub sweep_left_to_right only. | 
| 1318 |  |  |  |  |  |  | # This test can help find problems with the alignment logic. | 
| 1319 |  |  |  |  |  |  | # This flag should normally be zero. | 
| 1320 | 39 |  |  | 39 |  | 403 | use constant TEST_SWEEP_ONLY => 0; | 
|  | 39 |  |  |  |  | 127 |  | 
|  | 39 |  |  |  |  | 2879 |  | 
| 1321 |  |  |  |  |  |  |  | 
| 1322 | 39 |  |  | 39 |  | 340 | use constant EXPLAIN_CHECK_MATCH => 0; | 
|  | 39 |  |  |  |  | 107 |  | 
|  | 39 |  |  |  |  | 3506 |  | 
| 1323 |  |  |  |  |  |  |  | 
| 1324 |  |  |  |  |  |  | sub check_match { | 
| 1325 |  |  |  |  |  |  |  | 
| 1326 |  |  |  |  |  |  | # See if the current line matches the current vertical alignment group. | 
| 1327 |  |  |  |  |  |  |  | 
| 1328 | 1139 |  |  | 1139 | 0 | 3716 | my ( $self, $new_line, $base_line, $prev_line, $group_line_count ) = @_; | 
| 1329 |  |  |  |  |  |  |  | 
| 1330 |  |  |  |  |  |  | # Given: | 
| 1331 |  |  |  |  |  |  | #  $new_line  = the line being considered for group inclusion | 
| 1332 |  |  |  |  |  |  | #  $base_line = the first line of the current group | 
| 1333 |  |  |  |  |  |  | #  $prev_line = the line just before $new_line | 
| 1334 |  |  |  |  |  |  | #  $group_line_count = number of lines in the current group | 
| 1335 |  |  |  |  |  |  |  | 
| 1336 |  |  |  |  |  |  | # returns a flag and a value as follows: | 
| 1337 |  |  |  |  |  |  | #    return (0, $imax_align)   if the line does not match | 
| 1338 |  |  |  |  |  |  | #    return (1, $imax_align)   if the line matches but does not fit | 
| 1339 |  |  |  |  |  |  | #    return (2, $imax_align)   if the line matches and fits | 
| 1340 |  |  |  |  |  |  |  | 
| 1341 | 39 |  |  | 39 |  | 359 | use constant NO_MATCH      => 0; | 
|  | 39 |  |  |  |  | 114 |  | 
|  | 39 |  |  |  |  | 2480 |  | 
| 1342 | 39 |  |  | 39 |  | 312 | use constant MATCH_NO_FIT  => 1; | 
|  | 39 |  |  |  |  | 84 |  | 
|  | 39 |  |  |  |  | 2255 |  | 
| 1343 | 39 |  |  | 39 |  | 245 | use constant MATCH_AND_FIT => 2; | 
|  | 39 |  |  |  |  | 102 |  | 
|  | 39 |  |  |  |  | 69567 |  | 
| 1344 |  |  |  |  |  |  |  | 
| 1345 | 1139 |  |  |  |  | 2223 | my $return_value; | 
| 1346 |  |  |  |  |  |  |  | 
| 1347 |  |  |  |  |  |  | # Returns '$imax_align' which is the index of the maximum matching token. | 
| 1348 |  |  |  |  |  |  | # It will be used in the subsequent left-to-right sweep to align as many | 
| 1349 |  |  |  |  |  |  | # tokens as possible for lines which partially match. | 
| 1350 | 1139 |  |  |  |  | 1921 | my $imax_align = -1; | 
| 1351 |  |  |  |  |  |  |  | 
| 1352 |  |  |  |  |  |  | # variable $GoToMsg explains reason for no match, for debugging | 
| 1353 | 1139 |  |  |  |  | 2125 | my $GoToMsg = EMPTY_STRING; | 
| 1354 |  |  |  |  |  |  |  | 
| 1355 | 1139 |  |  |  |  | 2043 | my $jmax                = $new_line->{'jmax'}; | 
| 1356 | 1139 |  |  |  |  | 2024 | my $maximum_field_index = $base_line->{'jmax'}; | 
| 1357 |  |  |  |  |  |  |  | 
| 1358 | 1139 |  |  |  |  | 1985 | my $jlimit = $jmax - 2; | 
| 1359 | 1139 | 100 |  |  |  | 2892 | if ( $jmax > $maximum_field_index ) { | 
| 1360 | 82 |  |  |  |  | 251 | $jlimit = $maximum_field_index - 2; | 
| 1361 |  |  |  |  |  |  | } | 
| 1362 |  |  |  |  |  |  |  | 
| 1363 | 1139 | 100 |  |  |  | 2429 | if ( $new_line->{'is_hanging_side_comment'} ) { | 
| 1364 |  |  |  |  |  |  |  | 
| 1365 |  |  |  |  |  |  | # HSC's can join the group if they fit | 
| 1366 |  |  |  |  |  |  | } | 
| 1367 |  |  |  |  |  |  |  | 
| 1368 |  |  |  |  |  |  | # Everything else | 
| 1369 |  |  |  |  |  |  | else { | 
| 1370 |  |  |  |  |  |  |  | 
| 1371 |  |  |  |  |  |  | # A group with hanging side comments ends with the first non hanging | 
| 1372 |  |  |  |  |  |  | # side comment. | 
| 1373 | 1101 | 50 |  |  |  | 2452 | if ( $base_line->{'is_hanging_side_comment'} ) { | 
| 1374 | 0 |  |  |  |  | 0 | $GoToMsg      = "end of hanging side comments"; | 
| 1375 | 0 |  |  |  |  | 0 | $return_value = NO_MATCH; | 
| 1376 |  |  |  |  |  |  | } | 
| 1377 |  |  |  |  |  |  | else { | 
| 1378 |  |  |  |  |  |  |  | 
| 1379 |  |  |  |  |  |  | # The number of tokens that this line shares with the previous | 
| 1380 |  |  |  |  |  |  | # line has been stored with the previous line.  This value was | 
| 1381 |  |  |  |  |  |  | # calculated and stored by sub 'match_line_pair'. | 
| 1382 | 1101 |  |  |  |  | 1847 | $imax_align = $prev_line->{'imax_pair'}; | 
| 1383 |  |  |  |  |  |  |  | 
| 1384 |  |  |  |  |  |  | # Only the following ci sequences are accepted (issue c225): | 
| 1385 |  |  |  |  |  |  | #   0 0 0 ...  OK | 
| 1386 |  |  |  |  |  |  | #   0 1 1 ...  OK but marginal* | 
| 1387 |  |  |  |  |  |  | #   1 1 1 ...  OK | 
| 1388 |  |  |  |  |  |  | # This check is rarely activated, but for example we want | 
| 1389 |  |  |  |  |  |  | # to avoid something like this 'tail wag dog' situation: | 
| 1390 |  |  |  |  |  |  | #  $tag        =~ s/\b([a-z]+)/\L\u$1/gio; | 
| 1391 |  |  |  |  |  |  | #  $tag        =~ s/\b([b-df-hj-np-tv-z]+)\b/\U$1/gio | 
| 1392 |  |  |  |  |  |  | #      if $tag =~ /-/; | 
| 1393 |  |  |  |  |  |  | # *Note: we could set a flag for the 0 1 marginal case and | 
| 1394 |  |  |  |  |  |  | # use it to prevent alignment of selected token types. | 
| 1395 | 1101 |  |  |  |  | 1816 | my $ci_prev = $prev_line->{'ci_level'}; | 
| 1396 | 1101 |  |  |  |  | 1825 | my $ci_new  = $new_line->{'ci_level'}; | 
| 1397 | 1101 | 50 | 100 |  |  | 4808 | if (   $ci_prev != $ci_new | 
|  |  | 100 | 33 |  |  |  |  | 
|  |  |  | 66 |  |  |  |  | 
| 1398 |  |  |  |  |  |  | && $imax_align >= 0 | 
| 1399 |  |  |  |  |  |  | && ( $ci_new == 0 || $group_line_count > 1 ) ) | 
| 1400 |  |  |  |  |  |  | { | 
| 1401 | 0 |  |  |  |  | 0 | $imax_align = -1; | 
| 1402 | 0 |  |  |  |  | 0 | $GoToMsg = | 
| 1403 |  |  |  |  |  |  | "Rejected ci: ci_prev=$ci_prev ci_new=$ci_new num=$group_line_count\n"; | 
| 1404 | 0 |  |  |  |  | 0 | $return_value = NO_MATCH; | 
| 1405 |  |  |  |  |  |  | } | 
| 1406 |  |  |  |  |  |  | elsif ( $imax_align != $jlimit ) { | 
| 1407 | 27 |  |  |  |  | 203 | $GoToMsg = "Not all tokens match: $imax_align != $jlimit\n"; | 
| 1408 | 27 |  |  |  |  | 71 | $return_value = NO_MATCH; | 
| 1409 |  |  |  |  |  |  | } | 
| 1410 |  |  |  |  |  |  | else { | 
| 1411 |  |  |  |  |  |  | ##ok: continue | 
| 1412 |  |  |  |  |  |  | } | 
| 1413 |  |  |  |  |  |  | } | 
| 1414 |  |  |  |  |  |  | } | 
| 1415 |  |  |  |  |  |  |  | 
| 1416 | 1139 | 100 |  |  |  | 2628 | if ( !defined($return_value) ) { | 
| 1417 |  |  |  |  |  |  |  | 
| 1418 |  |  |  |  |  |  | # The tokens match, but the lines must have identical number of | 
| 1419 |  |  |  |  |  |  | # tokens to join the group. | 
| 1420 | 1112 | 100 | 100 |  |  | 4005 | if ( $maximum_field_index != $jmax ) { | 
|  |  | 100 |  |  |  |  |  | 
| 1421 | 118 |  |  |  |  | 320 | $GoToMsg      = "token count differs"; | 
| 1422 | 118 |  |  |  |  | 245 | $return_value = NO_MATCH; | 
| 1423 |  |  |  |  |  |  | } | 
| 1424 |  |  |  |  |  |  |  | 
| 1425 |  |  |  |  |  |  | # The tokens match. Now See if there is space for this line in the | 
| 1426 |  |  |  |  |  |  | # current group. | 
| 1427 |  |  |  |  |  |  | elsif ( $self->check_fit( $new_line, $base_line ) && !TEST_SWEEP_ONLY ) | 
| 1428 |  |  |  |  |  |  | { | 
| 1429 |  |  |  |  |  |  |  | 
| 1430 | 981 |  |  |  |  | 2982 | $GoToMsg = "match and fit, imax_align=$imax_align, jmax=$jmax\n"; | 
| 1431 | 981 |  |  |  |  | 1607 | $return_value = MATCH_AND_FIT; | 
| 1432 | 981 |  |  |  |  | 1799 | $imax_align   = $jlimit; | 
| 1433 |  |  |  |  |  |  | } | 
| 1434 |  |  |  |  |  |  | else { | 
| 1435 | 13 |  |  |  |  | 61 | $GoToMsg = "match but no fit, imax_align=$imax_align, jmax=$jmax\n"; | 
| 1436 | 13 |  |  |  |  | 25 | $return_value = MATCH_NO_FIT; | 
| 1437 | 13 |  |  |  |  | 25 | $imax_align   = $jlimit; | 
| 1438 |  |  |  |  |  |  | } | 
| 1439 |  |  |  |  |  |  | } | 
| 1440 |  |  |  |  |  |  |  | 
| 1441 |  |  |  |  |  |  | EXPLAIN_CHECK_MATCH | 
| 1442 | 1139 |  |  |  |  | 1688 | && print | 
| 1443 |  |  |  |  |  |  | "returning $return_value because $GoToMsg, max match index =i $imax_align, jmax=$jmax\n"; | 
| 1444 |  |  |  |  |  |  |  | 
| 1445 | 1139 |  |  |  |  | 3022 | return ( $return_value, $imax_align ); | 
| 1446 |  |  |  |  |  |  | } ## end sub check_match | 
| 1447 |  |  |  |  |  |  |  | 
| 1448 |  |  |  |  |  |  | sub check_fit { | 
| 1449 |  |  |  |  |  |  |  | 
| 1450 | 994 |  |  | 994 | 0 | 2195 | my ( $self, $new_line, $old_line ) = @_; | 
| 1451 |  |  |  |  |  |  |  | 
| 1452 |  |  |  |  |  |  | # The new line has alignments identical to the current group. Now we have | 
| 1453 |  |  |  |  |  |  | # to fit the new line into the group without causing a field to exceed the | 
| 1454 |  |  |  |  |  |  | # line length limit. | 
| 1455 |  |  |  |  |  |  | #   return true if successful | 
| 1456 |  |  |  |  |  |  | #   return false if not successful | 
| 1457 |  |  |  |  |  |  |  | 
| 1458 | 994 |  |  |  |  | 1837 | my $jmax                = $new_line->{'jmax'}; | 
| 1459 | 994 |  |  |  |  | 1738 | my $leading_space_count = $new_line->{'leading_space_count'}; | 
| 1460 | 994 |  |  |  |  | 1665 | my $rfield_lengths      = $new_line->{'rfield_lengths'}; | 
| 1461 | 994 |  |  |  |  | 3498 | my $padding_available   = $old_line->get_available_space_on_right(); | 
| 1462 | 994 |  |  |  |  | 1856 | my $jmax_old            = $old_line->{'jmax'}; | 
| 1463 |  |  |  |  |  |  |  | 
| 1464 |  |  |  |  |  |  | # Safety check ... only lines with equal array sizes should arrive here | 
| 1465 |  |  |  |  |  |  | # from sub check_match.  So if this error occurs, look at recent changes in | 
| 1466 |  |  |  |  |  |  | # sub check_match.  It is only supposed to check the fit of lines with | 
| 1467 |  |  |  |  |  |  | # identical numbers of alignment tokens. | 
| 1468 | 994 | 50 |  |  |  | 3462 | if ( $jmax_old ne $jmax ) { | 
| 1469 |  |  |  |  |  |  |  | 
| 1470 | 0 |  |  |  |  | 0 | warning(<<EOM); | 
| 1471 |  |  |  |  |  |  | Program bug detected in Perl::Tidy::VerticalAligner sub check_fit | 
| 1472 |  |  |  |  |  |  | unexpected difference in array lengths: $jmax != $jmax_old | 
| 1473 |  |  |  |  |  |  | EOM | 
| 1474 | 0 |  |  |  |  | 0 | return; | 
| 1475 |  |  |  |  |  |  | } | 
| 1476 |  |  |  |  |  |  |  | 
| 1477 |  |  |  |  |  |  | # Save current columns in case this line does not fit. | 
| 1478 | 994 |  |  |  |  | 1696 | my @alignments = @{ $old_line->{'ralignments'} }; | 
|  | 994 |  |  |  |  | 2440 |  | 
| 1479 | 994 |  |  |  |  | 2100 | foreach my $alignment (@alignments) { | 
| 1480 | 3451 |  |  |  |  | 7267 | $alignment->save_column(); | 
| 1481 |  |  |  |  |  |  | } | 
| 1482 |  |  |  |  |  |  |  | 
| 1483 |  |  |  |  |  |  | # Loop over all alignments ... | 
| 1484 | 994 |  |  |  |  | 2990 | for my $j ( 0 .. $jmax ) { | 
| 1485 |  |  |  |  |  |  |  | 
| 1486 | 3435 |  |  |  |  | 8277 | my $pad = $rfield_lengths->[$j] - $old_line->current_field_width($j); | 
| 1487 |  |  |  |  |  |  |  | 
| 1488 | 3435 | 100 |  |  |  | 7180 | if ( $j == 0 ) { | 
| 1489 | 994 |  |  |  |  | 1579 | $pad += $leading_space_count; | 
| 1490 |  |  |  |  |  |  | } | 
| 1491 |  |  |  |  |  |  |  | 
| 1492 |  |  |  |  |  |  | # Keep going if this field does not need any space. | 
| 1493 | 3435 | 100 |  |  |  | 6600 | next if ( $pad < 0 ); | 
| 1494 |  |  |  |  |  |  |  | 
| 1495 |  |  |  |  |  |  | # Revert to the starting state if does not fit | 
| 1496 | 2376 | 100 |  |  |  | 4868 | if ( $pad > $padding_available ) { | 
| 1497 |  |  |  |  |  |  |  | 
| 1498 |  |  |  |  |  |  | #---------------------------------------------- | 
| 1499 |  |  |  |  |  |  | # Line does not fit -- revert to starting state | 
| 1500 |  |  |  |  |  |  | #---------------------------------------------- | 
| 1501 | 13 |  |  |  |  | 28 | foreach my $alignment (@alignments) { | 
| 1502 | 39 |  |  |  |  | 100 | $alignment->restore_column(); | 
| 1503 |  |  |  |  |  |  | } | 
| 1504 | 13 |  |  |  |  | 67 | return; | 
| 1505 |  |  |  |  |  |  | } | 
| 1506 |  |  |  |  |  |  |  | 
| 1507 |  |  |  |  |  |  | # make room for this field | 
| 1508 | 2363 |  |  |  |  | 6505 | $old_line->increase_field_width( $j, $pad ); | 
| 1509 | 2363 |  |  |  |  | 3984 | $padding_available -= $pad; | 
| 1510 |  |  |  |  |  |  | } | 
| 1511 |  |  |  |  |  |  |  | 
| 1512 |  |  |  |  |  |  | #------------------------------------- | 
| 1513 |  |  |  |  |  |  | # The line fits, the match is accepted | 
| 1514 |  |  |  |  |  |  | #------------------------------------- | 
| 1515 | 981 |  |  |  |  | 5075 | return 1; | 
| 1516 |  |  |  |  |  |  |  | 
| 1517 |  |  |  |  |  |  | } ## end sub check_fit | 
| 1518 |  |  |  |  |  |  |  | 
| 1519 |  |  |  |  |  |  | sub install_new_alignments { | 
| 1520 |  |  |  |  |  |  |  | 
| 1521 | 2084 |  |  | 2084 | 0 | 4179 | my ($new_line) = @_; | 
| 1522 |  |  |  |  |  |  |  | 
| 1523 | 2084 |  |  |  |  | 4117 | my $jmax           = $new_line->{'jmax'}; | 
| 1524 | 2084 |  |  |  |  | 3755 | my $rfield_lengths = $new_line->{'rfield_lengths'}; | 
| 1525 | 2084 |  |  |  |  | 3717 | my $col            = $new_line->{'leading_space_count'}; | 
| 1526 |  |  |  |  |  |  |  | 
| 1527 | 2084 |  |  |  |  | 3590 | my @alignments; | 
| 1528 | 2084 |  |  |  |  | 5040 | for my $j ( 0 .. $jmax ) { | 
| 1529 | 6963 |  |  |  |  | 10535 | $col += $rfield_lengths->[$j]; | 
| 1530 |  |  |  |  |  |  |  | 
| 1531 |  |  |  |  |  |  | # create initial alignments for the new group | 
| 1532 | 6963 |  |  |  |  | 22656 | my $alignment = | 
| 1533 |  |  |  |  |  |  | Perl::Tidy::VerticalAligner::Alignment->new( { column => $col } ); | 
| 1534 | 6963 |  |  |  |  | 14624 | push @alignments, $alignment; | 
| 1535 |  |  |  |  |  |  | } | 
| 1536 | 2084 |  |  |  |  | 5894 | $new_line->{'ralignments'} = \@alignments; | 
| 1537 | 2084 |  |  |  |  | 4600 | return; | 
| 1538 |  |  |  |  |  |  | } ## end sub install_new_alignments | 
| 1539 |  |  |  |  |  |  |  | 
| 1540 |  |  |  |  |  |  | sub copy_old_alignments { | 
| 1541 | 981 |  |  | 981 | 0 | 1923 | my ( $new_line, $old_line ) = @_; | 
| 1542 | 981 |  |  |  |  | 1525 | my @new_alignments = @{ $old_line->{'ralignments'} }; | 
|  | 981 |  |  |  |  | 2615 |  | 
| 1543 | 981 |  |  |  |  | 2341 | $new_line->{'ralignments'} = \@new_alignments; | 
| 1544 | 981 |  |  |  |  | 2285 | return; | 
| 1545 |  |  |  |  |  |  | } ## end sub copy_old_alignments | 
| 1546 |  |  |  |  |  |  |  | 
| 1547 |  |  |  |  |  |  | sub dump_array { | 
| 1548 |  |  |  |  |  |  |  | 
| 1549 |  |  |  |  |  |  | # debug routine to dump array contents | 
| 1550 | 0 |  |  | 0 | 0 | 0 | local $LIST_SEPARATOR = ')('; | 
| 1551 | 0 |  |  |  |  | 0 | print {*STDOUT} "(@_)\n"; | 
|  | 0 |  |  |  |  | 0 |  | 
| 1552 | 0 |  |  |  |  | 0 | return; | 
| 1553 |  |  |  |  |  |  | } ## end sub dump_array | 
| 1554 |  |  |  |  |  |  |  | 
| 1555 |  |  |  |  |  |  | sub level_change { | 
| 1556 |  |  |  |  |  |  |  | 
| 1557 |  |  |  |  |  |  | # compute decrease in level when we remove $diff spaces from the | 
| 1558 |  |  |  |  |  |  | # leading spaces | 
| 1559 | 10 |  |  | 10 | 0 | 23 | my ( $self, $leading_space_count, $diff, $level ) = @_; | 
| 1560 |  |  |  |  |  |  |  | 
| 1561 | 10 |  |  |  |  | 20 | my $rOpts_indent_columns = $self->[_rOpts_indent_columns_]; | 
| 1562 | 10 | 50 |  |  |  | 24 | if ($rOpts_indent_columns) { | 
| 1563 | 10 |  |  |  |  | 26 | my $olev = | 
| 1564 |  |  |  |  |  |  | int( ( $leading_space_count + $diff ) / $rOpts_indent_columns ); | 
| 1565 | 10 |  |  |  |  | 18 | my $nlev = int( $leading_space_count / $rOpts_indent_columns ); | 
| 1566 | 10 |  |  |  |  | 18 | $level -= ( $olev - $nlev ); | 
| 1567 | 10 | 50 |  |  |  | 25 | if ( $level < 0 ) { $level = 0 } | 
|  | 0 |  |  |  |  | 0 |  | 
| 1568 |  |  |  |  |  |  | } | 
| 1569 | 10 |  |  |  |  | 23 | return $level; | 
| 1570 |  |  |  |  |  |  | } ## end sub level_change | 
| 1571 |  |  |  |  |  |  |  | 
| 1572 |  |  |  |  |  |  | ############################################### | 
| 1573 |  |  |  |  |  |  | # CODE SECTION 4: Code to process comment lines | 
| 1574 |  |  |  |  |  |  | ############################################### | 
| 1575 |  |  |  |  |  |  |  | 
| 1576 |  |  |  |  |  |  | sub _flush_comment_lines { | 
| 1577 |  |  |  |  |  |  |  | 
| 1578 |  |  |  |  |  |  | # Output a group consisting of COMMENT lines | 
| 1579 |  |  |  |  |  |  |  | 
| 1580 | 531 |  |  | 531 |  | 1256 | my ($self) = @_; | 
| 1581 | 531 |  |  |  |  | 1166 | my $rgroup_lines = $self->[_rgroup_lines_]; | 
| 1582 | 531 | 50 |  |  |  | 860 | return if ( !@{$rgroup_lines} ); | 
|  | 531 |  |  |  |  | 1558 |  | 
| 1583 | 531 |  |  |  |  | 1082 | my $group_level               = $self->[_group_level_]; | 
| 1584 | 531 |  |  |  |  | 1047 | my $group_maximum_line_length = $self->[_group_maximum_line_length_]; | 
| 1585 | 531 |  |  |  |  | 1070 | my $leading_space_count       = $self->[_comment_leading_space_count_]; | 
| 1586 |  |  |  |  |  |  |  | 
| 1587 |  |  |  |  |  |  | # look for excessively long lines | 
| 1588 | 531 |  |  |  |  | 2302 | my $max_excess = 0; | 
| 1589 | 531 |  |  |  |  | 1014 | foreach my $item ( @{$rgroup_lines} ) { | 
|  | 531 |  |  |  |  | 1465 |  | 
| 1590 | 608 |  |  |  |  | 1009 | my ( $str, $str_len ) = @{$item}; | 
|  | 608 |  |  |  |  | 1544 |  | 
| 1591 | 608 |  |  |  |  | 1391 | my $excess = | 
| 1592 |  |  |  |  |  |  | $str_len + $leading_space_count - $group_maximum_line_length; | 
| 1593 | 608 | 100 |  |  |  | 2049 | if ( $excess > $max_excess ) { | 
| 1594 | 38 |  |  |  |  | 117 | $max_excess = $excess; | 
| 1595 |  |  |  |  |  |  | } | 
| 1596 |  |  |  |  |  |  | } | 
| 1597 |  |  |  |  |  |  |  | 
| 1598 |  |  |  |  |  |  | # zero leading space count if any lines are too long | 
| 1599 | 531 | 100 |  |  |  | 1843 | if ( $max_excess > 0 ) { | 
| 1600 | 36 |  |  |  |  | 102 | $leading_space_count -= $max_excess; | 
| 1601 | 36 | 50 |  |  |  | 132 | if ( $leading_space_count < 0 ) { $leading_space_count = 0 } | 
|  | 36 |  |  |  |  | 109 |  | 
| 1602 | 36 |  |  |  |  | 89 | my $file_writer_object = $self->[_file_writer_object_]; | 
| 1603 | 36 |  |  |  |  | 186 | my $last_outdented_line_at = | 
| 1604 |  |  |  |  |  |  | $file_writer_object->get_output_line_number(); | 
| 1605 | 36 |  |  |  |  | 82 | my $nlines = @{$rgroup_lines}; | 
|  | 36 |  |  |  |  | 67 |  | 
| 1606 | 36 |  |  |  |  | 96 | $self->[_last_outdented_line_at_] = | 
| 1607 |  |  |  |  |  |  | $last_outdented_line_at + $nlines - 1; | 
| 1608 | 36 |  |  |  |  | 69 | my $outdented_line_count = $self->[_outdented_line_count_]; | 
| 1609 | 36 | 100 |  |  |  | 142 | if ( !$outdented_line_count ) { | 
| 1610 | 18 |  |  |  |  | 43 | $self->[_first_outdented_line_at_] = $last_outdented_line_at; | 
| 1611 |  |  |  |  |  |  | } | 
| 1612 | 36 |  |  |  |  | 64 | $outdented_line_count += $nlines; | 
| 1613 | 36 |  |  |  |  | 76 | $self->[_outdented_line_count_] = $outdented_line_count; | 
| 1614 |  |  |  |  |  |  | } | 
| 1615 |  |  |  |  |  |  |  | 
| 1616 |  |  |  |  |  |  | # write the lines | 
| 1617 | 531 |  |  |  |  | 1142 | my $outdent_long_lines = 0; | 
| 1618 |  |  |  |  |  |  |  | 
| 1619 | 531 |  |  |  |  | 1029 | foreach my $item ( @{$rgroup_lines} ) { | 
|  | 531 |  |  |  |  | 1200 |  | 
| 1620 | 608 |  |  |  |  | 1058 | my ( $str, $str_len, $Kend ) = @{$item}; | 
|  | 608 |  |  |  |  | 1551 |  | 
| 1621 | 608 |  |  |  |  | 6969 | $self->valign_output_step_B( | 
| 1622 |  |  |  |  |  |  | { | 
| 1623 |  |  |  |  |  |  | leading_space_count       => $leading_space_count, | 
| 1624 |  |  |  |  |  |  | line                      => $str, | 
| 1625 |  |  |  |  |  |  | line_length               => $str_len, | 
| 1626 |  |  |  |  |  |  | side_comment_length       => 0, | 
| 1627 |  |  |  |  |  |  | outdent_long_lines        => $outdent_long_lines, | 
| 1628 |  |  |  |  |  |  | rvertical_tightness_flags => undef, | 
| 1629 |  |  |  |  |  |  | level                     => $group_level, | 
| 1630 |  |  |  |  |  |  | level_end                 => $group_level, | 
| 1631 |  |  |  |  |  |  | Kend                      => $Kend, | 
| 1632 |  |  |  |  |  |  | maximum_line_length       => $group_maximum_line_length, | 
| 1633 |  |  |  |  |  |  | } | 
| 1634 |  |  |  |  |  |  | ); | 
| 1635 |  |  |  |  |  |  | } | 
| 1636 |  |  |  |  |  |  |  | 
| 1637 | 531 |  |  |  |  | 2624 | $self->initialize_for_new_group(); | 
| 1638 | 531 |  |  |  |  | 1076 | return; | 
| 1639 |  |  |  |  |  |  | } ## end sub _flush_comment_lines | 
| 1640 |  |  |  |  |  |  |  | 
| 1641 |  |  |  |  |  |  | ###################################################### | 
| 1642 |  |  |  |  |  |  | # CODE SECTION 5: Code to process groups of code lines | 
| 1643 |  |  |  |  |  |  | ###################################################### | 
| 1644 |  |  |  |  |  |  |  | 
| 1645 |  |  |  |  |  |  | sub _flush_group_lines { | 
| 1646 |  |  |  |  |  |  |  | 
| 1647 |  |  |  |  |  |  | # This is the vertical aligner internal flush, which leaves the cache | 
| 1648 |  |  |  |  |  |  | # intact | 
| 1649 | 5582 |  |  | 5582 |  | 11317 | my ( $self, $level_jump ) = @_; | 
| 1650 |  |  |  |  |  |  |  | 
| 1651 |  |  |  |  |  |  | # $level_jump = $next_level-$group_level, if known | 
| 1652 |  |  |  |  |  |  | #             = undef if not known | 
| 1653 |  |  |  |  |  |  | # Note: only the sign of the jump is needed | 
| 1654 |  |  |  |  |  |  |  | 
| 1655 | 5582 |  |  |  |  | 10005 | my $rgroup_lines = $self->[_rgroup_lines_]; | 
| 1656 | 5582 | 100 |  |  |  | 7924 | return if ( !@{$rgroup_lines} ); | 
|  | 5582 |  |  |  |  | 14562 |  | 
| 1657 | 2236 |  |  |  |  | 4883 | my $group_type  = $self->[_group_type_]; | 
| 1658 | 2236 |  |  |  |  | 3949 | my $group_level = $self->[_group_level_]; | 
| 1659 |  |  |  |  |  |  |  | 
| 1660 |  |  |  |  |  |  | # Debug | 
| 1661 | 2236 |  |  |  |  | 3311 | 0 && do { | 
| 1662 |  |  |  |  |  |  | my ( $a, $b, $c ) = caller(); | 
| 1663 |  |  |  |  |  |  | my $nlines = @{$rgroup_lines}; | 
| 1664 |  |  |  |  |  |  | print {*STDOUT} | 
| 1665 |  |  |  |  |  |  | "APPEND0: _flush_group_lines called from $a $b $c lines=$nlines, type=$group_type \n"; | 
| 1666 |  |  |  |  |  |  | }; | 
| 1667 |  |  |  |  |  |  |  | 
| 1668 |  |  |  |  |  |  | #------------------------------------------- | 
| 1669 |  |  |  |  |  |  | # Section 1: Handle a group of COMMENT lines | 
| 1670 |  |  |  |  |  |  | #------------------------------------------- | 
| 1671 | 2236 | 100 |  |  |  | 5971 | if ( $group_type eq 'COMMENT' ) { | 
| 1672 | 531 |  |  |  |  | 2330 | $self->_flush_comment_lines(); | 
| 1673 | 531 |  |  |  |  | 1599 | return; | 
| 1674 |  |  |  |  |  |  | } | 
| 1675 |  |  |  |  |  |  |  | 
| 1676 |  |  |  |  |  |  | #------------------------------------------------------------------------ | 
| 1677 |  |  |  |  |  |  | # Section 2: Handle line(s) of CODE.  Most of the actual work of vertical | 
| 1678 |  |  |  |  |  |  | # aligning happens here in the following steps: | 
| 1679 |  |  |  |  |  |  | #------------------------------------------------------------------------ | 
| 1680 |  |  |  |  |  |  |  | 
| 1681 |  |  |  |  |  |  | # STEP 1: Remove most unmatched tokens. They block good alignments. | 
| 1682 | 1705 |  |  |  |  | 6253 | my ( $max_lev_diff, $saw_side_comment ) = | 
| 1683 |  |  |  |  |  |  | delete_unmatched_tokens( $rgroup_lines, $group_level ); | 
| 1684 |  |  |  |  |  |  |  | 
| 1685 |  |  |  |  |  |  | # STEP 2: Sweep top to bottom, forming subgroups of lines with exactly | 
| 1686 |  |  |  |  |  |  | # matching common alignments.  The indexes of these subgroups are in the | 
| 1687 |  |  |  |  |  |  | # return variable. | 
| 1688 | 1705 |  |  |  |  | 7150 | my $rgroups = $self->sweep_top_down( $rgroup_lines, $group_level ); | 
| 1689 |  |  |  |  |  |  |  | 
| 1690 |  |  |  |  |  |  | # STEP 3: Sweep left to right through the lines, looking for leading | 
| 1691 |  |  |  |  |  |  | # alignment tokens shared by groups. | 
| 1692 |  |  |  |  |  |  | sweep_left_to_right( $rgroup_lines, $rgroups, $group_level ) | 
| 1693 | 1705 | 100 |  |  |  | 2821 | if ( @{$rgroups} > 1 ); | 
|  | 1705 |  |  |  |  | 5703 |  | 
| 1694 |  |  |  |  |  |  |  | 
| 1695 |  |  |  |  |  |  | # STEP 4: Move side comments to a common column if possible. | 
| 1696 | 1705 | 100 |  |  |  | 4394 | if ($saw_side_comment) { | 
| 1697 | 199 |  |  |  |  | 975 | $self->align_side_comments( $rgroup_lines, $rgroups ); | 
| 1698 |  |  |  |  |  |  | } | 
| 1699 |  |  |  |  |  |  |  | 
| 1700 |  |  |  |  |  |  | # STEP 5: For the -lp option, increase the indentation of lists | 
| 1701 |  |  |  |  |  |  | # to the desired amount, but do not exceed the line length limit. | 
| 1702 |  |  |  |  |  |  |  | 
| 1703 |  |  |  |  |  |  | # We are allowed to shift a group of lines to the right if: | 
| 1704 |  |  |  |  |  |  | #  (1) its level is greater than the level of the previous group, and | 
| 1705 |  |  |  |  |  |  | #  (2) its level is greater than the level of the next line to be written. | 
| 1706 |  |  |  |  |  |  |  | 
| 1707 | 1705 |  |  |  |  | 2820 | my $extra_indent_ok; | 
| 1708 | 1705 | 100 |  |  |  | 4816 | if ( $group_level > $self->[_last_level_written_] ) { | 
| 1709 |  |  |  |  |  |  |  | 
| 1710 |  |  |  |  |  |  | # Use the level jump to next line to come, if given | 
| 1711 | 853 | 100 |  |  |  | 2507 | if ( defined($level_jump) ) { | 
| 1712 | 571 |  |  |  |  | 1528 | $extra_indent_ok = $level_jump < 0; | 
| 1713 |  |  |  |  |  |  | } | 
| 1714 |  |  |  |  |  |  |  | 
| 1715 |  |  |  |  |  |  | # Otherwise, assume the next line has the level of the end of last line. | 
| 1716 |  |  |  |  |  |  | # This fixes case c008. | 
| 1717 |  |  |  |  |  |  | else { | 
| 1718 | 282 |  |  |  |  | 790 | my $level_end = $rgroup_lines->[-1]->{'level_end'}; | 
| 1719 | 282 |  |  |  |  | 770 | $extra_indent_ok = $group_level > $level_end; | 
| 1720 |  |  |  |  |  |  | } | 
| 1721 |  |  |  |  |  |  | } | 
| 1722 |  |  |  |  |  |  |  | 
| 1723 | 1705 | 100 |  |  |  | 5178 | my $extra_leading_spaces = | 
| 1724 |  |  |  |  |  |  | $extra_indent_ok | 
| 1725 |  |  |  |  |  |  | ? get_extra_leading_spaces( $rgroup_lines, $rgroups ) | 
| 1726 |  |  |  |  |  |  | : 0; | 
| 1727 |  |  |  |  |  |  |  | 
| 1728 |  |  |  |  |  |  | # STEP 6: Output the lines. | 
| 1729 |  |  |  |  |  |  | # All lines in this group have the same leading spacing and maximum line | 
| 1730 |  |  |  |  |  |  | # length | 
| 1731 | 1705 |  |  |  |  | 3345 | my $group_leader_length       = $rgroup_lines->[0]->{'leading_space_count'}; | 
| 1732 | 1705 |  |  |  |  | 3505 | my $group_maximum_line_length = $rgroup_lines->[0]->{'maximum_line_length'}; | 
| 1733 |  |  |  |  |  |  |  | 
| 1734 | 1705 |  |  |  |  | 2732 | foreach my $line ( @{$rgroup_lines} ) { | 
|  | 1705 |  |  |  |  | 3580 |  | 
| 1735 | 3065 |  |  |  |  | 18621 | $self->valign_output_step_A( | 
| 1736 |  |  |  |  |  |  | { | 
| 1737 |  |  |  |  |  |  | line                 => $line, | 
| 1738 |  |  |  |  |  |  | min_ci_gap           => 0, | 
| 1739 |  |  |  |  |  |  | do_not_align         => 0, | 
| 1740 |  |  |  |  |  |  | group_leader_length  => $group_leader_length, | 
| 1741 |  |  |  |  |  |  | extra_leading_spaces => $extra_leading_spaces, | 
| 1742 |  |  |  |  |  |  | level                => $group_level, | 
| 1743 |  |  |  |  |  |  | maximum_line_length  => $group_maximum_line_length, | 
| 1744 |  |  |  |  |  |  | } | 
| 1745 |  |  |  |  |  |  | ); | 
| 1746 |  |  |  |  |  |  | } | 
| 1747 |  |  |  |  |  |  |  | 
| 1748 |  |  |  |  |  |  | # Let the formatter know that this object has been processed and any | 
| 1749 |  |  |  |  |  |  | # recoverable spaces have been handled.  This is needed for setting the | 
| 1750 |  |  |  |  |  |  | # closing paren location in -lp mode. | 
| 1751 | 1705 |  |  |  |  | 4493 | my $object = $rgroup_lines->[0]->{'indentation'}; | 
| 1752 | 1705 | 100 |  |  |  | 4683 | if ( ref($object) ) { $object->set_recoverable_spaces(0) } | 
|  | 92 |  |  |  |  | 397 |  | 
| 1753 |  |  |  |  |  |  |  | 
| 1754 | 1705 |  |  |  |  | 6333 | $self->initialize_for_new_group(); | 
| 1755 | 1705 |  |  |  |  | 3771 | return; | 
| 1756 |  |  |  |  |  |  | } ## end sub _flush_group_lines | 
| 1757 |  |  |  |  |  |  |  | 
| 1758 |  |  |  |  |  |  | {    ## closure for sub sweep_top_down | 
| 1759 |  |  |  |  |  |  |  | 
| 1760 |  |  |  |  |  |  | my $rall_lines;         # all of the lines | 
| 1761 |  |  |  |  |  |  | my $grp_level;          # level of all lines | 
| 1762 |  |  |  |  |  |  | my $rgroups;            # describes the partition of lines we will make here | 
| 1763 |  |  |  |  |  |  | my $group_line_count;   # number of lines in current partition | 
| 1764 |  |  |  |  |  |  |  | 
| 1765 | 39 |  |  | 39 |  | 81117 | BEGIN { $rgroups = [] } | 
| 1766 |  |  |  |  |  |  |  | 
| 1767 |  |  |  |  |  |  | sub initialize_for_new_rgroup { | 
| 1768 | 3789 |  |  | 3789 | 0 | 5856 | $group_line_count = 0; | 
| 1769 | 3789 |  |  |  |  | 5678 | return; | 
| 1770 |  |  |  |  |  |  | } | 
| 1771 |  |  |  |  |  |  |  | 
| 1772 |  |  |  |  |  |  | sub add_to_rgroup { | 
| 1773 |  |  |  |  |  |  |  | 
| 1774 | 3065 |  |  | 3065 | 0 | 5800 | my ($jend) = @_; | 
| 1775 | 3065 |  |  |  |  | 5511 | my $rline = $rall_lines->[$jend]; | 
| 1776 |  |  |  |  |  |  |  | 
| 1777 | 3065 |  |  |  |  | 4476 | my $jbeg = $jend; | 
| 1778 | 3065 | 100 |  |  |  | 6631 | if ( $group_line_count == 0 ) { | 
| 1779 | 2084 |  |  |  |  | 5705 | install_new_alignments($rline); | 
| 1780 |  |  |  |  |  |  | } | 
| 1781 |  |  |  |  |  |  | else { | 
| 1782 | 981 |  |  |  |  | 1558 | my $rvals = pop @{$rgroups}; | 
|  | 981 |  |  |  |  | 1863 |  | 
| 1783 | 981 |  |  |  |  | 1899 | $jbeg = $rvals->[0]; | 
| 1784 | 981 |  |  |  |  | 2608 | copy_old_alignments( $rline, $rall_lines->[$jbeg] ); | 
| 1785 |  |  |  |  |  |  | } | 
| 1786 | 3065 |  |  |  |  | 5114 | push @{$rgroups}, [ $jbeg, $jend, undef ]; | 
|  | 3065 |  |  |  |  | 7351 |  | 
| 1787 | 3065 |  |  |  |  | 5091 | $group_line_count++; | 
| 1788 | 3065 |  |  |  |  | 4774 | return; | 
| 1789 |  |  |  |  |  |  | } ## end sub add_to_rgroup | 
| 1790 |  |  |  |  |  |  |  | 
| 1791 |  |  |  |  |  |  | sub get_rgroup_jrange { | 
| 1792 |  |  |  |  |  |  |  | 
| 1793 | 1288 | 50 |  | 1288 | 0 | 1923 | return if ( !@{$rgroups} ); | 
|  | 1288 |  |  |  |  | 3208 |  | 
| 1794 | 1288 | 50 |  |  |  | 3099 | return if ( $group_line_count <= 0 ); | 
| 1795 | 1288 |  |  |  |  | 1976 | my ( $jbeg, $jend ) = @{ $rgroups->[-1] }; | 
|  | 1288 |  |  |  |  | 2898 |  | 
| 1796 | 1288 |  |  |  |  | 2806 | return ( $jbeg, $jend ); | 
| 1797 |  |  |  |  |  |  | } ## end sub get_rgroup_jrange | 
| 1798 |  |  |  |  |  |  |  | 
| 1799 |  |  |  |  |  |  | sub end_rgroup { | 
| 1800 |  |  |  |  |  |  |  | 
| 1801 | 2103 |  |  | 2103 | 0 | 4243 | my ($imax_align) = @_; | 
| 1802 | 2103 | 50 |  |  |  | 3229 | return if ( !@{$rgroups} ); | 
|  | 2103 |  |  |  |  | 5257 |  | 
| 1803 | 2103 | 100 |  |  |  | 5120 | return if ( $group_line_count <= 0 ); | 
| 1804 |  |  |  |  |  |  |  | 
| 1805 | 2084 |  |  |  |  | 3267 | my ( $jbeg, $jend ) = @{ pop @{$rgroups} }; | 
|  | 2084 |  |  |  |  | 2917 |  | 
|  | 2084 |  |  |  |  | 4869 |  | 
| 1806 | 2084 |  |  |  |  | 3992 | push @{$rgroups}, [ $jbeg, $jend, $imax_align ]; | 
|  | 2084 |  |  |  |  | 5246 |  | 
| 1807 |  |  |  |  |  |  |  | 
| 1808 |  |  |  |  |  |  | # Undo some alignments of poor two-line combinations. | 
| 1809 |  |  |  |  |  |  | # We had to wait until now to know the line count. | 
| 1810 | 2084 | 100 |  |  |  | 5871 | if ( $jend - $jbeg == 1 ) { | 
| 1811 | 256 |  |  |  |  | 867 | my $line_0 = $rall_lines->[$jbeg]; | 
| 1812 | 256 |  |  |  |  | 627 | my $line_1 = $rall_lines->[$jend]; | 
| 1813 |  |  |  |  |  |  |  | 
| 1814 | 256 |  |  |  |  | 625 | my $imax_pair = $line_1->{'imax_pair'}; | 
| 1815 | 256 | 50 |  |  |  | 868 | if ( $imax_pair > $imax_align ) { $imax_align = $imax_pair } | 
|  | 0 |  |  |  |  | 0 |  | 
| 1816 |  |  |  |  |  |  |  | 
| 1817 |  |  |  |  |  |  | ## flag for possible future use: | 
| 1818 |  |  |  |  |  |  | ## my $is_isolated_pair = $imax_pair < 0 | 
| 1819 |  |  |  |  |  |  | ##  && ( $jbeg == 0 | 
| 1820 |  |  |  |  |  |  | ##    || $rall_lines->[ $jbeg - 1 ]->{'imax_pair'} < 0 ); | 
| 1821 |  |  |  |  |  |  |  | 
| 1822 |  |  |  |  |  |  | my $imax_prev = | 
| 1823 | 256 | 100 |  |  |  | 987 | $jbeg > 0 ? $rall_lines->[ $jbeg - 1 ]->{'imax_pair'} : -1; | 
| 1824 |  |  |  |  |  |  |  | 
| 1825 | 256 |  |  |  |  | 1205 | my ( $is_marginal, $imax_align_fix ) = | 
| 1826 |  |  |  |  |  |  | is_marginal_match( $line_0, $line_1, $grp_level, $imax_align, | 
| 1827 |  |  |  |  |  |  | $imax_prev ); | 
| 1828 | 256 | 100 |  |  |  | 889 | if ($is_marginal) { | 
| 1829 | 14 |  |  |  |  | 71 | combine_fields( $line_0, $line_1, $imax_align_fix ); | 
| 1830 |  |  |  |  |  |  | } | 
| 1831 |  |  |  |  |  |  | } | 
| 1832 |  |  |  |  |  |  |  | 
| 1833 | 2084 |  |  |  |  | 5246 | initialize_for_new_rgroup(); | 
| 1834 | 2084 |  |  |  |  | 3656 | return; | 
| 1835 |  |  |  |  |  |  | } ## end sub end_rgroup | 
| 1836 |  |  |  |  |  |  |  | 
| 1837 |  |  |  |  |  |  | sub block_penultimate_match { | 
| 1838 |  |  |  |  |  |  |  | 
| 1839 |  |  |  |  |  |  | # emergency reset to prevent sweep_left_to_right from trying to match a | 
| 1840 |  |  |  |  |  |  | # failed terminal else match | 
| 1841 | 1 | 50 |  | 1 | 0 | 2 | return if ( @{$rgroups} <= 1 ); | 
|  | 1 |  |  |  |  | 4 |  | 
| 1842 | 1 |  |  |  |  | 3 | $rgroups->[-2]->[2] = -1; | 
| 1843 | 1 |  |  |  |  | 2 | return; | 
| 1844 |  |  |  |  |  |  | } ## end sub block_penultimate_match | 
| 1845 |  |  |  |  |  |  |  | 
| 1846 |  |  |  |  |  |  | sub sweep_top_down { | 
| 1847 | 1705 |  |  | 1705 | 0 | 3903 | my ( $self, $rlines, $group_level ) = @_; | 
| 1848 |  |  |  |  |  |  |  | 
| 1849 |  |  |  |  |  |  | # Partition the set of lines into final alignment subgroups | 
| 1850 |  |  |  |  |  |  | # and store the alignments with the lines. | 
| 1851 |  |  |  |  |  |  |  | 
| 1852 |  |  |  |  |  |  | # The alignment subgroups we are making here are groups of consecutive | 
| 1853 |  |  |  |  |  |  | # lines which have (1) identical alignment tokens and (2) do not | 
| 1854 |  |  |  |  |  |  | # exceed the allowable maximum line length.  A later sweep from | 
| 1855 |  |  |  |  |  |  | # left-to-right ('sweep_lr') will handle additional alignments. | 
| 1856 |  |  |  |  |  |  |  | 
| 1857 |  |  |  |  |  |  | # transfer args to closure variables | 
| 1858 | 1705 |  |  |  |  | 20552 | $rall_lines = $rlines; | 
| 1859 | 1705 |  |  |  |  | 4087 | $grp_level  = $group_level; | 
| 1860 | 1705 |  |  |  |  | 5424 | $rgroups    = []; | 
| 1861 | 1705 |  |  |  |  | 5748 | initialize_for_new_rgroup(); | 
| 1862 | 1705 | 50 |  |  |  | 2557 | return unless @{$rlines};    # shouldn't happen | 
|  | 1705 |  |  |  |  | 4904 |  | 
| 1863 |  |  |  |  |  |  |  | 
| 1864 |  |  |  |  |  |  | # Unset the _end_group flag for the last line if it it set because it | 
| 1865 |  |  |  |  |  |  | # is not needed and can causes problems for -lp formatting | 
| 1866 | 1705 |  |  |  |  | 4101 | $rall_lines->[-1]->{'end_group'} = 0; | 
| 1867 |  |  |  |  |  |  |  | 
| 1868 |  |  |  |  |  |  | # Loop over all lines ... | 
| 1869 | 1705 |  |  |  |  | 3176 | my $jline = -1; | 
| 1870 | 1705 |  |  |  |  | 2940 | foreach my $new_line ( @{$rall_lines} ) { | 
|  | 1705 |  |  |  |  | 4040 |  | 
| 1871 | 3065 |  |  |  |  | 4553 | $jline++; | 
| 1872 |  |  |  |  |  |  |  | 
| 1873 |  |  |  |  |  |  | # Start a new subgroup if necessary | 
| 1874 | 3065 | 100 |  |  |  | 6939 | if ( !$group_line_count ) { | 
| 1875 | 1777 |  |  |  |  | 5413 | add_to_rgroup($jline); | 
| 1876 | 1777 | 100 |  |  |  | 4991 | if ( $new_line->{'end_group'} ) { | 
| 1877 | 22 |  |  |  |  | 101 | end_rgroup(-1); | 
| 1878 |  |  |  |  |  |  | } | 
| 1879 | 1777 |  |  |  |  | 3812 | next; | 
| 1880 |  |  |  |  |  |  | } | 
| 1881 |  |  |  |  |  |  |  | 
| 1882 | 1288 |  |  |  |  | 2819 | my $j_terminal_match = $new_line->{'j_terminal_match'}; | 
| 1883 | 1288 |  |  |  |  | 3441 | my ( $jbeg, $jend ) = get_rgroup_jrange(); | 
| 1884 | 1288 | 50 |  |  |  | 3317 | if ( !defined($jbeg) ) { | 
| 1885 |  |  |  |  |  |  |  | 
| 1886 |  |  |  |  |  |  | # safety check, shouldn't happen | 
| 1887 | 0 |  |  |  |  | 0 | warning(<<EOM); | 
| 1888 |  |  |  |  |  |  | Program bug detected in Perl::Tidy::VerticalAligner sub sweep_top_down | 
| 1889 |  |  |  |  |  |  | undefined index for group line count $group_line_count | 
| 1890 |  |  |  |  |  |  | EOM | 
| 1891 | 0 |  |  |  |  | 0 | $jbeg = $jline; | 
| 1892 |  |  |  |  |  |  | } | 
| 1893 | 1288 |  |  |  |  | 2295 | my $base_line = $rall_lines->[$jbeg]; | 
| 1894 |  |  |  |  |  |  |  | 
| 1895 |  |  |  |  |  |  | # Initialize a global flag saying if the last line of the group | 
| 1896 |  |  |  |  |  |  | # should match end of group and also terminate the group.  There | 
| 1897 |  |  |  |  |  |  | # should be no returns between here and where the flag is handled | 
| 1898 |  |  |  |  |  |  | # at the bottom. | 
| 1899 | 1288 |  |  |  |  | 1986 | my $col_matching_terminal = 0; | 
| 1900 | 1288 | 100 |  |  |  | 2911 | if ( defined($j_terminal_match) ) { | 
| 1901 |  |  |  |  |  |  |  | 
| 1902 |  |  |  |  |  |  | # remember the column of the terminal ? or { to match with | 
| 1903 | 19 |  |  |  |  | 127 | $col_matching_terminal = | 
| 1904 |  |  |  |  |  |  | $base_line->get_column($j_terminal_match); | 
| 1905 |  |  |  |  |  |  |  | 
| 1906 |  |  |  |  |  |  | # Ignore an undefined value as a defensive step; shouldn't | 
| 1907 |  |  |  |  |  |  | # normally happen. | 
| 1908 | 19 | 50 |  |  |  | 103 | $col_matching_terminal = 0 | 
| 1909 |  |  |  |  |  |  | unless defined($col_matching_terminal); | 
| 1910 |  |  |  |  |  |  | } | 
| 1911 |  |  |  |  |  |  |  | 
| 1912 |  |  |  |  |  |  | # ------------------------------------------------------------- | 
| 1913 |  |  |  |  |  |  | # Allow hanging side comment to join current group, if any.  The | 
| 1914 |  |  |  |  |  |  | # only advantage is to keep the other tokens in the same group. For | 
| 1915 |  |  |  |  |  |  | # example, this would make the '=' align here: | 
| 1916 |  |  |  |  |  |  | #  $ax         = 1;           # side comment | 
| 1917 |  |  |  |  |  |  | #                             # hanging side comment | 
| 1918 |  |  |  |  |  |  | #  $boondoggle = 5;           # side comment | 
| 1919 |  |  |  |  |  |  | #  $beetle     = 5;           # side comment | 
| 1920 |  |  |  |  |  |  |  | 
| 1921 |  |  |  |  |  |  | # here is another example.. | 
| 1922 |  |  |  |  |  |  |  | 
| 1923 |  |  |  |  |  |  | #  _rtoc_name_count   => {},                   # hash to track .. | 
| 1924 |  |  |  |  |  |  | #  _rpackage_stack    => [],                   # stack to check .. | 
| 1925 |  |  |  |  |  |  | #                                              # name changes | 
| 1926 |  |  |  |  |  |  | #  _rlast_level       => \$last_level,         # brace indentation | 
| 1927 |  |  |  |  |  |  | # | 
| 1928 |  |  |  |  |  |  | # | 
| 1929 |  |  |  |  |  |  | # If this were not desired, the next step could be skipped. | 
| 1930 |  |  |  |  |  |  | # ------------------------------------------------------------- | 
| 1931 | 1288 | 100 |  |  |  | 4121 | if ( $new_line->{'is_hanging_side_comment'} ) { | 
|  |  | 100 |  |  |  |  |  | 
| 1932 | 38 |  |  |  |  | 159 | join_hanging_comment( $new_line, $base_line ); | 
| 1933 |  |  |  |  |  |  | } | 
| 1934 |  |  |  |  |  |  |  | 
| 1935 |  |  |  |  |  |  | # If this line has no matching tokens, then flush out the lines | 
| 1936 |  |  |  |  |  |  | # BEFORE this line unless both it and the previous line have side | 
| 1937 |  |  |  |  |  |  | # comments.  This prevents this line from pushing side comments out | 
| 1938 |  |  |  |  |  |  | # to the right. | 
| 1939 |  |  |  |  |  |  | elsif ( $new_line->{'jmax'} == 1 ) { | 
| 1940 |  |  |  |  |  |  |  | 
| 1941 |  |  |  |  |  |  | # There are no matching tokens, so now check side comments. | 
| 1942 |  |  |  |  |  |  | # Programming note: accessing arrays with index -1 is | 
| 1943 |  |  |  |  |  |  | # risky in Perl, but we have verified there is at least one | 
| 1944 |  |  |  |  |  |  | # line in the group and that there is at least one field. | 
| 1945 |  |  |  |  |  |  | my $prev_comment = | 
| 1946 | 194 |  |  |  |  | 713 | $rall_lines->[ $jline - 1 ]->{'rfields'}->[-1]; | 
| 1947 | 194 |  |  |  |  | 464 | my $side_comment = $new_line->{'rfields'}->[-1]; | 
| 1948 | 194 | 100 | 100 |  |  | 998 | end_rgroup(-1) if ( !$side_comment || !$prev_comment ); | 
| 1949 |  |  |  |  |  |  | } | 
| 1950 |  |  |  |  |  |  | else { | 
| 1951 |  |  |  |  |  |  | ##ok: continue | 
| 1952 |  |  |  |  |  |  | } | 
| 1953 |  |  |  |  |  |  |  | 
| 1954 |  |  |  |  |  |  | # See if the new line matches and fits the current group, | 
| 1955 |  |  |  |  |  |  | # if it still exists. Flush the current group if not. | 
| 1956 | 1288 |  |  |  |  | 2115 | my $match_code; | 
| 1957 | 1288 | 100 |  |  |  | 2879 | if ($group_line_count) { | 
| 1958 | 1139 |  |  |  |  | 3984 | ( $match_code, my $imax_align ) = | 
| 1959 |  |  |  |  |  |  | $self->check_match( $new_line, $base_line, | 
| 1960 |  |  |  |  |  |  | $rall_lines->[ $jline - 1 ], | 
| 1961 |  |  |  |  |  |  | $group_line_count ); | 
| 1962 | 1139 | 100 |  |  |  | 3009 | if ( $match_code != 2 ) { end_rgroup($imax_align) } | 
|  | 158 |  |  |  |  | 547 |  | 
| 1963 |  |  |  |  |  |  | } | 
| 1964 |  |  |  |  |  |  |  | 
| 1965 |  |  |  |  |  |  | # Store the new line | 
| 1966 | 1288 |  |  |  |  | 3478 | add_to_rgroup($jline); | 
| 1967 |  |  |  |  |  |  |  | 
| 1968 | 1288 | 100 |  |  |  | 5646 | if ( defined($j_terminal_match) ) { | 
|  |  | 100 |  |  |  |  |  | 
| 1969 |  |  |  |  |  |  |  | 
| 1970 |  |  |  |  |  |  | # Decide if we should fix a terminal match. We can either: | 
| 1971 |  |  |  |  |  |  | # 1. fix it and prevent the sweep_lr from changing it, or | 
| 1972 |  |  |  |  |  |  | # 2. leave it alone and let sweep_lr try to fix it. | 
| 1973 |  |  |  |  |  |  |  | 
| 1974 |  |  |  |  |  |  | # The current logic is to fix it if: | 
| 1975 |  |  |  |  |  |  | # -it has not joined to previous lines, | 
| 1976 |  |  |  |  |  |  | # -and either the previous subgroup has just 1 line, or | 
| 1977 |  |  |  |  |  |  | # -this line matched but did not fit (so sweep won't work) | 
| 1978 | 19 |  |  |  |  | 86 | my $fixit; | 
| 1979 | 19 | 100 |  |  |  | 95 | if ( $group_line_count == 1 ) { | 
| 1980 | 3 |  | 66 |  |  | 21 | $fixit ||= $match_code; | 
| 1981 | 3 | 100 |  |  |  | 12 | if ( !$fixit ) { | 
| 1982 | 2 | 50 |  |  |  | 4 | if ( @{$rgroups} > 1 ) { | 
|  | 2 |  |  |  |  | 9 |  | 
| 1983 | 2 |  |  |  |  | 4 | my ( $jbegx, $jendx ) = @{ $rgroups->[-2] }; | 
|  | 2 |  |  |  |  | 6 |  | 
| 1984 | 2 |  |  |  |  | 7 | my $nlines = $jendx - $jbegx + 1; | 
| 1985 | 2 |  | 66 |  |  | 13 | $fixit ||= $nlines <= 1; | 
| 1986 |  |  |  |  |  |  | } | 
| 1987 |  |  |  |  |  |  | } | 
| 1988 |  |  |  |  |  |  | } | 
| 1989 |  |  |  |  |  |  |  | 
| 1990 | 19 | 100 |  |  |  | 81 | if ($fixit) { | 
| 1991 | 2 |  |  |  |  | 6 | $base_line = $new_line; | 
| 1992 | 2 |  |  |  |  | 8 | my $col_now = $base_line->get_column($j_terminal_match); | 
| 1993 |  |  |  |  |  |  |  | 
| 1994 |  |  |  |  |  |  | # Ignore an undefined value as a defensive step; shouldn't | 
| 1995 |  |  |  |  |  |  | # normally happen. | 
| 1996 | 2 | 50 |  |  |  | 7 | $col_now = 0 unless defined($col_now); | 
| 1997 |  |  |  |  |  |  |  | 
| 1998 | 2 |  |  |  |  | 6 | my $pad = $col_matching_terminal - $col_now; | 
| 1999 | 2 |  |  |  |  | 11 | my $padding_available = | 
| 2000 |  |  |  |  |  |  | $base_line->get_available_space_on_right(); | 
| 2001 | 2 | 100 | 33 |  |  | 18 | if ( $col_now && $pad > 0 && $pad <= $padding_available ) { | 
|  |  |  | 66 |  |  |  |  | 
| 2002 | 1 |  |  |  |  | 6 | $base_line->increase_field_width( $j_terminal_match, | 
| 2003 |  |  |  |  |  |  | $pad ); | 
| 2004 |  |  |  |  |  |  | } | 
| 2005 |  |  |  |  |  |  |  | 
| 2006 |  |  |  |  |  |  | # do not let sweep_left_to_right change an isolated 'else' | 
| 2007 | 2 | 100 |  |  |  | 15 | if ( !$new_line->{'is_terminal_ternary'} ) { | 
| 2008 | 1 |  |  |  |  | 5 | block_penultimate_match(); | 
| 2009 |  |  |  |  |  |  | } | 
| 2010 |  |  |  |  |  |  | } | 
| 2011 | 19 |  |  |  |  | 91 | end_rgroup(-1); | 
| 2012 |  |  |  |  |  |  | } | 
| 2013 |  |  |  |  |  |  |  | 
| 2014 |  |  |  |  |  |  | # end the group if we know we cannot match next line. | 
| 2015 |  |  |  |  |  |  | elsif ( $new_line->{'end_group'} ) { | 
| 2016 | 50 |  |  |  |  | 254 | end_rgroup(-1); | 
| 2017 |  |  |  |  |  |  | } | 
| 2018 |  |  |  |  |  |  |  | 
| 2019 |  |  |  |  |  |  | else { | 
| 2020 |  |  |  |  |  |  | ##ok: continue | 
| 2021 |  |  |  |  |  |  | } | 
| 2022 |  |  |  |  |  |  | } ## end loop over lines | 
| 2023 |  |  |  |  |  |  |  | 
| 2024 | 1705 |  |  |  |  | 6418 | end_rgroup(-1); | 
| 2025 | 1705 |  |  |  |  | 3779 | return ($rgroups); | 
| 2026 |  |  |  |  |  |  | } ## end sub sweep_top_down | 
| 2027 |  |  |  |  |  |  | } | 
| 2028 |  |  |  |  |  |  |  | 
| 2029 |  |  |  |  |  |  | sub two_line_pad { | 
| 2030 |  |  |  |  |  |  |  | 
| 2031 | 18 |  |  | 18 | 0 | 89 | my ( $line_m, $line, $imax_min ) = @_; | 
| 2032 |  |  |  |  |  |  |  | 
| 2033 |  |  |  |  |  |  | # Given: | 
| 2034 |  |  |  |  |  |  | #  two isolated (list) lines | 
| 2035 |  |  |  |  |  |  | #  imax_min = number of common alignment tokens | 
| 2036 |  |  |  |  |  |  | # Return: | 
| 2037 |  |  |  |  |  |  | #  $pad_max = maximum suggested pad distance | 
| 2038 |  |  |  |  |  |  | #           = 0 if alignment not recommended | 
| 2039 |  |  |  |  |  |  | # Note that this is only for two lines which do not have alignment tokens | 
| 2040 |  |  |  |  |  |  | # in common with any other lines.  It is intended for lists, but it might | 
| 2041 |  |  |  |  |  |  | # also be used for two non-list lines with a common leading '='. | 
| 2042 |  |  |  |  |  |  |  | 
| 2043 |  |  |  |  |  |  | # Allow alignment if the difference in the two unpadded line lengths | 
| 2044 |  |  |  |  |  |  | # is not more than either line length.  The idea is to avoid | 
| 2045 |  |  |  |  |  |  | # aligning lines with very different field lengths, like these two: | 
| 2046 |  |  |  |  |  |  |  | 
| 2047 |  |  |  |  |  |  | #   [ | 
| 2048 |  |  |  |  |  |  | #       'VARCHAR', DBI::SQL_VARCHAR, undef, "'", "'", undef, 0, 1, | 
| 2049 |  |  |  |  |  |  | #       1, 0, 0, 0, undef, 0, 0 | 
| 2050 |  |  |  |  |  |  | #   ]; | 
| 2051 | 18 |  |  |  |  | 59 | my $rfield_lengths   = $line->{'rfield_lengths'}; | 
| 2052 | 18 |  |  |  |  | 47 | my $rfield_lengths_m = $line_m->{'rfield_lengths'}; | 
| 2053 |  |  |  |  |  |  |  | 
| 2054 |  |  |  |  |  |  | # Safety check - shouldn't happen | 
| 2055 |  |  |  |  |  |  | return 0 | 
| 2056 | 18 |  |  |  |  | 121 | if ( $imax_min >= @{$rfield_lengths} | 
| 2057 | 18 | 50 | 33 |  |  | 46 | || $imax_min >= @{$rfield_lengths_m} ); | 
|  | 18 |  |  |  |  | 77 |  | 
| 2058 |  |  |  |  |  |  |  | 
| 2059 | 18 |  |  |  |  | 56 | my $lensum_m = 0; | 
| 2060 | 18 |  |  |  |  | 47 | my $lensum   = 0; | 
| 2061 | 18 |  |  |  |  | 67 | foreach my $i ( 0 .. $imax_min ) { | 
| 2062 | 49 |  |  |  |  | 90 | $lensum_m += $rfield_lengths_m->[$i]; | 
| 2063 | 49 |  |  |  |  | 104 | $lensum   += $rfield_lengths->[$i]; | 
| 2064 |  |  |  |  |  |  | } | 
| 2065 |  |  |  |  |  |  |  | 
| 2066 | 18 | 100 |  |  |  | 140 | my ( $lenmin, $lenmax ) = | 
| 2067 |  |  |  |  |  |  | $lensum >= $lensum_m ? ( $lensum_m, $lensum ) : ( $lensum, $lensum_m ); | 
| 2068 |  |  |  |  |  |  |  | 
| 2069 | 18 |  |  |  |  | 39 | my $patterns_match; | 
| 2070 | 18 | 50 | 66 |  |  | 129 | if ( $line_m->{'list_type'} && $line->{'list_type'} ) { | 
| 2071 | 16 |  |  |  |  | 92 | $patterns_match = 1; | 
| 2072 | 16 |  |  |  |  | 52 | my $rpatterns_m = $line_m->{'rpatterns'}; | 
| 2073 | 16 |  |  |  |  | 42 | my $rpatterns   = $line->{'rpatterns'}; | 
| 2074 | 16 |  |  |  |  | 51 | foreach my $i ( 0 .. $imax_min ) { | 
| 2075 | 46 |  |  |  |  | 94 | my $pat   = $rpatterns->[$i]; | 
| 2076 | 46 |  |  |  |  | 82 | my $pat_m = $rpatterns_m->[$i]; | 
| 2077 | 46 | 100 |  |  |  | 149 | if ( $pat ne $pat_m ) { $patterns_match = 0; last } | 
|  | 2 |  |  |  |  | 5 |  | 
|  | 2 |  |  |  |  | 6 |  | 
| 2078 |  |  |  |  |  |  | } | 
| 2079 |  |  |  |  |  |  | } | 
| 2080 |  |  |  |  |  |  |  | 
| 2081 | 18 |  |  |  |  | 49 | my $pad_max = $lenmax; | 
| 2082 | 18 | 50 | 66 |  |  | 99 | if ( !$patterns_match && $lenmax > 2 * $lenmin ) { $pad_max = 0 } | 
|  | 0 |  |  |  |  | 0 |  | 
| 2083 |  |  |  |  |  |  |  | 
| 2084 | 18 |  |  |  |  | 59 | return $pad_max; | 
| 2085 |  |  |  |  |  |  | } ## end sub two_line_pad | 
| 2086 |  |  |  |  |  |  |  | 
| 2087 |  |  |  |  |  |  | sub sweep_left_to_right { | 
| 2088 |  |  |  |  |  |  |  | 
| 2089 | 255 |  |  | 255 | 0 | 911 | my ( $rlines, $rgroups, $group_level ) = @_; | 
| 2090 |  |  |  |  |  |  |  | 
| 2091 |  |  |  |  |  |  | # So far we have divided the lines into groups having an equal number of | 
| 2092 |  |  |  |  |  |  | # identical alignments.  Here we are going to look for common leading | 
| 2093 |  |  |  |  |  |  | # alignments between the different groups and align them when possible. | 
| 2094 |  |  |  |  |  |  | # For example, the three lines below are in three groups because each line | 
| 2095 |  |  |  |  |  |  | # has a different number of commas.  In this routine we will sweep from | 
| 2096 |  |  |  |  |  |  | # left to right, aligning the leading commas as we go, but stopping if we | 
| 2097 |  |  |  |  |  |  | # hit the line length limit. | 
| 2098 |  |  |  |  |  |  |  | 
| 2099 |  |  |  |  |  |  | #  my ( $num, $numi, $numj,  $xyza, $ka,   $xyzb, $kb, $aff, $error ); | 
| 2100 |  |  |  |  |  |  | #  my ( $i,   $j,    $error, $aff,  $asum, $avec ); | 
| 2101 |  |  |  |  |  |  | #  my ( $km,  $area, $varea ); | 
| 2102 |  |  |  |  |  |  |  | 
| 2103 |  |  |  |  |  |  | # nothing to do if just one group | 
| 2104 | 255 |  |  |  |  | 479 | my $ng_max = @{$rgroups} - 1; | 
|  | 255 |  |  |  |  | 587 |  | 
| 2105 | 255 | 50 |  |  |  | 754 | return if ( $ng_max <= 0 ); | 
| 2106 |  |  |  |  |  |  |  | 
| 2107 |  |  |  |  |  |  | #--------------------------------------------------------------------- | 
| 2108 |  |  |  |  |  |  | # Step 1: Loop over groups to find all common leading alignment tokens | 
| 2109 |  |  |  |  |  |  | #--------------------------------------------------------------------- | 
| 2110 |  |  |  |  |  |  |  | 
| 2111 | 255 |  |  |  |  | 3669 | my $line; | 
| 2112 |  |  |  |  |  |  | my $rtokens; | 
| 2113 | 255 |  |  |  |  | 0 | my $imax;     # index of maximum non-side-comment alignment token | 
| 2114 | 255 |  |  |  |  | 0 | my $istop;    # an optional stopping index | 
| 2115 | 255 |  |  |  |  | 0 | my $jbeg;     # starting line index | 
| 2116 | 255 |  |  |  |  | 0 | my $jend;     # ending line index | 
| 2117 |  |  |  |  |  |  |  | 
| 2118 | 255 |  |  |  |  | 0 | my $line_m; | 
| 2119 | 255 |  |  |  |  | 0 | my $rtokens_m; | 
| 2120 | 255 |  |  |  |  | 0 | my $imax_m; | 
| 2121 | 255 |  |  |  |  | 0 | my $istop_m; | 
| 2122 | 255 |  |  |  |  | 0 | my $jbeg_m; | 
| 2123 | 255 |  |  |  |  | 0 | my $jend_m; | 
| 2124 |  |  |  |  |  |  |  | 
| 2125 | 255 |  |  |  |  | 0 | my $istop_mm; | 
| 2126 |  |  |  |  |  |  |  | 
| 2127 |  |  |  |  |  |  | # Look at neighboring pairs of groups and form a simple list | 
| 2128 |  |  |  |  |  |  | # of all common leading alignment tokens. Foreach such match we | 
| 2129 |  |  |  |  |  |  | # store [$i, $ng], where | 
| 2130 |  |  |  |  |  |  | #  $i = index of the token in the line (0,1,...) | 
| 2131 |  |  |  |  |  |  | #  $ng is the second of the two groups with this common token | 
| 2132 | 255 |  |  |  |  | 0 | my @icommon; | 
| 2133 |  |  |  |  |  |  |  | 
| 2134 |  |  |  |  |  |  | # Hash to hold the maximum alignment change for any group | 
| 2135 | 255 |  |  |  |  | 0 | my %max_move; | 
| 2136 |  |  |  |  |  |  |  | 
| 2137 |  |  |  |  |  |  | # a small number of columns | 
| 2138 | 255 |  |  |  |  | 498 | my $short_pad = 4; | 
| 2139 |  |  |  |  |  |  |  | 
| 2140 | 255 |  |  |  |  | 536 | my $ng = -1; | 
| 2141 | 255 |  |  |  |  | 507 | foreach my $item ( @{$rgroups} ) { | 
|  | 255 |  |  |  |  | 655 |  | 
| 2142 | 634 |  |  |  |  | 928 | $ng++; | 
| 2143 |  |  |  |  |  |  |  | 
| 2144 | 634 |  |  |  |  | 957 | $istop_mm = $istop_m; | 
| 2145 |  |  |  |  |  |  |  | 
| 2146 |  |  |  |  |  |  | # save _m values of previous group | 
| 2147 | 634 |  |  |  |  | 950 | $line_m    = $line; | 
| 2148 | 634 |  |  |  |  | 923 | $rtokens_m = $rtokens; | 
| 2149 | 634 |  |  |  |  | 892 | $imax_m    = $imax; | 
| 2150 | 634 |  |  |  |  | 984 | $istop_m   = $istop; | 
| 2151 | 634 |  |  |  |  | 1010 | $jbeg_m    = $jbeg; | 
| 2152 | 634 |  |  |  |  | 970 | $jend_m    = $jend; | 
| 2153 |  |  |  |  |  |  |  | 
| 2154 |  |  |  |  |  |  | # Get values for this group. Note that we just have to use values for | 
| 2155 |  |  |  |  |  |  | # one of the lines of the group since all members have the same | 
| 2156 |  |  |  |  |  |  | # alignments. | 
| 2157 | 634 |  |  |  |  | 936 | ( $jbeg, $jend, $istop ) = @{$item}; | 
|  | 634 |  |  |  |  | 1266 |  | 
| 2158 |  |  |  |  |  |  |  | 
| 2159 | 634 |  |  |  |  | 1238 | $line    = $rlines->[$jbeg]; | 
| 2160 | 634 |  |  |  |  | 1155 | $rtokens = $line->{'rtokens'}; | 
| 2161 | 634 |  |  |  |  | 1232 | $imax    = $line->{'jmax'} - 2; | 
| 2162 | 634 | 50 |  |  |  | 1482 | $istop   = -1    if ( !defined($istop) ); | 
| 2163 | 634 | 50 |  |  |  | 1413 | $istop   = $imax if ( $istop > $imax ); | 
| 2164 |  |  |  |  |  |  |  | 
| 2165 |  |  |  |  |  |  | # Initialize on first group | 
| 2166 | 634 | 100 |  |  |  | 1563 | next if ( $ng == 0 ); | 
| 2167 |  |  |  |  |  |  |  | 
| 2168 |  |  |  |  |  |  | # Use the minimum index limit of the two groups | 
| 2169 | 379 | 100 |  |  |  | 1424 | my $imax_min = $imax > $imax_m ? $imax_m : $imax; | 
| 2170 |  |  |  |  |  |  |  | 
| 2171 |  |  |  |  |  |  | # Also impose a limit if given. | 
| 2172 | 379 | 100 |  |  |  | 1167 | if ( $istop_m < $imax_min ) { | 
| 2173 | 51 |  |  |  |  | 153 | $imax_min = $istop_m; | 
| 2174 |  |  |  |  |  |  | } | 
| 2175 |  |  |  |  |  |  |  | 
| 2176 |  |  |  |  |  |  | # Special treatment of two one-line groups isolated from other lines, | 
| 2177 |  |  |  |  |  |  | # unless they form a simple list or a terminal match.  Otherwise the | 
| 2178 |  |  |  |  |  |  | # alignment can look strange in some cases. | 
| 2179 | 379 |  |  |  |  | 1006 | my $list_type = $rlines->[$jbeg]->{'list_type'}; | 
| 2180 | 379 | 100 | 100 |  |  | 4713 | if ( | 
|  |  |  | 100 |  |  |  |  | 
|  |  |  | 100 |  |  |  |  | 
|  |  |  | 100 |  |  |  |  | 
|  |  |  | 100 |  |  |  |  | 
|  |  |  | 100 |  |  |  |  | 
|  |  |  | 100 |  |  |  |  | 
|  |  |  | 100 |  |  |  |  | 
| 2181 |  |  |  |  |  |  | $jend == $jbeg | 
| 2182 |  |  |  |  |  |  | && $jend_m == $jbeg_m | 
| 2183 |  |  |  |  |  |  | && ( $ng == 1 || $istop_mm < 0 ) | 
| 2184 |  |  |  |  |  |  | && ( $ng == $ng_max || $istop < 0 ) | 
| 2185 |  |  |  |  |  |  | && !$line->{'j_terminal_match'} | 
| 2186 |  |  |  |  |  |  |  | 
| 2187 |  |  |  |  |  |  | # Only do this for imperfect matches. This is normally true except | 
| 2188 |  |  |  |  |  |  | # when two perfect matches cannot form a group because the line | 
| 2189 |  |  |  |  |  |  | # length limit would be exceeded. In that case we can still try | 
| 2190 |  |  |  |  |  |  | # to match as many alignments as possible. | 
| 2191 |  |  |  |  |  |  | && ( $imax != $imax_m || $istop_m != $imax_m ) | 
| 2192 |  |  |  |  |  |  | ) | 
| 2193 |  |  |  |  |  |  | { | 
| 2194 |  |  |  |  |  |  |  | 
| 2195 |  |  |  |  |  |  | # We will just align assignments and simple lists | 
| 2196 | 73 | 100 |  |  |  | 330 | next if ( $imax_min < 0 ); | 
| 2197 |  |  |  |  |  |  | next | 
| 2198 | 21 | 100 | 100 |  |  | 197 | if ( $rtokens->[0] !~ /^=\d/ | 
| 2199 |  |  |  |  |  |  | && !$list_type ); | 
| 2200 |  |  |  |  |  |  |  | 
| 2201 |  |  |  |  |  |  | # In this case we will limit padding to a short distance.  This | 
| 2202 |  |  |  |  |  |  | # is a compromise to keep some vertical alignment but prevent large | 
| 2203 |  |  |  |  |  |  | # gaps, which do not look good for just two lines. | 
| 2204 | 18 |  |  |  |  | 275 | my $pad_max = | 
| 2205 |  |  |  |  |  |  | two_line_pad( $rlines->[$jbeg], $rlines->[$jbeg_m], $imax_min ); | 
| 2206 | 18 | 50 |  |  |  | 66 | next if ( !$pad_max ); | 
| 2207 | 18 |  |  |  |  | 51 | my $ng_m = $ng - 1; | 
| 2208 | 18 |  |  |  |  | 71 | $max_move{"$ng_m"} = $pad_max; | 
| 2209 | 18 |  |  |  |  | 65 | $max_move{"$ng"}   = $pad_max; | 
| 2210 |  |  |  |  |  |  | } | 
| 2211 |  |  |  |  |  |  |  | 
| 2212 |  |  |  |  |  |  | # Loop to find all common leading tokens. | 
| 2213 | 324 | 100 |  |  |  | 1203 | if ( $imax_min >= 0 ) { | 
| 2214 | 78 |  |  |  |  | 261 | foreach my $i ( 0 .. $imax_min ) { | 
| 2215 | 144 |  |  |  |  | 270 | my $tok   = $rtokens->[$i]; | 
| 2216 | 144 |  |  |  |  | 266 | my $tok_m = $rtokens_m->[$i]; | 
| 2217 | 144 | 50 |  |  |  | 376 | last if ( $tok ne $tok_m ); | 
| 2218 | 144 |  |  |  |  | 537 | push @icommon, [ $i, $ng, $tok ]; | 
| 2219 |  |  |  |  |  |  | } | 
| 2220 |  |  |  |  |  |  | } | 
| 2221 |  |  |  |  |  |  | } | 
| 2222 | 255 | 100 |  |  |  | 1169 | return unless @icommon; | 
| 2223 |  |  |  |  |  |  |  | 
| 2224 |  |  |  |  |  |  | #---------------------------------------------------------- | 
| 2225 |  |  |  |  |  |  | # Step 2: Reorder and consolidate the list into a task list | 
| 2226 |  |  |  |  |  |  | #---------------------------------------------------------- | 
| 2227 |  |  |  |  |  |  |  | 
| 2228 |  |  |  |  |  |  | # We have to work first from lowest token index to highest, then by group, | 
| 2229 |  |  |  |  |  |  | # sort our list first on token index then group number | 
| 2230 | 64 | 50 |  |  |  | 409 | @icommon = sort { $a->[0] <=> $b->[0] || $a->[1] <=> $b->[1] } @icommon; | 
|  | 160 |  |  |  |  | 443 |  | 
| 2231 |  |  |  |  |  |  |  | 
| 2232 |  |  |  |  |  |  | # Make a task list of the form | 
| 2233 |  |  |  |  |  |  | #   [$i, ng_beg, $ng_end, $tok], .. | 
| 2234 |  |  |  |  |  |  | # where | 
| 2235 |  |  |  |  |  |  | #   $i is the index of the token to be aligned | 
| 2236 |  |  |  |  |  |  | #   $ng_beg..$ng_end is the group range for this action | 
| 2237 | 64 |  |  |  |  | 131 | my @todo; | 
| 2238 | 64 |  |  |  |  | 157 | my ( $i, $ng_end, $tok ); | 
| 2239 | 64 |  |  |  |  | 185 | foreach my $item (@icommon) { | 
| 2240 | 144 |  |  |  |  | 266 | my $ng_last = $ng_end; | 
| 2241 | 144 |  |  |  |  | 230 | my $i_last  = $i; | 
| 2242 | 144 |  |  |  |  | 256 | ( $i, $ng_end, $tok ) = @{$item}; | 
|  | 144 |  |  |  |  | 325 |  | 
| 2243 | 144 |  |  |  |  | 279 | my $ng_beg = $ng_end - 1; | 
| 2244 | 144 | 100 | 100 |  |  | 658 | if ( defined($ng_last) && $ng_beg == $ng_last && $i == $i_last ) { | 
|  |  |  | 66 |  |  |  |  | 
| 2245 | 29 |  |  |  |  | 87 | my $var = pop(@todo); | 
| 2246 | 29 |  |  |  |  | 74 | $ng_beg = $var->[1]; | 
| 2247 |  |  |  |  |  |  | } | 
| 2248 | 144 |  |  |  |  | 373 | my ( $raw_tok, $lev, $tag, $tok_count ) = decode_alignment_token($tok); | 
| 2249 | 144 |  |  |  |  | 582 | push @todo, [ $i, $ng_beg, $ng_end, $raw_tok, $lev ]; | 
| 2250 |  |  |  |  |  |  | } | 
| 2251 |  |  |  |  |  |  |  | 
| 2252 |  |  |  |  |  |  | #------------------------------ | 
| 2253 |  |  |  |  |  |  | # Step 3: Execute the task list | 
| 2254 |  |  |  |  |  |  | #------------------------------ | 
| 2255 | 64 |  |  |  |  | 736 | do_left_to_right_sweep( $rlines, $rgroups, \@todo, \%max_move, $short_pad, | 
| 2256 |  |  |  |  |  |  | $group_level ); | 
| 2257 | 64 |  |  |  |  | 296 | return; | 
| 2258 |  |  |  |  |  |  | } ## end sub sweep_left_to_right | 
| 2259 |  |  |  |  |  |  |  | 
| 2260 |  |  |  |  |  |  | {    ## closure for sub do_left_to_right_sweep | 
| 2261 |  |  |  |  |  |  |  | 
| 2262 |  |  |  |  |  |  | my %is_good_alignment_token; | 
| 2263 |  |  |  |  |  |  |  | 
| 2264 |  |  |  |  |  |  | BEGIN { | 
| 2265 |  |  |  |  |  |  |  | 
| 2266 |  |  |  |  |  |  | # One of the most difficult aspects of vertical alignment is knowing | 
| 2267 |  |  |  |  |  |  | # when not to align.  Alignment can go from looking very nice to very | 
| 2268 |  |  |  |  |  |  | # bad when overdone.  In the sweep algorithm there are two special | 
| 2269 |  |  |  |  |  |  | # cases where we may need to limit padding to a '$short_pad' distance | 
| 2270 |  |  |  |  |  |  | # to avoid some very ugly formatting: | 
| 2271 |  |  |  |  |  |  |  | 
| 2272 |  |  |  |  |  |  | # 1. Two isolated lines with partial alignment | 
| 2273 |  |  |  |  |  |  | # 2. A 'tail-wag-dog' situation, in which a single terminal | 
| 2274 |  |  |  |  |  |  | #    line with partial alignment could cause a significant pad | 
| 2275 |  |  |  |  |  |  | #    increase in many previous lines if allowed to join the alignment. | 
| 2276 |  |  |  |  |  |  |  | 
| 2277 |  |  |  |  |  |  | # For most alignment tokens, we will allow only a small pad to be | 
| 2278 |  |  |  |  |  |  | # introduced (the hardwired $short_pad variable) . But for some 'good' | 
| 2279 |  |  |  |  |  |  | # alignments we can be less restrictive. | 
| 2280 |  |  |  |  |  |  |  | 
| 2281 |  |  |  |  |  |  | # These are 'good' alignments, which are allowed more padding: | 
| 2282 | 39 |  |  | 39 |  | 272 | my @q = qw( | 
| 2283 |  |  |  |  |  |  | => = ? if unless or || { | 
| 2284 |  |  |  |  |  |  | ); | 
| 2285 | 39 |  |  |  |  | 132 | push @q, ','; | 
| 2286 | 39 |  |  |  |  | 319 | @is_good_alignment_token{@q} = (0) x scalar(@q); | 
| 2287 |  |  |  |  |  |  |  | 
| 2288 |  |  |  |  |  |  | # Promote a few of these to 'best', with essentially no pad limit: | 
| 2289 | 39 |  |  |  |  | 165 | $is_good_alignment_token{'='}      = 1; | 
| 2290 | 39 |  |  |  |  | 123 | $is_good_alignment_token{'if'}     = 1; | 
| 2291 | 39 |  |  |  |  | 115 | $is_good_alignment_token{'unless'} = 1; | 
| 2292 | 39 |  |  |  |  | 34258 | $is_good_alignment_token{'=>'}     = 1; | 
| 2293 |  |  |  |  |  |  |  | 
| 2294 |  |  |  |  |  |  | # Note the hash values are set so that: | 
| 2295 |  |  |  |  |  |  | #         if ($is_good_alignment_token{$raw_tok}) => best | 
| 2296 |  |  |  |  |  |  | # if defined ($is_good_alignment_token{$raw_tok}) => good or best | 
| 2297 |  |  |  |  |  |  |  | 
| 2298 |  |  |  |  |  |  | } ## end BEGIN | 
| 2299 |  |  |  |  |  |  |  | 
| 2300 |  |  |  |  |  |  | sub move_to_common_column { | 
| 2301 |  |  |  |  |  |  |  | 
| 2302 |  |  |  |  |  |  | # This is a sub called by sub do_left_to_right_sweep to | 
| 2303 |  |  |  |  |  |  | # move the alignment column of token $itok to $col_want for a | 
| 2304 |  |  |  |  |  |  | # sequence of groups. | 
| 2305 | 118 |  |  | 118 | 0 | 410 | my ( $rlines, $rgroups, $rmax_move, $ngb, $nge, $itok, $col_want, | 
| 2306 |  |  |  |  |  |  | $raw_tok ) | 
| 2307 |  |  |  |  |  |  | = @_; | 
| 2308 | 118 | 100 | 66 |  |  | 551 | return if ( !defined($ngb) || $nge <= $ngb ); | 
| 2309 | 108 |  |  |  |  | 309 | foreach my $ng ( $ngb .. $nge ) { | 
| 2310 |  |  |  |  |  |  |  | 
| 2311 | 242 |  |  |  |  | 387 | my ( $jbeg, $jend ) = @{ $rgroups->[$ng] }; | 
|  | 242 |  |  |  |  | 556 |  | 
| 2312 | 242 |  |  |  |  | 456 | my $line = $rlines->[$jbeg]; | 
| 2313 | 242 |  |  |  |  | 604 | my $col  = $line->get_column($itok); | 
| 2314 | 242 |  |  |  |  | 509 | my $move = $col_want - $col; | 
| 2315 | 242 | 100 |  |  |  | 880 | if ( $move > 0 ) { | 
|  |  | 50 |  |  |  |  |  | 
| 2316 |  |  |  |  |  |  |  | 
| 2317 |  |  |  |  |  |  | # limit padding increase in isolated two lines | 
| 2318 |  |  |  |  |  |  | next | 
| 2319 |  |  |  |  |  |  | if ( defined( $rmax_move->{$ng} ) | 
| 2320 |  |  |  |  |  |  | && $move > $rmax_move->{$ng} | 
| 2321 | 77 | 50 | 66 |  |  | 517 | && !$is_good_alignment_token{$raw_tok} ); | 
|  |  |  | 33 |  |  |  |  | 
| 2322 |  |  |  |  |  |  |  | 
| 2323 | 77 |  |  |  |  | 346 | $line->increase_field_width( $itok, $move ); | 
| 2324 |  |  |  |  |  |  | } | 
| 2325 |  |  |  |  |  |  | elsif ( $move < 0 ) { | 
| 2326 |  |  |  |  |  |  |  | 
| 2327 |  |  |  |  |  |  | # spot to take special action on failure to move | 
| 2328 |  |  |  |  |  |  | } | 
| 2329 |  |  |  |  |  |  | else { | 
| 2330 |  |  |  |  |  |  | ##ok: (move==0) | 
| 2331 |  |  |  |  |  |  | } | 
| 2332 |  |  |  |  |  |  | } | 
| 2333 | 108 |  |  |  |  | 302 | return; | 
| 2334 |  |  |  |  |  |  | } ## end sub move_to_common_column | 
| 2335 |  |  |  |  |  |  |  | 
| 2336 |  |  |  |  |  |  | sub do_left_to_right_sweep { | 
| 2337 | 64 |  |  | 64 | 0 | 262 | my ( $rlines, $rgroups, $rtodo, $rmax_move, $short_pad, $group_level ) | 
| 2338 |  |  |  |  |  |  | = @_; | 
| 2339 |  |  |  |  |  |  |  | 
| 2340 |  |  |  |  |  |  | # $blocking_level[$nj is the level at a match failure between groups | 
| 2341 |  |  |  |  |  |  | # $ng-1 and $ng | 
| 2342 | 64 |  |  |  |  | 139 | my @blocking_level; | 
| 2343 | 64 |  |  |  |  | 196 | my $group_list_type = $rlines->[0]->{'list_type'}; | 
| 2344 |  |  |  |  |  |  |  | 
| 2345 | 64 |  |  |  |  | 1116 | foreach my $task ( @{$rtodo} ) { | 
|  | 64 |  |  |  |  | 201 |  | 
| 2346 | 115 |  |  |  |  | 230 | my ( $itok, $ng_beg, $ng_end, $raw_tok, $lev ) = @{$task}; | 
|  | 115 |  |  |  |  | 340 |  | 
| 2347 |  |  |  |  |  |  |  | 
| 2348 |  |  |  |  |  |  | # Nothing to do for a single group | 
| 2349 | 115 | 50 |  |  |  | 337 | next if ( $ng_end <= $ng_beg ); | 
| 2350 |  |  |  |  |  |  |  | 
| 2351 | 115 |  |  |  |  | 321 | my $ng_first;  # index of the first group of a continuous sequence | 
| 2352 |  |  |  |  |  |  | my $col_want;  # the common alignment column of a sequence of groups | 
| 2353 | 115 |  |  |  |  | 0 | my $col_limit; # maximum column before bumping into max line length | 
| 2354 | 115 |  |  |  |  | 206 | my $line_count_ng_m = 0; | 
| 2355 | 115 |  |  |  |  | 236 | my $jmax_m; | 
| 2356 |  |  |  |  |  |  | my $it_stop_m; | 
| 2357 |  |  |  |  |  |  |  | 
| 2358 |  |  |  |  |  |  | # Loop over the groups | 
| 2359 |  |  |  |  |  |  | # 'ix_' = index in the array of lines | 
| 2360 |  |  |  |  |  |  | # 'ng_' = index in the array of groups | 
| 2361 |  |  |  |  |  |  | # 'it_' = index in the array of tokens | 
| 2362 | 115 |  |  |  |  | 238 | my $ix_min      = $rgroups->[$ng_beg]->[0]; | 
| 2363 | 115 |  |  |  |  | 216 | my $ix_max      = $rgroups->[$ng_end]->[1]; | 
| 2364 | 115 |  |  |  |  | 300 | my $lines_total = $ix_max - $ix_min + 1; | 
| 2365 | 115 |  |  |  |  | 304 | foreach my $ng ( $ng_beg .. $ng_end ) { | 
| 2366 | 259 |  |  |  |  | 380 | my ( $ix_beg, $ix_end, $it_stop ) = @{ $rgroups->[$ng] }; | 
|  | 259 |  |  |  |  | 607 |  | 
| 2367 | 259 |  |  |  |  | 453 | my $line_count_ng = $ix_end - $ix_beg + 1; | 
| 2368 |  |  |  |  |  |  |  | 
| 2369 |  |  |  |  |  |  | # Important: note that since all lines in a group have a common | 
| 2370 |  |  |  |  |  |  | # alignments object, we just have to work on one of the lines | 
| 2371 |  |  |  |  |  |  | # (the first line).  All of the rest will be changed | 
| 2372 |  |  |  |  |  |  | # automatically. | 
| 2373 | 259 |  |  |  |  | 455 | my $line = $rlines->[$ix_beg]; | 
| 2374 | 259 |  |  |  |  | 443 | my $jmax = $line->{'jmax'}; | 
| 2375 |  |  |  |  |  |  |  | 
| 2376 |  |  |  |  |  |  | # the maximum space without exceeding the line length: | 
| 2377 | 259 |  |  |  |  | 727 | my $avail   = $line->get_available_space_on_right(); | 
| 2378 | 259 |  |  |  |  | 654 | my $col     = $line->get_column($itok); | 
| 2379 | 259 |  |  |  |  | 529 | my $col_max = $col + $avail; | 
| 2380 |  |  |  |  |  |  |  | 
| 2381 |  |  |  |  |  |  | # Initialize on first group | 
| 2382 | 259 | 100 |  |  |  | 719 | if ( !defined($col_want) ) { | 
| 2383 | 115 |  |  |  |  | 194 | $ng_first        = $ng; | 
| 2384 | 115 |  |  |  |  | 195 | $col_want        = $col; | 
| 2385 | 115 |  |  |  |  | 201 | $col_limit       = $col_max; | 
| 2386 | 115 |  |  |  |  | 196 | $line_count_ng_m = $line_count_ng; | 
| 2387 | 115 |  |  |  |  | 204 | $jmax_m          = $jmax; | 
| 2388 | 115 |  |  |  |  | 201 | $it_stop_m       = $it_stop; | 
| 2389 | 115 |  |  |  |  | 255 | next; | 
| 2390 |  |  |  |  |  |  | } | 
| 2391 |  |  |  |  |  |  |  | 
| 2392 |  |  |  |  |  |  | # RULE: Throw a blocking flag upon encountering a token level | 
| 2393 |  |  |  |  |  |  | # different from the level of the first blocking token.  For | 
| 2394 |  |  |  |  |  |  | # example, in the following example, if the = matches get | 
| 2395 |  |  |  |  |  |  | # blocked between two groups as shown, then we want to start | 
| 2396 |  |  |  |  |  |  | # blocking matches at the commas, which are at deeper level, so | 
| 2397 |  |  |  |  |  |  | # that we do not get the big gaps shown here: | 
| 2398 |  |  |  |  |  |  |  | 
| 2399 |  |  |  |  |  |  | #  my $unknown3 = pack( "v",          -2 ); | 
| 2400 |  |  |  |  |  |  | #  my $unknown4 = pack( "v",          0x09 ); | 
| 2401 |  |  |  |  |  |  | #  my $unknown5 = pack( "VVV",        0x06, 0x00, 0x00 ); | 
| 2402 |  |  |  |  |  |  | #  my $num_bbd_blocks  = pack( "V",   $num_lists ); | 
| 2403 |  |  |  |  |  |  | #  my $root_startblock = pack( "V",   $root_start ); | 
| 2404 |  |  |  |  |  |  | #  my $unknown6        = pack( "VV",  0x00, 0x1000 ); | 
| 2405 |  |  |  |  |  |  |  | 
| 2406 |  |  |  |  |  |  | # On the other hand, it is okay to keep matching at the same | 
| 2407 |  |  |  |  |  |  | # level such as in a simple list of commas and/or fat commas. | 
| 2408 |  |  |  |  |  |  |  | 
| 2409 | 144 |  | 66 |  |  | 679 | my $is_blocked = defined( $blocking_level[$ng] ) | 
| 2410 |  |  |  |  |  |  | && $lev > $blocking_level[$ng]; | 
| 2411 |  |  |  |  |  |  |  | 
| 2412 |  |  |  |  |  |  | # TAIL-WAG-DOG RULE: prevent a 'tail-wag-dog' syndrom, meaning: | 
| 2413 |  |  |  |  |  |  | # Do not let one or two lines with a **different number of | 
| 2414 |  |  |  |  |  |  | # alignments** open up a big gap in a large block.  For | 
| 2415 |  |  |  |  |  |  | # example, we will prevent something like this, where the first | 
| 2416 |  |  |  |  |  |  | # line pries open the rest: | 
| 2417 |  |  |  |  |  |  |  | 
| 2418 |  |  |  |  |  |  | #  $worksheet->write( "B7", "http://www.perl.com", undef, $format ); | 
| 2419 |  |  |  |  |  |  | #  $worksheet->write( "C7", "",                    $format ); | 
| 2420 |  |  |  |  |  |  | #  $worksheet->write( "D7", "",                    $format ); | 
| 2421 |  |  |  |  |  |  | #  $worksheet->write( "D8", "",                    $format ); | 
| 2422 |  |  |  |  |  |  | #  $worksheet->write( "D8", "",                    $format ); | 
| 2423 |  |  |  |  |  |  |  | 
| 2424 |  |  |  |  |  |  | # We should exclude from consideration two groups which are | 
| 2425 |  |  |  |  |  |  | # effectively the same but separated because one does not | 
| 2426 |  |  |  |  |  |  | # fit in the maximum allowed line length. | 
| 2427 | 144 |  | 100 |  |  | 1191 | my $is_same_group = | 
| 2428 |  |  |  |  |  |  | $jmax == $jmax_m && $it_stop_m == $jmax_m - 2; | 
| 2429 |  |  |  |  |  |  |  | 
| 2430 | 144 |  |  |  |  | 286 | my $lines_above = $ix_beg - $ix_min; | 
| 2431 | 144 |  |  |  |  | 274 | my $lines_below = $lines_total - $lines_above; | 
| 2432 |  |  |  |  |  |  |  | 
| 2433 |  |  |  |  |  |  | # Increase the tolerable gap for certain favorable factors | 
| 2434 | 144 |  |  |  |  | 235 | my $factor    = 1; | 
| 2435 | 144 |  |  |  |  | 285 | my $top_level = $lev == $group_level; | 
| 2436 |  |  |  |  |  |  |  | 
| 2437 |  |  |  |  |  |  | # Align best top level alignment tokens like '=', 'if', ... | 
| 2438 |  |  |  |  |  |  | # A factor of 10 allows a gap of up to 40 spaces | 
| 2439 | 144 | 100 | 100 |  |  | 706 | if ( $top_level && $is_good_alignment_token{$raw_tok} ) { | 
| 2440 | 31 |  |  |  |  | 75 | $factor = 10; | 
| 2441 |  |  |  |  |  |  | } | 
| 2442 |  |  |  |  |  |  |  | 
| 2443 |  |  |  |  |  |  | # Otherwise allow some minimal padding of good alignments | 
| 2444 |  |  |  |  |  |  | else { | 
| 2445 |  |  |  |  |  |  |  | 
| 2446 | 113 | 100 | 100 |  |  | 780 | if ( | 
|  |  |  | 100 |  |  |  |  | 
| 2447 |  |  |  |  |  |  |  | 
| 2448 |  |  |  |  |  |  | defined( $is_good_alignment_token{$raw_tok} ) | 
| 2449 |  |  |  |  |  |  |  | 
| 2450 |  |  |  |  |  |  | # We have to be careful if there are just 2 lines. | 
| 2451 |  |  |  |  |  |  | # This two-line factor allows large gaps only for 2 | 
| 2452 |  |  |  |  |  |  | # lines which are simple lists with fewer items on the | 
| 2453 |  |  |  |  |  |  | # second line. It gives results similar to previous | 
| 2454 |  |  |  |  |  |  | # versions of perltidy. | 
| 2455 |  |  |  |  |  |  | && ( | 
| 2456 |  |  |  |  |  |  | $lines_total > 2 | 
| 2457 |  |  |  |  |  |  | || (   $group_list_type | 
| 2458 |  |  |  |  |  |  | && $jmax < $jmax_m | 
| 2459 |  |  |  |  |  |  | && $top_level ) | 
| 2460 |  |  |  |  |  |  | ) | 
| 2461 |  |  |  |  |  |  | ) | 
| 2462 |  |  |  |  |  |  | { | 
| 2463 | 102 |  |  |  |  | 187 | $factor += 1; | 
| 2464 | 102 | 100 |  |  |  | 259 | if ($top_level) { | 
| 2465 | 66 |  |  |  |  | 107 | $factor += 1; | 
| 2466 |  |  |  |  |  |  | } | 
| 2467 |  |  |  |  |  |  | } | 
| 2468 |  |  |  |  |  |  | } | 
| 2469 |  |  |  |  |  |  |  | 
| 2470 | 144 |  |  |  |  | 258 | my $is_big_gap; | 
| 2471 | 144 | 100 |  |  |  | 369 | if ( !$is_same_group ) { | 
| 2472 | 118 |  | 66 |  |  | 1037 | $is_big_gap ||= | 
|  |  |  | 33 |  |  |  |  | 
| 2473 |  |  |  |  |  |  | (      $lines_above == 1 | 
| 2474 |  |  |  |  |  |  | || $lines_above == 2 && $lines_below >= 4 ) | 
| 2475 |  |  |  |  |  |  | && $col_want > $col + $short_pad * $factor; | 
| 2476 | 118 |  | 66 |  |  | 859 | $is_big_gap ||= | 
|  |  |  | 33 |  |  |  |  | 
| 2477 |  |  |  |  |  |  | (      $lines_below == 1 | 
| 2478 |  |  |  |  |  |  | || $lines_below == 2 && $lines_above >= 4 ) | 
| 2479 |  |  |  |  |  |  | && $col > $col_want + $short_pad * $factor; | 
| 2480 |  |  |  |  |  |  | } | 
| 2481 |  |  |  |  |  |  |  | 
| 2482 |  |  |  |  |  |  | # if match is limited by gap size, stop aligning at this level | 
| 2483 | 144 | 50 |  |  |  | 383 | if ($is_big_gap) { | 
| 2484 | 0 |  |  |  |  | 0 | $blocking_level[$ng] = $lev - 1; | 
| 2485 |  |  |  |  |  |  | } | 
| 2486 |  |  |  |  |  |  |  | 
| 2487 |  |  |  |  |  |  | # quit and restart if it cannot join this batch | 
| 2488 | 144 | 50 | 100 |  |  | 1026 | if (   $col_want > $col_max | 
|  |  |  | 66 |  |  |  |  | 
|  |  |  | 66 |  |  |  |  | 
| 2489 |  |  |  |  |  |  | || $col > $col_limit | 
| 2490 |  |  |  |  |  |  | || $is_big_gap | 
| 2491 |  |  |  |  |  |  | || $is_blocked ) | 
| 2492 |  |  |  |  |  |  | { | 
| 2493 |  |  |  |  |  |  |  | 
| 2494 |  |  |  |  |  |  | # remember the level of the first blocking token | 
| 2495 | 10 | 100 |  |  |  | 33 | if ( !defined( $blocking_level[$ng] ) ) { | 
| 2496 | 9 |  |  |  |  | 23 | $blocking_level[$ng] = $lev; | 
| 2497 |  |  |  |  |  |  | } | 
| 2498 |  |  |  |  |  |  |  | 
| 2499 |  |  |  |  |  |  | move_to_common_column( | 
| 2500 | 10 |  |  |  |  | 34 | $rlines, $rgroups, $rmax_move, $ng_first, | 
| 2501 |  |  |  |  |  |  | $ng - 1, $itok,    $col_want,  $raw_tok | 
| 2502 |  |  |  |  |  |  | ); | 
| 2503 | 10 |  |  |  |  | 21 | $ng_first        = $ng; | 
| 2504 | 10 |  |  |  |  | 21 | $col_want        = $col; | 
| 2505 | 10 |  |  |  |  | 14 | $col_limit       = $col_max; | 
| 2506 | 10 |  |  |  |  | 18 | $line_count_ng_m = $line_count_ng; | 
| 2507 | 10 |  |  |  |  | 18 | $jmax_m          = $jmax; | 
| 2508 | 10 |  |  |  |  | 16 | $it_stop_m       = $it_stop; | 
| 2509 | 10 |  |  |  |  | 21 | next; | 
| 2510 |  |  |  |  |  |  | } | 
| 2511 |  |  |  |  |  |  |  | 
| 2512 | 134 |  |  |  |  | 253 | $line_count_ng_m += $line_count_ng; | 
| 2513 |  |  |  |  |  |  |  | 
| 2514 |  |  |  |  |  |  | # update the common column and limit | 
| 2515 | 134 | 100 |  |  |  | 358 | if ( $col > $col_want )      { $col_want  = $col } | 
|  | 42 |  |  |  |  | 89 |  | 
| 2516 | 134 | 100 |  |  |  | 408 | if ( $col_max < $col_limit ) { $col_limit = $col_max } | 
|  | 35 |  |  |  |  | 90 |  | 
| 2517 |  |  |  |  |  |  |  | 
| 2518 |  |  |  |  |  |  | } ## end loop over groups | 
| 2519 |  |  |  |  |  |  |  | 
| 2520 | 115 | 100 |  |  |  | 357 | if ( $ng_end > $ng_first ) { | 
| 2521 | 108 |  |  |  |  | 419 | move_to_common_column( | 
| 2522 |  |  |  |  |  |  | $rlines, $rgroups, $rmax_move, $ng_first, | 
| 2523 |  |  |  |  |  |  | $ng_end, $itok,    $col_want,  $raw_tok | 
| 2524 |  |  |  |  |  |  | ); | 
| 2525 |  |  |  |  |  |  | } ## end loop over groups for one task | 
| 2526 |  |  |  |  |  |  | } ## end loop over tasks | 
| 2527 |  |  |  |  |  |  |  | 
| 2528 | 64 |  |  |  |  | 169 | return; | 
| 2529 |  |  |  |  |  |  | } ## end sub do_left_to_right_sweep | 
| 2530 |  |  |  |  |  |  | } | 
| 2531 |  |  |  |  |  |  |  | 
| 2532 |  |  |  |  |  |  | sub delete_selected_tokens { | 
| 2533 |  |  |  |  |  |  |  | 
| 2534 | 469 |  |  | 469 | 0 | 1108 | my ( $line_obj, $ridel ) = @_; | 
| 2535 |  |  |  |  |  |  |  | 
| 2536 |  |  |  |  |  |  | # $line_obj    is the line to be modified | 
| 2537 |  |  |  |  |  |  | # $ridel       is a ref to list of indexes to be deleted | 
| 2538 |  |  |  |  |  |  |  | 
| 2539 |  |  |  |  |  |  | # remove an unused alignment token(s) to improve alignment chances | 
| 2540 |  |  |  |  |  |  |  | 
| 2541 | 469 | 50 | 33 |  |  | 2182 | return if ( !defined($line_obj) || !defined($ridel) || !@{$ridel} ); | 
|  | 469 |  | 33 |  |  | 1535 |  | 
| 2542 |  |  |  |  |  |  |  | 
| 2543 | 469 |  |  |  |  | 1084 | my $jmax_old           = $line_obj->{'jmax'}; | 
| 2544 | 469 |  |  |  |  | 1025 | my $rfields_old        = $line_obj->{'rfields'}; | 
| 2545 | 469 |  |  |  |  | 893 | my $rfield_lengths_old = $line_obj->{'rfield_lengths'}; | 
| 2546 | 469 |  |  |  |  | 957 | my $rpatterns_old      = $line_obj->{'rpatterns'}; | 
| 2547 | 469 |  |  |  |  | 901 | my $rtokens_old        = $line_obj->{'rtokens'}; | 
| 2548 | 469 |  |  |  |  | 920 | my $j_terminal_match   = $line_obj->{'j_terminal_match'}; | 
| 2549 |  |  |  |  |  |  |  | 
| 2550 | 39 |  |  | 39 |  | 385 | use constant EXPLAIN_DELETE_SELECTED => 0; | 
|  | 39 |  |  |  |  | 136 |  | 
|  | 39 |  |  |  |  | 35072 |  | 
| 2551 |  |  |  |  |  |  |  | 
| 2552 | 469 |  |  |  |  | 1214 | local $LIST_SEPARATOR = '> <'; | 
| 2553 | 469 |  |  |  |  | 707 | EXPLAIN_DELETE_SELECTED && print <<EOM; | 
| 2554 |  |  |  |  |  |  | delete indexes: <@{$ridel}> | 
| 2555 |  |  |  |  |  |  | old jmax: $jmax_old | 
| 2556 |  |  |  |  |  |  | old tokens: <@{$rtokens_old}> | 
| 2557 |  |  |  |  |  |  | old patterns: <@{$rpatterns_old}> | 
| 2558 |  |  |  |  |  |  | old fields: <@{$rfields_old}> | 
| 2559 |  |  |  |  |  |  | old field_lengths: <@{$rfield_lengths_old}> | 
| 2560 |  |  |  |  |  |  | EOM | 
| 2561 |  |  |  |  |  |  |  | 
| 2562 | 469 |  |  |  |  | 951 | my $rfields_new        = []; | 
| 2563 | 469 |  |  |  |  | 942 | my $rpatterns_new      = []; | 
| 2564 | 469 |  |  |  |  | 965 | my $rtokens_new        = []; | 
| 2565 | 469 |  |  |  |  | 1062 | my $rfield_lengths_new = []; | 
| 2566 |  |  |  |  |  |  |  | 
| 2567 |  |  |  |  |  |  | # Convert deletion list to a hash to allow any order, multiple entries, | 
| 2568 |  |  |  |  |  |  | # and avoid problems with index values out of range | 
| 2569 | 469 |  |  |  |  | 811 | my %delete_me; | 
| 2570 | 469 |  |  |  |  | 809 | @delete_me{ @{$ridel} } = (1) x scalar( @{$ridel} ); | 
|  | 469 |  |  |  |  | 1653 |  | 
|  | 469 |  |  |  |  | 1068 |  | 
| 2571 |  |  |  |  |  |  |  | 
| 2572 | 469 |  |  |  |  | 1153 | my $pattern_0      = $rpatterns_old->[0]; | 
| 2573 | 469 |  |  |  |  | 976 | my $field_0        = $rfields_old->[0]; | 
| 2574 | 469 |  |  |  |  | 918 | my $field_length_0 = $rfield_lengths_old->[0]; | 
| 2575 | 469 |  |  |  |  | 807 | push @{$rfields_new},        $field_0; | 
|  | 469 |  |  |  |  | 1074 |  | 
| 2576 | 469 |  |  |  |  | 787 | push @{$rfield_lengths_new}, $field_length_0; | 
|  | 469 |  |  |  |  | 984 |  | 
| 2577 | 469 |  |  |  |  | 791 | push @{$rpatterns_new},      $pattern_0; | 
|  | 469 |  |  |  |  | 1058 |  | 
| 2578 |  |  |  |  |  |  |  | 
| 2579 |  |  |  |  |  |  | # Loop to either copy items or concatenate fields and patterns | 
| 2580 | 469 |  |  |  |  | 813 | my $jmin_del; | 
| 2581 | 469 |  |  |  |  | 1374 | foreach my $j ( 0 .. $jmax_old - 1 ) { | 
| 2582 | 1515 |  |  |  |  | 2540 | my $token        = $rtokens_old->[$j]; | 
| 2583 | 1515 |  |  |  |  | 2788 | my $field        = $rfields_old->[ $j + 1 ]; | 
| 2584 | 1515 |  |  |  |  | 2298 | my $field_length = $rfield_lengths_old->[ $j + 1 ]; | 
| 2585 | 1515 |  |  |  |  | 2606 | my $pattern      = $rpatterns_old->[ $j + 1 ]; | 
| 2586 | 1515 | 100 |  |  |  | 3231 | if ( !$delete_me{$j} ) { | 
| 2587 | 743 |  |  |  |  | 1258 | push @{$rtokens_new},        $token; | 
|  | 743 |  |  |  |  | 1590 |  | 
| 2588 | 743 |  |  |  |  | 1221 | push @{$rfields_new},        $field; | 
|  | 743 |  |  |  |  | 1361 |  | 
| 2589 | 743 |  |  |  |  | 1238 | push @{$rpatterns_new},      $pattern; | 
|  | 743 |  |  |  |  | 1325 |  | 
| 2590 | 743 |  |  |  |  | 1130 | push @{$rfield_lengths_new}, $field_length; | 
|  | 743 |  |  |  |  | 1745 |  | 
| 2591 |  |  |  |  |  |  | } | 
| 2592 |  |  |  |  |  |  | else { | 
| 2593 | 772 | 100 |  |  |  | 1904 | if ( !defined($jmin_del) ) { $jmin_del = $j } | 
|  | 469 |  |  |  |  | 892 |  | 
| 2594 | 772 |  |  |  |  | 1780 | $rfields_new->[-1] .= $field; | 
| 2595 | 772 |  |  |  |  | 1265 | $rfield_lengths_new->[-1] += $field_length; | 
| 2596 | 772 |  |  |  |  | 1699 | $rpatterns_new->[-1] .= $pattern; | 
| 2597 |  |  |  |  |  |  | } | 
| 2598 |  |  |  |  |  |  | } | 
| 2599 |  |  |  |  |  |  |  | 
| 2600 |  |  |  |  |  |  | # ----- x ------ x ------ x ------ | 
| 2601 |  |  |  |  |  |  | #t      0        1        2        <- token indexing | 
| 2602 |  |  |  |  |  |  | #f   0      1        2        3    <- field and pattern | 
| 2603 |  |  |  |  |  |  |  | 
| 2604 | 469 |  |  |  |  | 948 | my $jmax_new = @{$rfields_new} - 1; | 
|  | 469 |  |  |  |  | 1107 |  | 
| 2605 | 469 |  |  |  |  | 982 | $line_obj->{'rtokens'}        = $rtokens_new; | 
| 2606 | 469 |  |  |  |  | 854 | $line_obj->{'rpatterns'}      = $rpatterns_new; | 
| 2607 | 469 |  |  |  |  | 874 | $line_obj->{'rfields'}        = $rfields_new; | 
| 2608 | 469 |  |  |  |  | 844 | $line_obj->{'rfield_lengths'} = $rfield_lengths_new; | 
| 2609 | 469 |  |  |  |  | 836 | $line_obj->{'jmax'}           = $jmax_new; | 
| 2610 |  |  |  |  |  |  |  | 
| 2611 |  |  |  |  |  |  | # The value of j_terminal_match will be incorrect if we delete tokens prior | 
| 2612 |  |  |  |  |  |  | # to it. We will have to give up on aligning the terminal tokens if this | 
| 2613 |  |  |  |  |  |  | # happens. | 
| 2614 | 469 | 100 | 100 |  |  | 1429 | if ( defined($j_terminal_match) && $jmin_del <= $j_terminal_match ) { | 
| 2615 | 1 |  |  |  |  | 5 | $line_obj->{'j_terminal_match'} = undef; | 
| 2616 |  |  |  |  |  |  | } | 
| 2617 |  |  |  |  |  |  |  | 
| 2618 |  |  |  |  |  |  | # update list type - | 
| 2619 | 469 | 100 |  |  |  | 1203 | if ( $line_obj->{'list_seqno'} ) { | 
| 2620 |  |  |  |  |  |  |  | 
| 2621 |  |  |  |  |  |  | ## This works, but for efficiency see if we need to make a change: | 
| 2622 |  |  |  |  |  |  | ## decide_if_list($line_obj); | 
| 2623 |  |  |  |  |  |  |  | 
| 2624 |  |  |  |  |  |  | # An existing list will still be a list but with possibly different | 
| 2625 |  |  |  |  |  |  | # leading token | 
| 2626 | 76 |  |  |  |  | 201 | my $old_list_type = $line_obj->{'list_type'}; | 
| 2627 | 76 |  |  |  |  | 152 | my $new_list_type = EMPTY_STRING; | 
| 2628 | 76 | 100 |  |  |  | 505 | if ( $rtokens_new->[0] =~ /^(=>|,)/ ) { | 
| 2629 | 49 |  |  |  |  | 126 | $new_list_type = $rtokens_new->[0]; | 
| 2630 |  |  |  |  |  |  | } | 
| 2631 | 76 | 100 | 100 |  |  | 447 | if ( !$old_list_type || $old_list_type ne $new_list_type ) { | 
| 2632 | 44 |  |  |  |  | 156 | decide_if_list($line_obj); | 
| 2633 |  |  |  |  |  |  | } | 
| 2634 |  |  |  |  |  |  | } | 
| 2635 |  |  |  |  |  |  |  | 
| 2636 | 469 |  |  |  |  | 805 | EXPLAIN_DELETE_SELECTED && print <<EOM; | 
| 2637 |  |  |  |  |  |  |  | 
| 2638 |  |  |  |  |  |  | new jmax: $jmax_new | 
| 2639 |  |  |  |  |  |  | new tokens: <@{$rtokens_new}> | 
| 2640 |  |  |  |  |  |  | new patterns: <@{$rpatterns_new}> | 
| 2641 |  |  |  |  |  |  | new fields: <@{$rfields_new}> | 
| 2642 |  |  |  |  |  |  | EOM | 
| 2643 | 469 |  |  |  |  | 3499 | return; | 
| 2644 |  |  |  |  |  |  | } ## end sub delete_selected_tokens | 
| 2645 |  |  |  |  |  |  |  | 
| 2646 |  |  |  |  |  |  | {    ## closure for sub decode_alignment_token | 
| 2647 |  |  |  |  |  |  |  | 
| 2648 |  |  |  |  |  |  | # This routine is called repeatedly for each token, so it needs to be | 
| 2649 |  |  |  |  |  |  | # efficient.  We can speed things up by remembering the inputs and outputs | 
| 2650 |  |  |  |  |  |  | # in a hash. | 
| 2651 |  |  |  |  |  |  | my %decoded_token; | 
| 2652 |  |  |  |  |  |  |  | 
| 2653 |  |  |  |  |  |  | sub initialize_decode { | 
| 2654 |  |  |  |  |  |  |  | 
| 2655 |  |  |  |  |  |  | # We will re-initialize the hash for each file. Otherwise, there is | 
| 2656 |  |  |  |  |  |  | # a danger that the hash can become arbitrarily large if a very large | 
| 2657 |  |  |  |  |  |  | # number of files is processed at once. | 
| 2658 | 560 |  |  | 560 | 0 | 4182 | %decoded_token = (); | 
| 2659 | 560 |  |  |  |  | 1106 | return; | 
| 2660 |  |  |  |  |  |  | } ## end sub initialize_decode | 
| 2661 |  |  |  |  |  |  |  | 
| 2662 |  |  |  |  |  |  | sub decode_alignment_token { | 
| 2663 |  |  |  |  |  |  |  | 
| 2664 |  |  |  |  |  |  | # Unpack the values packed in an alignment token | 
| 2665 |  |  |  |  |  |  | # | 
| 2666 |  |  |  |  |  |  | # Usage: | 
| 2667 |  |  |  |  |  |  | #        my ( $raw_tok, $lev, $tag, $tok_count ) = | 
| 2668 |  |  |  |  |  |  | #          decode_alignment_token($token); | 
| 2669 |  |  |  |  |  |  |  | 
| 2670 |  |  |  |  |  |  | # Alignment tokens have a trailing decimal level and optional tag (for | 
| 2671 |  |  |  |  |  |  | # commas): | 
| 2672 |  |  |  |  |  |  | # For example, the first comma in the following line | 
| 2673 |  |  |  |  |  |  | #     sub banner  { crlf; report( shift, '/', shift ); crlf } | 
| 2674 |  |  |  |  |  |  | # is decorated as follows: | 
| 2675 |  |  |  |  |  |  | #    ,2+report-6  => (tok,lev,tag) =qw( ,   2   +report-6) | 
| 2676 |  |  |  |  |  |  |  | 
| 2677 |  |  |  |  |  |  | # An optional token count may be appended with a leading dot. | 
| 2678 |  |  |  |  |  |  | # Currently this is only done for '=' tokens but this could change. | 
| 2679 |  |  |  |  |  |  | # For example, consider the following line: | 
| 2680 |  |  |  |  |  |  | #   $nport   = $port = shift || $name; | 
| 2681 |  |  |  |  |  |  | # The first '=' may either be '=0' or '=0.1' [level 0, first equals] | 
| 2682 |  |  |  |  |  |  | # The second '=' will be '=0.2' [level 0, second equals] | 
| 2683 | 9364 |  |  | 9364 | 0 | 16074 | my ($tok) = @_; | 
| 2684 |  |  |  |  |  |  |  | 
| 2685 | 9364 | 100 |  |  |  | 19276 | if ( defined( $decoded_token{$tok} ) ) { | 
| 2686 | 7923 |  |  |  |  | 11100 | return @{ $decoded_token{$tok} }; | 
|  | 7923 |  |  |  |  | 30036 |  | 
| 2687 |  |  |  |  |  |  | } | 
| 2688 |  |  |  |  |  |  |  | 
| 2689 | 1441 |  |  |  |  | 4084 | my ( $raw_tok, $lev, $tag, $tok_count ) = ( $tok, 0, EMPTY_STRING, 1 ); | 
| 2690 | 1441 | 100 |  |  |  | 9341 | if ( $tok =~ /^(\D+)(\d+)([^\.]*)(\.(\d+))?$/ ) { | 
| 2691 | 1135 |  |  |  |  | 3299 | $raw_tok   = $1; | 
| 2692 | 1135 |  |  |  |  | 2287 | $lev       = $2; | 
| 2693 | 1135 | 100 |  |  |  | 4248 | $tag       = $3 if ($3); | 
| 2694 | 1135 | 100 |  |  |  | 3211 | $tok_count = $5 if ($5); | 
| 2695 |  |  |  |  |  |  | } | 
| 2696 | 1441 |  |  |  |  | 4862 | my @vals = ( $raw_tok, $lev, $tag, $tok_count ); | 
| 2697 | 1441 |  |  |  |  | 4187 | $decoded_token{$tok} = \@vals; | 
| 2698 | 1441 |  |  |  |  | 6189 | return @vals; | 
| 2699 |  |  |  |  |  |  | } ## end sub decode_alignment_token | 
| 2700 |  |  |  |  |  |  | } | 
| 2701 |  |  |  |  |  |  |  | 
| 2702 |  |  |  |  |  |  | {    ## closure for sub delete_unmatched_tokens | 
| 2703 |  |  |  |  |  |  |  | 
| 2704 |  |  |  |  |  |  | my %is_assignment; | 
| 2705 |  |  |  |  |  |  | my %keep_after_deleted_assignment; | 
| 2706 |  |  |  |  |  |  |  | 
| 2707 |  |  |  |  |  |  | BEGIN { | 
| 2708 | 39 |  |  | 39 |  | 260 | my @q; | 
| 2709 |  |  |  |  |  |  |  | 
| 2710 | 39 |  |  |  |  | 403 | @q = qw( | 
| 2711 |  |  |  |  |  |  | = **= += *= &= <<= &&= | 
| 2712 |  |  |  |  |  |  | -= /= |= >>= ||= //= | 
| 2713 |  |  |  |  |  |  | .= %= ^= | 
| 2714 |  |  |  |  |  |  | x= | 
| 2715 |  |  |  |  |  |  | ); | 
| 2716 | 39 |  |  |  |  | 706 | @is_assignment{@q} = (1) x scalar(@q); | 
| 2717 |  |  |  |  |  |  |  | 
| 2718 |  |  |  |  |  |  | # These tokens may be kept following an = deletion | 
| 2719 | 39 |  |  |  |  | 169 | @q = qw( | 
| 2720 |  |  |  |  |  |  | if unless or || | 
| 2721 |  |  |  |  |  |  | ); | 
| 2722 | 39 |  |  |  |  | 89328 | @keep_after_deleted_assignment{@q} = (1) x scalar(@q); | 
| 2723 |  |  |  |  |  |  |  | 
| 2724 |  |  |  |  |  |  | } ## end BEGIN | 
| 2725 |  |  |  |  |  |  |  | 
| 2726 |  |  |  |  |  |  | sub delete_unmatched_tokens { | 
| 2727 | 1705 |  |  | 1705 | 0 | 4012 | my ( $rlines, $group_level ) = @_; | 
| 2728 |  |  |  |  |  |  |  | 
| 2729 |  |  |  |  |  |  | # This is a important first step in vertical alignment in which | 
| 2730 |  |  |  |  |  |  | # we remove as many obviously un-needed alignment tokens as possible. | 
| 2731 |  |  |  |  |  |  | # This will prevent them from interfering with the final alignment. | 
| 2732 |  |  |  |  |  |  |  | 
| 2733 |  |  |  |  |  |  | # Returns: | 
| 2734 | 1705 |  |  |  |  | 2840 | my $max_lev_diff     = 0;    # used to avoid a call to prune_tree | 
| 2735 | 1705 |  |  |  |  | 2858 | my $saw_side_comment = 0;    # used to avoid a call for side comments | 
| 2736 |  |  |  |  |  |  |  | 
| 2737 |  |  |  |  |  |  | # Handle no lines -- shouldn't happen | 
| 2738 | 1705 | 50 |  |  |  | 2816 | return unless @{$rlines}; | 
|  | 1705 |  |  |  |  | 4341 |  | 
| 2739 |  |  |  |  |  |  |  | 
| 2740 |  |  |  |  |  |  | # Handle a single line | 
| 2741 | 1705 | 100 |  |  |  | 2792 | if ( @{$rlines} == 1 ) { | 
|  | 1705 |  |  |  |  | 4720 |  | 
| 2742 | 1121 |  |  |  |  | 2456 | my $line   = $rlines->[0]; | 
| 2743 | 1121 |  |  |  |  | 2476 | my $jmax   = $line->{'jmax'}; | 
| 2744 | 1121 |  |  |  |  | 2451 | my $length = $line->{'rfield_lengths'}->[$jmax]; | 
| 2745 | 1121 |  |  |  |  | 2391 | $saw_side_comment = $length > 0; | 
| 2746 | 1121 |  |  |  |  | 4730 | return ( $max_lev_diff, $saw_side_comment ); | 
| 2747 |  |  |  |  |  |  | } | 
| 2748 |  |  |  |  |  |  |  | 
| 2749 |  |  |  |  |  |  | # ignore hanging side comments in these operations | 
| 2750 | 584 |  |  |  |  | 1410 | my @filtered   = grep { !$_->{'is_hanging_side_comment'} } @{$rlines}; | 
|  | 1944 |  |  |  |  | 6057 |  | 
|  | 584 |  |  |  |  | 1726 |  | 
| 2751 | 584 |  |  |  |  | 1639 | my $rnew_lines = \@filtered; | 
| 2752 |  |  |  |  |  |  |  | 
| 2753 | 584 |  |  |  |  | 1223 | $saw_side_comment = @filtered != @{$rlines}; | 
|  | 584 |  |  |  |  | 1386 |  | 
| 2754 | 584 |  |  |  |  | 1175 | $max_lev_diff     = 0; | 
| 2755 |  |  |  |  |  |  |  | 
| 2756 |  |  |  |  |  |  | # nothing to do if all lines were hanging side comments | 
| 2757 | 584 |  |  |  |  | 970 | my $jmax = @{$rnew_lines} - 1; | 
|  | 584 |  |  |  |  | 1274 |  | 
| 2758 | 584 | 100 |  |  |  | 1751 | return ( $max_lev_diff, $saw_side_comment ) if ( $jmax < 0 ); | 
| 2759 |  |  |  |  |  |  |  | 
| 2760 |  |  |  |  |  |  | #---------------------------------------------------- | 
| 2761 |  |  |  |  |  |  | # Create a hash of alignment token info for each line | 
| 2762 |  |  |  |  |  |  | #---------------------------------------------------- | 
| 2763 | 583 |  |  |  |  | 2161 | ( my $rline_hashes, my $requals_info, $saw_side_comment, $max_lev_diff ) | 
| 2764 |  |  |  |  |  |  | = make_alignment_info( $group_level, $rnew_lines, $saw_side_comment ); | 
| 2765 |  |  |  |  |  |  |  | 
| 2766 |  |  |  |  |  |  | #------------------------------------------------------------ | 
| 2767 |  |  |  |  |  |  | # Find independent subgroups of lines.  Neighboring subgroups | 
| 2768 |  |  |  |  |  |  | # do not have a common alignment token. | 
| 2769 |  |  |  |  |  |  | #------------------------------------------------------------ | 
| 2770 | 583 |  |  |  |  | 1267 | my @subgroups; | 
| 2771 | 583 |  |  |  |  | 1659 | push @subgroups, [ 0, $jmax ]; | 
| 2772 | 583 |  |  |  |  | 1965 | foreach my $jl ( 0 .. $jmax - 1 ) { | 
| 2773 | 1315 | 100 |  |  |  | 3548 | if ( $rnew_lines->[$jl]->{'end_group'} ) { | 
| 2774 | 72 |  |  |  |  | 207 | $subgroups[-1]->[1] = $jl; | 
| 2775 | 72 |  |  |  |  | 276 | push @subgroups, [ $jl + 1, $jmax ]; | 
| 2776 |  |  |  |  |  |  | } | 
| 2777 |  |  |  |  |  |  | } | 
| 2778 |  |  |  |  |  |  |  | 
| 2779 |  |  |  |  |  |  | #----------------------------------------------------------- | 
| 2780 |  |  |  |  |  |  | # PASS 1 over subgroups to remove unmatched alignment tokens | 
| 2781 |  |  |  |  |  |  | #----------------------------------------------------------- | 
| 2782 |  |  |  |  |  |  | delete_unmatched_tokens_main_loop( | 
| 2783 | 583 |  |  |  |  | 2831 | $group_level,  $rnew_lines, \@subgroups, | 
| 2784 |  |  |  |  |  |  | $rline_hashes, $requals_info | 
| 2785 |  |  |  |  |  |  | ); | 
| 2786 |  |  |  |  |  |  |  | 
| 2787 |  |  |  |  |  |  | #---------------------------------------------------------------- | 
| 2788 |  |  |  |  |  |  | # PASS 2: Construct a tree of matched lines and delete some small | 
| 2789 |  |  |  |  |  |  | # deeper levels of tokens.  They also block good alignments. | 
| 2790 |  |  |  |  |  |  | #---------------------------------------------------------------- | 
| 2791 | 583 | 100 |  |  |  | 2695 | prune_alignment_tree($rnew_lines) if ($max_lev_diff); | 
| 2792 |  |  |  |  |  |  |  | 
| 2793 |  |  |  |  |  |  | #-------------------------------------------- | 
| 2794 |  |  |  |  |  |  | # PASS 3: compare all lines for common tokens | 
| 2795 |  |  |  |  |  |  | #-------------------------------------------- | 
| 2796 | 583 |  |  |  |  | 2871 | match_line_pairs( $rlines, $rnew_lines, \@subgroups, $group_level ); | 
| 2797 |  |  |  |  |  |  |  | 
| 2798 | 583 |  |  |  |  | 6178 | return ( $max_lev_diff, $saw_side_comment ); | 
| 2799 |  |  |  |  |  |  | } ## end sub delete_unmatched_tokens | 
| 2800 |  |  |  |  |  |  |  | 
| 2801 |  |  |  |  |  |  | sub make_alignment_info { | 
| 2802 |  |  |  |  |  |  |  | 
| 2803 | 583 |  |  | 583 | 0 | 1754 | my ( $group_level, $rnew_lines, $saw_side_comment ) = @_; | 
| 2804 |  |  |  |  |  |  |  | 
| 2805 |  |  |  |  |  |  | #------------------------------------------------------------ | 
| 2806 |  |  |  |  |  |  | # Loop to create a hash of alignment token info for each line | 
| 2807 |  |  |  |  |  |  | #------------------------------------------------------------ | 
| 2808 | 583 |  |  |  |  | 1274 | my $rline_hashes = []; | 
| 2809 | 583 |  |  |  |  | 1241 | my @equals_info; | 
| 2810 |  |  |  |  |  |  | my @line_info;    # no longer used | 
| 2811 | 583 |  |  |  |  | 987 | my $jmax         = @{$rnew_lines} - 1; | 
|  | 583 |  |  |  |  | 1347 |  | 
| 2812 | 583 |  |  |  |  | 1138 | my $max_lev_diff = 0; | 
| 2813 | 583 |  |  |  |  | 1111 | foreach my $line ( @{$rnew_lines} ) { | 
|  | 583 |  |  |  |  | 1625 |  | 
| 2814 | 1898 |  |  |  |  | 3304 | my $rhash     = {}; | 
| 2815 | 1898 |  |  |  |  | 3741 | my $rtokens   = $line->{'rtokens'}; | 
| 2816 | 1898 |  |  |  |  | 3118 | my $rpatterns = $line->{'rpatterns'}; | 
| 2817 | 1898 |  |  |  |  | 2859 | my $i         = 0; | 
| 2818 | 1898 |  |  |  |  | 4552 | my ( $i_eq, $tok_eq, $pat_eq ); | 
| 2819 | 1898 |  |  |  |  | 0 | my ( $lev_min, $lev_max ); | 
| 2820 | 1898 |  |  |  |  | 2692 | foreach my $tok ( @{$rtokens} ) { | 
|  | 1898 |  |  |  |  | 3586 |  | 
| 2821 | 5174 |  |  |  |  | 9692 | my ( $raw_tok, $lev, $tag, $tok_count ) = | 
| 2822 |  |  |  |  |  |  | decode_alignment_token($tok); | 
| 2823 |  |  |  |  |  |  |  | 
| 2824 | 5174 | 100 |  |  |  | 11163 | if ( $tok ne '#' ) { | 
| 2825 | 3276 | 100 |  |  |  | 6107 | if ( !defined($lev_min) ) { | 
| 2826 | 1779 |  |  |  |  | 2901 | $lev_min = $lev; | 
| 2827 | 1779 |  |  |  |  | 2844 | $lev_max = $lev; | 
| 2828 |  |  |  |  |  |  | } | 
| 2829 |  |  |  |  |  |  | else { | 
| 2830 | 1497 | 100 |  |  |  | 3825 | if ( $lev < $lev_min ) { $lev_min = $lev } | 
|  | 75 |  |  |  |  | 144 |  | 
| 2831 | 1497 | 100 |  |  |  | 3173 | if ( $lev > $lev_max ) { $lev_max = $lev } | 
|  | 260 |  |  |  |  | 528 |  | 
| 2832 |  |  |  |  |  |  | } | 
| 2833 |  |  |  |  |  |  | } | 
| 2834 |  |  |  |  |  |  | else { | 
| 2835 | 1898 | 100 |  |  |  | 4626 | if ( !$saw_side_comment ) { | 
| 2836 | 1709 |  |  |  |  | 3830 | my $length = $line->{'rfield_lengths'}->[ $i + 1 ]; | 
| 2837 | 1709 |  | 66 |  |  | 5214 | $saw_side_comment ||= $length; | 
| 2838 |  |  |  |  |  |  | } | 
| 2839 |  |  |  |  |  |  | } | 
| 2840 |  |  |  |  |  |  |  | 
| 2841 |  |  |  |  |  |  | # Possible future upgrade: for multiple matches, | 
| 2842 |  |  |  |  |  |  | # record [$i1, $i2, ..] instead of $i | 
| 2843 | 5174 |  |  |  |  | 16210 | $rhash->{$tok} = | 
| 2844 |  |  |  |  |  |  | [ $i, undef, undef, $raw_tok, $lev, $tag, $tok_count ]; | 
| 2845 |  |  |  |  |  |  |  | 
| 2846 |  |  |  |  |  |  | # remember the first equals at line level | 
| 2847 | 5174 | 100 | 100 |  |  | 16470 | if ( !defined($i_eq) && $raw_tok eq '=' ) { | 
| 2848 |  |  |  |  |  |  |  | 
| 2849 | 520 | 100 |  |  |  | 1414 | if ( $lev eq $group_level ) { | 
| 2850 | 405 |  |  |  |  | 721 | $i_eq   = $i; | 
| 2851 | 405 |  |  |  |  | 717 | $tok_eq = $tok; | 
| 2852 | 405 |  |  |  |  | 838 | $pat_eq = $rpatterns->[$i]; | 
| 2853 |  |  |  |  |  |  | } | 
| 2854 |  |  |  |  |  |  | } | 
| 2855 | 5174 |  |  |  |  | 8993 | $i++; | 
| 2856 |  |  |  |  |  |  | } | 
| 2857 | 1898 |  |  |  |  | 3187 | push @{$rline_hashes}, $rhash; | 
|  | 1898 |  |  |  |  | 3717 |  | 
| 2858 | 1898 |  |  |  |  | 5743 | push @equals_info,     [ $i_eq,    $tok_eq, $pat_eq ]; | 
| 2859 | 1898 |  |  |  |  | 5638 | push @line_info,       [ $lev_min, $lev_max ]; | 
| 2860 | 1898 | 100 |  |  |  | 4099 | if ( defined($lev_min) ) { | 
| 2861 | 1779 |  |  |  |  | 3160 | my $lev_diff = $lev_max - $lev_min; | 
| 2862 | 1779 | 100 |  |  |  | 4885 | if ( $lev_diff > $max_lev_diff ) { $max_lev_diff = $lev_diff } | 
|  | 162 |  |  |  |  | 504 |  | 
| 2863 |  |  |  |  |  |  | } | 
| 2864 |  |  |  |  |  |  | } | 
| 2865 |  |  |  |  |  |  |  | 
| 2866 |  |  |  |  |  |  | #---------------------------------------------------- | 
| 2867 |  |  |  |  |  |  | # Loop to compare each line pair and remember matches | 
| 2868 |  |  |  |  |  |  | #---------------------------------------------------- | 
| 2869 | 583 |  |  |  |  | 1880 | my $rtok_hash = {}; | 
| 2870 | 583 |  |  |  |  | 1256 | my $nr        = 0; | 
| 2871 | 583 |  |  |  |  | 1980 | foreach my $jl ( 0 .. $jmax - 1 ) { | 
| 2872 | 1315 |  |  |  |  | 2151 | my $nl = $nr; | 
| 2873 | 1315 |  |  |  |  | 1972 | $nr = 0; | 
| 2874 | 1315 |  |  |  |  | 2207 | my $jr      = $jl + 1; | 
| 2875 | 1315 |  |  |  |  | 2193 | my $rhash_l = $rline_hashes->[$jl]; | 
| 2876 | 1315 |  |  |  |  | 2074 | my $rhash_r = $rline_hashes->[$jr]; | 
| 2877 | 1315 |  |  |  |  | 1985 | foreach my $tok ( keys %{$rhash_l} ) { | 
|  | 1315 |  |  |  |  | 4514 |  | 
| 2878 | 3154 | 100 |  |  |  | 6644 | if ( defined( $rhash_r->{$tok} ) ) { | 
| 2879 | 2670 |  |  |  |  | 4114 | my $il = $rhash_l->{$tok}->[0]; | 
| 2880 | 2670 |  |  |  |  | 4021 | my $ir = $rhash_r->{$tok}->[0]; | 
| 2881 | 2670 |  |  |  |  | 3966 | $rhash_l->{$tok}->[2] = $ir; | 
| 2882 | 2670 |  |  |  |  | 3796 | $rhash_r->{$tok}->[1] = $il; | 
| 2883 | 2670 | 100 |  |  |  | 5759 | if ( $tok ne '#' ) { | 
| 2884 | 1355 |  |  |  |  | 2016 | push @{ $rtok_hash->{$tok} }, ( $jl, $jr ); | 
|  | 1355 |  |  |  |  | 3879 |  | 
| 2885 | 1355 |  |  |  |  | 2693 | $nr++; | 
| 2886 |  |  |  |  |  |  | } | 
| 2887 |  |  |  |  |  |  | } | 
| 2888 |  |  |  |  |  |  | } | 
| 2889 |  |  |  |  |  |  |  | 
| 2890 |  |  |  |  |  |  | # Set a line break if no matching tokens between these lines | 
| 2891 |  |  |  |  |  |  | # (this is not strictly necessary now but does not hurt) | 
| 2892 | 1315 | 100 | 100 |  |  | 5168 | if ( $nr == 0 && $nl > 0 ) { | 
| 2893 | 36 |  |  |  |  | 213 | $rnew_lines->[$jl]->{'end_group'} = 1; | 
| 2894 |  |  |  |  |  |  | } | 
| 2895 |  |  |  |  |  |  |  | 
| 2896 |  |  |  |  |  |  | # Also set a line break if both lines have simple equals but with | 
| 2897 |  |  |  |  |  |  | # different leading characters in patterns.  This check is similar | 
| 2898 |  |  |  |  |  |  | # to one in sub check_match, and will prevent sub | 
| 2899 |  |  |  |  |  |  | # prune_alignment_tree from removing alignments which otherwise | 
| 2900 |  |  |  |  |  |  | # should be kept. This fix is rarely needed, but it can | 
| 2901 |  |  |  |  |  |  | # occasionally improve formatting. | 
| 2902 |  |  |  |  |  |  | # For example: | 
| 2903 |  |  |  |  |  |  | #     my $name = $this->{Name}; | 
| 2904 |  |  |  |  |  |  | #     $type = $this->ctype($genlooptype) if defined $genlooptype; | 
| 2905 |  |  |  |  |  |  | #     my $declini = ( $asgnonly ? ""          : "\t$type *" ); | 
| 2906 |  |  |  |  |  |  | #     my $cast    = ( $type     ? "($type *)" : "" ); | 
| 2907 |  |  |  |  |  |  | # The last two lines start with 'my' and will not match the | 
| 2908 |  |  |  |  |  |  | # previous line starting with $type, so we do not want | 
| 2909 |  |  |  |  |  |  | # prune_alignment tree to delete their ? : alignments at a deeper | 
| 2910 |  |  |  |  |  |  | # level. | 
| 2911 | 1315 |  |  |  |  | 2121 | my ( $i_eq_l, $tok_eq_l, $pat_eq_l ) = @{ $equals_info[$jl] }; | 
|  | 1315 |  |  |  |  | 3273 |  | 
| 2912 | 1315 |  |  |  |  | 2095 | my ( $i_eq_r, $tok_eq_r, $pat_eq_r ) = @{ $equals_info[$jr] }; | 
|  | 1315 |  |  |  |  | 2625 |  | 
| 2913 | 1315 | 100 | 100 |  |  | 4538 | if ( defined($i_eq_l) && defined($i_eq_r) ) { | 
| 2914 |  |  |  |  |  |  |  | 
| 2915 |  |  |  |  |  |  | # Also, do not align equals across a change in ci level | 
| 2916 |  |  |  |  |  |  | my $ci_jump = $rnew_lines->[$jl]->{'ci_level'} != | 
| 2917 | 199 |  |  |  |  | 596 | $rnew_lines->[$jr]->{'ci_level'}; | 
| 2918 |  |  |  |  |  |  |  | 
| 2919 | 199 | 100 | 66 |  |  | 2193 | if ( | 
|  |  |  | 66 |  |  |  |  | 
|  |  |  | 100 |  |  |  |  | 
|  |  |  | 100 |  |  |  |  | 
| 2920 |  |  |  |  |  |  | $tok_eq_l eq $tok_eq_r | 
| 2921 |  |  |  |  |  |  | && $i_eq_l == 0 | 
| 2922 |  |  |  |  |  |  | && $i_eq_r == 0 | 
| 2923 |  |  |  |  |  |  | && ( substr( $pat_eq_l, 0, 1 ) ne substr( $pat_eq_r, 0, 1 ) | 
| 2924 |  |  |  |  |  |  | || $ci_jump ) | 
| 2925 |  |  |  |  |  |  | ) | 
| 2926 |  |  |  |  |  |  | { | 
| 2927 | 12 |  |  |  |  | 47 | $rnew_lines->[$jl]->{'end_group'} = 1; | 
| 2928 |  |  |  |  |  |  | } | 
| 2929 |  |  |  |  |  |  | } | 
| 2930 |  |  |  |  |  |  | } | 
| 2931 | 583 |  |  |  |  | 4118 | return ( $rline_hashes, \@equals_info, $saw_side_comment, | 
| 2932 |  |  |  |  |  |  | $max_lev_diff ); | 
| 2933 |  |  |  |  |  |  | } ## end sub make_alignment_info | 
| 2934 |  |  |  |  |  |  |  | 
| 2935 |  |  |  |  |  |  | sub delete_unmatched_tokens_main_loop { | 
| 2936 |  |  |  |  |  |  |  | 
| 2937 |  |  |  |  |  |  | my ( | 
| 2938 | 583 |  |  | 583 | 0 | 1872 | $group_level,  $rnew_lines, $rsubgroups, | 
| 2939 |  |  |  |  |  |  | $rline_hashes, $requals_info | 
| 2940 |  |  |  |  |  |  | ) = @_; | 
| 2941 |  |  |  |  |  |  |  | 
| 2942 |  |  |  |  |  |  | #-------------------------------------------------------------- | 
| 2943 |  |  |  |  |  |  | # Main loop over subgroups to remove unmatched alignment tokens | 
| 2944 |  |  |  |  |  |  | #-------------------------------------------------------------- | 
| 2945 |  |  |  |  |  |  |  | 
| 2946 |  |  |  |  |  |  | # flag to allow skipping pass 2 - not currently used | 
| 2947 | 583 |  |  |  |  | 1093 | my $saw_large_group; | 
| 2948 |  |  |  |  |  |  |  | 
| 2949 | 583 |  |  |  |  | 1468 | my $has_terminal_match = $rnew_lines->[-1]->{'j_terminal_match'}; | 
| 2950 |  |  |  |  |  |  |  | 
| 2951 | 583 |  |  |  |  | 1102 | foreach my $item ( @{$rsubgroups} ) { | 
|  | 583 |  |  |  |  | 1531 |  | 
| 2952 | 655 |  |  |  |  | 1200 | my ( $jbeg, $jend ) = @{$item}; | 
|  | 655 |  |  |  |  | 1614 |  | 
| 2953 |  |  |  |  |  |  |  | 
| 2954 | 655 |  |  |  |  | 1510 | my $nlines = $jend - $jbeg + 1; | 
| 2955 |  |  |  |  |  |  |  | 
| 2956 |  |  |  |  |  |  | #--------------------------------------------------- | 
| 2957 |  |  |  |  |  |  | # Look for complete if/elsif/else and ternary blocks | 
| 2958 |  |  |  |  |  |  | #--------------------------------------------------- | 
| 2959 |  |  |  |  |  |  |  | 
| 2960 |  |  |  |  |  |  | # We are looking for a common '$dividing_token' like these: | 
| 2961 |  |  |  |  |  |  |  | 
| 2962 |  |  |  |  |  |  | #    if    ( $b and $s ) { $p->{'type'} = 'a'; } | 
| 2963 |  |  |  |  |  |  | #    elsif ($b)          { $p->{'type'} = 'b'; } | 
| 2964 |  |  |  |  |  |  | #    elsif ($s)          { $p->{'type'} = 's'; } | 
| 2965 |  |  |  |  |  |  | #    else                { $p->{'type'} = ''; } | 
| 2966 |  |  |  |  |  |  | #                        ^----------- dividing_token | 
| 2967 |  |  |  |  |  |  |  | 
| 2968 |  |  |  |  |  |  | #   my $severity = | 
| 2969 |  |  |  |  |  |  | #      !$routine                     ? '[PFX]' | 
| 2970 |  |  |  |  |  |  | #     : $routine =~ /warn.*_d\z/     ? '[DS]' | 
| 2971 |  |  |  |  |  |  | #     : $routine =~ /ck_warn/        ? 'W' | 
| 2972 |  |  |  |  |  |  | #     : $routine =~ /ckWARN\d*reg_d/ ? 'S' | 
| 2973 |  |  |  |  |  |  | #     : $routine =~ /ckWARN\d*reg/   ? 'W' | 
| 2974 |  |  |  |  |  |  | #     : $routine =~ /vWARN\d/        ? '[WDS]' | 
| 2975 |  |  |  |  |  |  | #     :                                '[PFX]'; | 
| 2976 |  |  |  |  |  |  | #                                    ^----------- dividing_token | 
| 2977 |  |  |  |  |  |  |  | 
| 2978 |  |  |  |  |  |  | # Only look for groups which are more than 2 lines long.  Two lines | 
| 2979 |  |  |  |  |  |  | # can get messed up doing this, probably due to the various | 
| 2980 |  |  |  |  |  |  | # two-line rules. | 
| 2981 |  |  |  |  |  |  |  | 
| 2982 | 655 |  |  |  |  | 1413 | my $dividing_token; | 
| 2983 |  |  |  |  |  |  | my %token_line_count; | 
| 2984 | 655 | 100 |  |  |  | 2080 | if ( $nlines > 2 ) { | 
| 2985 |  |  |  |  |  |  |  | 
| 2986 | 301 |  |  |  |  | 968 | foreach my $jj ( $jbeg .. $jend ) { | 
| 2987 | 1281 |  |  |  |  | 1843 | my %seen; | 
| 2988 | 1281 |  |  |  |  | 2027 | my $line    = $rnew_lines->[$jj]; | 
| 2989 | 1281 |  |  |  |  | 2023 | my $rtokens = $line->{'rtokens'}; | 
| 2990 | 1281 |  |  |  |  | 1715 | foreach my $tok ( @{$rtokens} ) { | 
|  | 1281 |  |  |  |  | 2278 |  | 
| 2991 | 3581 | 100 |  |  |  | 6636 | if ( !$seen{$tok} ) { | 
| 2992 | 3065 |  |  |  |  | 4630 | $seen{$tok}++; | 
| 2993 | 3065 |  |  |  |  | 6020 | $token_line_count{$tok}++; | 
| 2994 |  |  |  |  |  |  | } | 
| 2995 |  |  |  |  |  |  | } | 
| 2996 |  |  |  |  |  |  | } | 
| 2997 |  |  |  |  |  |  |  | 
| 2998 | 301 |  |  |  |  | 1697 | foreach my $tok ( keys %token_line_count ) { | 
| 2999 | 927 | 100 |  |  |  | 2541 | if ( $token_line_count{$tok} == $nlines ) { | 
| 3000 | 562 | 100 | 100 |  |  | 3246 | if (   substr( $tok, 0, 1 ) eq '?' | 
|  |  |  | 100 |  |  |  |  | 
| 3001 |  |  |  |  |  |  | || substr( $tok, 0, 1 ) eq '{' | 
| 3002 |  |  |  |  |  |  | && $tok =~ /^\{\d+if/ ) | 
| 3003 |  |  |  |  |  |  | { | 
| 3004 | 21 |  |  |  |  | 59 | $dividing_token = $tok; | 
| 3005 | 21 |  |  |  |  | 54 | last; | 
| 3006 |  |  |  |  |  |  | } | 
| 3007 |  |  |  |  |  |  | } | 
| 3008 |  |  |  |  |  |  | } | 
| 3009 |  |  |  |  |  |  | } | 
| 3010 |  |  |  |  |  |  |  | 
| 3011 |  |  |  |  |  |  | #------------------------------------------------------------- | 
| 3012 |  |  |  |  |  |  | # Loop over subgroup lines to remove unwanted alignment tokens | 
| 3013 |  |  |  |  |  |  | #------------------------------------------------------------- | 
| 3014 | 655 |  |  |  |  | 2397 | foreach my $jj ( $jbeg .. $jend ) { | 
| 3015 | 1898 |  |  |  |  | 3361 | my $line    = $rnew_lines->[$jj]; | 
| 3016 | 1898 |  |  |  |  | 3094 | my $rtokens = $line->{'rtokens'}; | 
| 3017 | 1898 |  |  |  |  | 2936 | my $rhash   = $rline_hashes->[$jj]; | 
| 3018 | 1898 |  |  |  |  | 2985 | my $i_eq    = $requals_info->[$jj]->[0]; | 
| 3019 | 1898 |  |  |  |  | 2848 | my @idel; | 
| 3020 | 1898 |  |  |  |  | 2748 | my $imax = @{$rtokens} - 2; | 
|  | 1898 |  |  |  |  | 3392 |  | 
| 3021 | 1898 |  |  |  |  | 2918 | my $delete_above_level; | 
| 3022 |  |  |  |  |  |  | my $deleted_assignment_token; | 
| 3023 |  |  |  |  |  |  |  | 
| 3024 | 1898 |  |  |  |  | 2951 | my $saw_dividing_token = EMPTY_STRING; | 
| 3025 | 1898 |  | 100 |  |  | 8551 | $saw_large_group ||= $nlines > 2 && $imax > 1; | 
|  |  |  | 100 |  |  |  |  | 
| 3026 |  |  |  |  |  |  |  | 
| 3027 |  |  |  |  |  |  | # Loop over all alignment tokens | 
| 3028 | 1898 |  |  |  |  | 3766 | foreach my $i ( 0 .. $imax ) { | 
| 3029 | 3276 |  |  |  |  | 5223 | my $tok = $rtokens->[$i]; | 
| 3030 | 3276 | 50 |  |  |  | 6463 | next if ( $tok eq '#' );    # shouldn't happen | 
| 3031 |  |  |  |  |  |  | my ( $iii, $il, $ir, $raw_tok, $lev, $tag, $tok_count ) = | 
| 3032 | 3276 |  |  |  |  | 4618 | @{ $rhash->{$tok} }; | 
|  | 3276 |  |  |  |  | 8108 |  | 
| 3033 |  |  |  |  |  |  |  | 
| 3034 |  |  |  |  |  |  | #------------------------------------------------------ | 
| 3035 |  |  |  |  |  |  | # Here is the basic RULE: remove an unmatched alignment | 
| 3036 |  |  |  |  |  |  | # which does not occur in the surrounding lines. | 
| 3037 |  |  |  |  |  |  | #------------------------------------------------------ | 
| 3038 | 3276 |  | 100 |  |  | 8840 | my $delete_me = !defined($il) && !defined($ir); | 
| 3039 |  |  |  |  |  |  |  | 
| 3040 |  |  |  |  |  |  | # Apply any user controls. Note that not all lines pass | 
| 3041 |  |  |  |  |  |  | # this way so they have to be applied elsewhere too. | 
| 3042 | 3276 |  |  |  |  | 4613 | my $align_ok = 1; | 
| 3043 | 3276 | 100 |  |  |  | 6169 | if (%valign_control_hash) { | 
| 3044 | 31 |  |  |  |  | 78 | $align_ok = $valign_control_hash{$raw_tok}; | 
| 3045 | 31 | 100 |  |  |  | 77 | $align_ok = $valign_control_default | 
| 3046 |  |  |  |  |  |  | unless defined($align_ok); | 
| 3047 | 31 |  | 100 |  |  | 96 | $delete_me ||= !$align_ok; | 
| 3048 |  |  |  |  |  |  | } | 
| 3049 |  |  |  |  |  |  |  | 
| 3050 |  |  |  |  |  |  | # But now we modify this with exceptions... | 
| 3051 |  |  |  |  |  |  |  | 
| 3052 |  |  |  |  |  |  | # EXCEPTION 1: If we are in a complete ternary or | 
| 3053 |  |  |  |  |  |  | # if/elsif/else group, and this token is not on every line | 
| 3054 |  |  |  |  |  |  | # of the group, should we delete it to preserve overall | 
| 3055 |  |  |  |  |  |  | # alignment? | 
| 3056 | 3276 | 100 |  |  |  | 6453 | if ($dividing_token) { | 
| 3057 | 147 | 100 |  |  |  | 314 | if ( $token_line_count{$tok} >= $nlines ) { | 
| 3058 | 120 |  | 100 |  |  | 413 | $saw_dividing_token ||= $tok eq $dividing_token; | 
| 3059 |  |  |  |  |  |  | } | 
| 3060 |  |  |  |  |  |  | else { | 
| 3061 |  |  |  |  |  |  |  | 
| 3062 |  |  |  |  |  |  | # For shorter runs, delete toks to save alignment. | 
| 3063 |  |  |  |  |  |  | # For longer runs, keep toks after the '{' or '?' | 
| 3064 |  |  |  |  |  |  | # to allow sub-alignments within braces.  The | 
| 3065 |  |  |  |  |  |  | # number 5 lines is arbitrary but seems to work ok. | 
| 3066 | 27 |  | 66 |  |  | 109 | $delete_me ||= | 
|  |  |  | 100 |  |  |  |  | 
| 3067 |  |  |  |  |  |  | ( $nlines < 5 || !$saw_dividing_token ); | 
| 3068 |  |  |  |  |  |  | } | 
| 3069 |  |  |  |  |  |  | } | 
| 3070 |  |  |  |  |  |  |  | 
| 3071 |  |  |  |  |  |  | # EXCEPTION 2: Remove all tokens above a certain level | 
| 3072 |  |  |  |  |  |  | # following a previous deletion.  For example, we have to | 
| 3073 |  |  |  |  |  |  | # remove tagged higher level alignment tokens following a | 
| 3074 |  |  |  |  |  |  | # '=>' deletion because the tags of higher level tokens | 
| 3075 |  |  |  |  |  |  | # will now be incorrect. For example, this will prevent | 
| 3076 |  |  |  |  |  |  | # aligning commas as follows after deleting the second '=>' | 
| 3077 |  |  |  |  |  |  | #    $w->insert( | 
| 3078 |  |  |  |  |  |  | #         ListBox => origin => [ 270, 160 ], | 
| 3079 |  |  |  |  |  |  | #         size    => [ 200,           55 ], | 
| 3080 |  |  |  |  |  |  | #    ); | 
| 3081 | 3276 | 100 |  |  |  | 6012 | if ( defined($delete_above_level) ) { | 
| 3082 | 280 | 100 |  |  |  | 1068 | if ( $lev > $delete_above_level ) { | 
| 3083 | 132 |  | 100 |  |  | 424 | $delete_me ||= 1; | 
| 3084 |  |  |  |  |  |  | } | 
| 3085 | 148 |  |  |  |  | 386 | else { $delete_above_level = undef } | 
| 3086 |  |  |  |  |  |  | } | 
| 3087 |  |  |  |  |  |  |  | 
| 3088 |  |  |  |  |  |  | # EXCEPTION 3: Remove all but certain tokens after an | 
| 3089 |  |  |  |  |  |  | # assignment deletion. | 
| 3090 | 3276 | 100 | 100 |  |  | 6045 | if ( | 
|  |  |  | 100 |  |  |  |  | 
| 3091 |  |  |  |  |  |  | $deleted_assignment_token | 
| 3092 |  |  |  |  |  |  | && ( $lev > $group_level | 
| 3093 |  |  |  |  |  |  | || !$keep_after_deleted_assignment{$raw_tok} ) | 
| 3094 |  |  |  |  |  |  | ) | 
| 3095 |  |  |  |  |  |  | { | 
| 3096 | 41 |  | 100 |  |  | 137 | $delete_me ||= 1; | 
| 3097 |  |  |  |  |  |  | } | 
| 3098 |  |  |  |  |  |  |  | 
| 3099 |  |  |  |  |  |  | # EXCEPTION 4: Do not touch the first line of a 2 line | 
| 3100 |  |  |  |  |  |  | # terminal match, such as below, because j_terminal has | 
| 3101 |  |  |  |  |  |  | # already been set. | 
| 3102 |  |  |  |  |  |  | #    if ($tag) { $tago = "<$tag>"; $tagc = "</$tag>"; } | 
| 3103 |  |  |  |  |  |  | #    else      { $tago = $tagc = ''; } | 
| 3104 |  |  |  |  |  |  | # But see snippets 'else1.t' and 'else2.t' | 
| 3105 | 3276 | 100 | 100 |  |  | 8475 | $delete_me = 0 | 
|  |  |  | 100 |  |  |  |  | 
| 3106 |  |  |  |  |  |  | if ( $jj == $jbeg | 
| 3107 |  |  |  |  |  |  | && $has_terminal_match | 
| 3108 |  |  |  |  |  |  | && $nlines == 2 ); | 
| 3109 |  |  |  |  |  |  |  | 
| 3110 |  |  |  |  |  |  | # EXCEPTION 5: misc additional rules for commas and equals | 
| 3111 | 3276 | 100 | 100 |  |  | 7963 | if ( $delete_me && $tok_count == 1 ) { | 
| 3112 |  |  |  |  |  |  |  | 
| 3113 |  |  |  |  |  |  | # okay to delete second and higher copies of a token | 
| 3114 |  |  |  |  |  |  |  | 
| 3115 |  |  |  |  |  |  | # for a comma... | 
| 3116 | 721 | 100 |  |  |  | 2000 | if ( $raw_tok eq ',' ) { | 
| 3117 |  |  |  |  |  |  |  | 
| 3118 |  |  |  |  |  |  | # Do not delete commas before an equals | 
| 3119 | 262 | 100 | 100 |  |  | 979 | $delete_me = 0 | 
| 3120 |  |  |  |  |  |  | if ( defined($i_eq) && $i < $i_eq ); | 
| 3121 |  |  |  |  |  |  |  | 
| 3122 |  |  |  |  |  |  | # Do not delete line-level commas | 
| 3123 | 262 | 100 |  |  |  | 733 | $delete_me = 0 if ( $lev <= $group_level ); | 
| 3124 |  |  |  |  |  |  | } | 
| 3125 |  |  |  |  |  |  |  | 
| 3126 |  |  |  |  |  |  | # For an assignment at group level.. | 
| 3127 | 721 | 100 | 100 |  |  | 2803 | if (   $is_assignment{$raw_tok} | 
| 3128 |  |  |  |  |  |  | && $lev == $group_level ) | 
| 3129 |  |  |  |  |  |  | { | 
| 3130 |  |  |  |  |  |  |  | 
| 3131 |  |  |  |  |  |  | # Do not delete if it is the last alignment of | 
| 3132 |  |  |  |  |  |  | # multiple tokens; this will prevent some | 
| 3133 |  |  |  |  |  |  | # undesirable alignments | 
| 3134 | 106 | 100 | 100 |  |  | 604 | if ( $imax > 0 && $i == $imax ) { | 
| 3135 | 12 |  |  |  |  | 31 | $delete_me = 0; | 
| 3136 |  |  |  |  |  |  | } | 
| 3137 |  |  |  |  |  |  |  | 
| 3138 |  |  |  |  |  |  | # Otherwise, set a flag to delete most | 
| 3139 |  |  |  |  |  |  | # remaining tokens | 
| 3140 | 94 |  |  |  |  | 220 | else { $deleted_assignment_token = $raw_tok } | 
| 3141 |  |  |  |  |  |  | } | 
| 3142 |  |  |  |  |  |  | } | 
| 3143 |  |  |  |  |  |  |  | 
| 3144 |  |  |  |  |  |  | # Do not let a user exclusion be reactivated by above rules | 
| 3145 | 3276 |  | 66 |  |  | 10185 | $delete_me ||= !$align_ok; | 
| 3146 |  |  |  |  |  |  |  | 
| 3147 |  |  |  |  |  |  | #------------------------------------ | 
| 3148 |  |  |  |  |  |  | # Add this token to the deletion list | 
| 3149 |  |  |  |  |  |  | #------------------------------------ | 
| 3150 | 3276 | 100 |  |  |  | 6961 | if ($delete_me) { | 
| 3151 | 661 |  |  |  |  | 1211 | push @idel, $i; | 
| 3152 |  |  |  |  |  |  |  | 
| 3153 |  |  |  |  |  |  | # update deletion propagation flags | 
| 3154 | 661 | 100 | 66 |  |  | 2097 | if ( !defined($delete_above_level) | 
| 3155 |  |  |  |  |  |  | || $lev < $delete_above_level ) | 
| 3156 |  |  |  |  |  |  | { | 
| 3157 |  |  |  |  |  |  |  | 
| 3158 |  |  |  |  |  |  | # delete all following higher level alignments | 
| 3159 | 529 |  |  |  |  | 915 | $delete_above_level = $lev; | 
| 3160 |  |  |  |  |  |  |  | 
| 3161 |  |  |  |  |  |  | # but keep deleting after => to next lower level | 
| 3162 |  |  |  |  |  |  | # to avoid some bizarre alignments | 
| 3163 | 529 | 100 |  |  |  | 1648 | if ( $raw_tok eq '=>' ) { | 
| 3164 | 53 |  |  |  |  | 151 | $delete_above_level = $lev - 1; | 
| 3165 |  |  |  |  |  |  | } | 
| 3166 |  |  |  |  |  |  | } | 
| 3167 |  |  |  |  |  |  | } | 
| 3168 |  |  |  |  |  |  | }    # End loop over alignment tokens | 
| 3169 |  |  |  |  |  |  |  | 
| 3170 |  |  |  |  |  |  | # Process all deletion requests for this line | 
| 3171 | 1898 | 100 |  |  |  | 5910 | if (@idel) { | 
| 3172 | 413 |  |  |  |  | 1736 | delete_selected_tokens( $line, \@idel ); | 
| 3173 |  |  |  |  |  |  | } | 
| 3174 |  |  |  |  |  |  | }    # End loop over lines | 
| 3175 |  |  |  |  |  |  | } ## end main loop over subgroups | 
| 3176 |  |  |  |  |  |  |  | 
| 3177 | 583 |  |  |  |  | 1692 | return; | 
| 3178 |  |  |  |  |  |  | } ## end sub delete_unmatched_tokens_main_loop | 
| 3179 |  |  |  |  |  |  | } | 
| 3180 |  |  |  |  |  |  |  | 
| 3181 |  |  |  |  |  |  | sub match_line_pairs { | 
| 3182 | 583 |  |  | 583 | 0 | 1866 | my ( $rlines, $rnew_lines, $rsubgroups, $group_level ) = @_; | 
| 3183 |  |  |  |  |  |  |  | 
| 3184 |  |  |  |  |  |  | # Compare each pair of lines and save information about common matches | 
| 3185 |  |  |  |  |  |  | # $rlines     = list of lines including hanging side comments | 
| 3186 |  |  |  |  |  |  | # $rnew_lines = list of lines without any hanging side comments | 
| 3187 |  |  |  |  |  |  | # $rsubgroups = list of subgroups of the new lines | 
| 3188 |  |  |  |  |  |  |  | 
| 3189 |  |  |  |  |  |  | # TODO: | 
| 3190 |  |  |  |  |  |  | # Maybe change: imax_pair => pair_match_info = ref to array | 
| 3191 |  |  |  |  |  |  | #  = [$imax_align, $rMsg, ... ] | 
| 3192 |  |  |  |  |  |  | #  This may eventually have multi-level match info | 
| 3193 |  |  |  |  |  |  |  | 
| 3194 |  |  |  |  |  |  | # Previous line vars | 
| 3195 | 583 |  |  |  |  | 2318 | my ( $line_m, $rtokens_m, $rpatterns_m, $rfield_lengths_m, $imax_m, | 
| 3196 |  |  |  |  |  |  | $list_type_m, $ci_level_m ); | 
| 3197 |  |  |  |  |  |  |  | 
| 3198 |  |  |  |  |  |  | # Current line vars | 
| 3199 | 583 |  |  |  |  | 0 | my ( $line, $rtokens, $rpatterns, $rfield_lengths, $imax, $list_type, | 
| 3200 |  |  |  |  |  |  | $ci_level ); | 
| 3201 |  |  |  |  |  |  |  | 
| 3202 |  |  |  |  |  |  | # loop over subgroups | 
| 3203 | 583 |  |  |  |  | 1076 | foreach my $item ( @{$rsubgroups} ) { | 
|  | 583 |  |  |  |  | 1400 |  | 
| 3204 | 655 |  |  |  |  | 1150 | my ( $jbeg, $jend ) = @{$item}; | 
|  | 655 |  |  |  |  | 1501 |  | 
| 3205 | 655 |  |  |  |  | 1589 | my $nlines = $jend - $jbeg + 1; | 
| 3206 | 655 | 100 |  |  |  | 1926 | next if ( $nlines <= 1 ); | 
| 3207 |  |  |  |  |  |  |  | 
| 3208 |  |  |  |  |  |  | # loop over lines in a subgroup | 
| 3209 | 564 |  |  |  |  | 1565 | foreach my $jj ( $jbeg .. $jend ) { | 
| 3210 |  |  |  |  |  |  |  | 
| 3211 | 1807 |  |  |  |  | 2663 | $line_m           = $line; | 
| 3212 | 1807 |  |  |  |  | 3537 | $rtokens_m        = $rtokens; | 
| 3213 | 1807 |  |  |  |  | 2989 | $rpatterns_m      = $rpatterns; | 
| 3214 | 1807 |  |  |  |  | 2518 | $rfield_lengths_m = $rfield_lengths; | 
| 3215 | 1807 |  |  |  |  | 2394 | $imax_m           = $imax; | 
| 3216 | 1807 |  |  |  |  | 2691 | $list_type_m      = $list_type; | 
| 3217 | 1807 |  |  |  |  | 2610 | $ci_level_m       = $ci_level; | 
| 3218 |  |  |  |  |  |  |  | 
| 3219 | 1807 |  |  |  |  | 2993 | $line           = $rnew_lines->[$jj]; | 
| 3220 | 1807 |  |  |  |  | 2975 | $rtokens        = $line->{'rtokens'}; | 
| 3221 | 1807 |  |  |  |  | 2915 | $rpatterns      = $line->{'rpatterns'}; | 
| 3222 | 1807 |  |  |  |  | 2742 | $rfield_lengths = $line->{'rfield_lengths'}; | 
| 3223 | 1807 |  |  |  |  | 2527 | $imax           = @{$rtokens} - 2; | 
|  | 1807 |  |  |  |  | 2796 |  | 
| 3224 | 1807 |  |  |  |  | 3098 | $list_type      = $line->{'list_type'}; | 
| 3225 | 1807 |  |  |  |  | 2843 | $ci_level       = $line->{'ci_level'}; | 
| 3226 |  |  |  |  |  |  |  | 
| 3227 |  |  |  |  |  |  | # nothing to do for first line | 
| 3228 | 1807 | 100 |  |  |  | 4393 | next if ( $jj == $jbeg ); | 
| 3229 |  |  |  |  |  |  |  | 
| 3230 | 1243 |  |  |  |  | 2848 | my $ci_jump = $ci_level - $ci_level_m; | 
| 3231 |  |  |  |  |  |  |  | 
| 3232 | 1243 | 100 |  |  |  | 3117 | my $imax_min = $imax_m < $imax ? $imax_m : $imax; | 
| 3233 |  |  |  |  |  |  |  | 
| 3234 | 1243 |  |  |  |  | 2005 | my $imax_align = -1; | 
| 3235 |  |  |  |  |  |  |  | 
| 3236 |  |  |  |  |  |  | # find number of leading common tokens | 
| 3237 |  |  |  |  |  |  |  | 
| 3238 |  |  |  |  |  |  | #--------------------------------- | 
| 3239 |  |  |  |  |  |  | # No match to hanging side comment | 
| 3240 |  |  |  |  |  |  | #--------------------------------- | 
| 3241 | 1243 | 50 | 100 |  |  | 4722 | if ( $line->{'is_hanging_side_comment'} ) { | 
|  |  | 100 |  |  |  |  |  | 
| 3242 |  |  |  |  |  |  |  | 
| 3243 |  |  |  |  |  |  | # Should not get here; HSC's have been filtered out | 
| 3244 | 0 |  |  |  |  | 0 | $imax_align = -1; | 
| 3245 |  |  |  |  |  |  | } | 
| 3246 |  |  |  |  |  |  |  | 
| 3247 |  |  |  |  |  |  | #----------------------------- | 
| 3248 |  |  |  |  |  |  | # Handle comma-separated lists | 
| 3249 |  |  |  |  |  |  | #----------------------------- | 
| 3250 |  |  |  |  |  |  | elsif ( $list_type && $list_type eq $list_type_m ) { | 
| 3251 |  |  |  |  |  |  |  | 
| 3252 |  |  |  |  |  |  | # do not align lists across a ci jump with new list method | 
| 3253 | 488 | 50 |  |  |  | 1136 | if ($ci_jump) { $imax_min = -1 } | 
|  | 0 |  |  |  |  | 0 |  | 
| 3254 |  |  |  |  |  |  |  | 
| 3255 | 488 |  |  |  |  | 861 | my $i_nomatch = $imax_min + 1; | 
| 3256 | 488 |  |  |  |  | 1014 | foreach my $i ( 0 .. $imax_min ) { | 
| 3257 | 883 |  |  |  |  | 1507 | my $tok   = $rtokens->[$i]; | 
| 3258 | 883 |  |  |  |  | 1384 | my $tok_m = $rtokens_m->[$i]; | 
| 3259 | 883 | 50 |  |  |  | 2062 | if ( $tok ne $tok_m ) { | 
| 3260 | 0 |  |  |  |  | 0 | $i_nomatch = $i; | 
| 3261 | 0 |  |  |  |  | 0 | last; | 
| 3262 |  |  |  |  |  |  | } | 
| 3263 |  |  |  |  |  |  | } | 
| 3264 |  |  |  |  |  |  |  | 
| 3265 | 488 |  |  |  |  | 893 | $imax_align = $i_nomatch - 1; | 
| 3266 |  |  |  |  |  |  | } | 
| 3267 |  |  |  |  |  |  |  | 
| 3268 |  |  |  |  |  |  | #----------------- | 
| 3269 |  |  |  |  |  |  | # Handle non-lists | 
| 3270 |  |  |  |  |  |  | #----------------- | 
| 3271 |  |  |  |  |  |  | else { | 
| 3272 | 755 |  |  |  |  | 1444 | my $i_nomatch = $imax_min + 1; | 
| 3273 | 755 |  |  |  |  | 1553 | foreach my $i ( 0 .. $imax_min ) { | 
| 3274 | 745 |  |  |  |  | 1392 | my $tok   = $rtokens->[$i]; | 
| 3275 | 745 |  |  |  |  | 1263 | my $tok_m = $rtokens_m->[$i]; | 
| 3276 | 745 | 100 |  |  |  | 1669 | if ( $tok ne $tok_m ) { | 
| 3277 | 19 |  |  |  |  | 54 | $i_nomatch = $i; | 
| 3278 | 19 |  |  |  |  | 53 | last; | 
| 3279 |  |  |  |  |  |  | } | 
| 3280 |  |  |  |  |  |  |  | 
| 3281 | 726 |  |  |  |  | 1294 | my $pat   = $rpatterns->[$i]; | 
| 3282 | 726 |  |  |  |  | 1183 | my $pat_m = $rpatterns_m->[$i]; | 
| 3283 |  |  |  |  |  |  |  | 
| 3284 |  |  |  |  |  |  | # If patterns don't match, we have to be careful... | 
| 3285 | 726 | 100 |  |  |  | 1779 | if ( $pat_m ne $pat ) { | 
| 3286 | 166 |  |  |  |  | 431 | my $pad = | 
| 3287 |  |  |  |  |  |  | $rfield_lengths->[$i] - $rfield_lengths_m->[$i]; | 
| 3288 | 166 |  |  |  |  | 506 | my ( $match_code, $rmsg ) = | 
| 3289 |  |  |  |  |  |  | compare_patterns( $group_level, | 
| 3290 |  |  |  |  |  |  | $tok, $tok_m, $pat, $pat_m, $pad ); | 
| 3291 | 166 | 100 |  |  |  | 563 | if ($match_code) { | 
| 3292 | 8 | 100 |  |  |  | 37 | if    ( $match_code == 1 ) { $i_nomatch = $i } | 
|  | 7 | 50 |  |  |  | 17 |  | 
| 3293 | 1 |  |  |  |  | 2 | elsif ( $match_code == 2 ) { $i_nomatch = 0 } | 
| 3294 |  |  |  |  |  |  | else                       { }                  ##ok | 
| 3295 | 8 |  |  |  |  | 21 | last; | 
| 3296 |  |  |  |  |  |  | } | 
| 3297 |  |  |  |  |  |  | } | 
| 3298 |  |  |  |  |  |  | } | 
| 3299 | 755 |  |  |  |  | 1279 | $imax_align = $i_nomatch - 1; | 
| 3300 |  |  |  |  |  |  | } | 
| 3301 |  |  |  |  |  |  |  | 
| 3302 | 1243 |  |  |  |  | 2705 | $line_m->{'imax_pair'} = $imax_align; | 
| 3303 |  |  |  |  |  |  |  | 
| 3304 |  |  |  |  |  |  | } ## end loop over lines | 
| 3305 |  |  |  |  |  |  |  | 
| 3306 |  |  |  |  |  |  | # Put fence at end of subgroup | 
| 3307 | 564 |  |  |  |  | 1868 | $line->{'imax_pair'} = -1; | 
| 3308 |  |  |  |  |  |  |  | 
| 3309 |  |  |  |  |  |  | } ## end loop over subgroups | 
| 3310 |  |  |  |  |  |  |  | 
| 3311 |  |  |  |  |  |  | # if there are hanging side comments, propagate the pair info down to them | 
| 3312 |  |  |  |  |  |  | # so that lines can just look back one line for their pair info. | 
| 3313 | 583 | 100 |  |  |  | 1069 | if ( @{$rlines} > @{$rnew_lines} ) { | 
|  | 583 |  |  |  |  | 1132 |  | 
|  | 583 |  |  |  |  | 1869 |  | 
| 3314 | 24 |  |  |  |  | 59 | my $last_pair_info = -1; | 
| 3315 | 24 |  |  |  |  | 54 | foreach my $line ( @{$rlines} ) { | 
|  | 24 |  |  |  |  | 77 |  | 
| 3316 | 95 | 100 |  |  |  | 217 | if ( $line->{'is_hanging_side_comment'} ) { | 
| 3317 | 39 |  |  |  |  | 91 | $line->{'imax_pair'} = $last_pair_info; | 
| 3318 |  |  |  |  |  |  | } | 
| 3319 |  |  |  |  |  |  | else { | 
| 3320 | 56 |  |  |  |  | 113 | $last_pair_info = $line->{'imax_pair'}; | 
| 3321 |  |  |  |  |  |  | } | 
| 3322 |  |  |  |  |  |  | } | 
| 3323 |  |  |  |  |  |  | } | 
| 3324 | 583 |  |  |  |  | 1534 | return; | 
| 3325 |  |  |  |  |  |  | } ## end sub match_line_pairs | 
| 3326 |  |  |  |  |  |  |  | 
| 3327 |  |  |  |  |  |  | sub compare_patterns { | 
| 3328 |  |  |  |  |  |  |  | 
| 3329 | 166 |  |  | 166 | 0 | 516 | my ( $group_level, $tok, $tok_m, $pat, $pat_m, $pad ) = @_; | 
| 3330 |  |  |  |  |  |  |  | 
| 3331 |  |  |  |  |  |  | # helper routine for sub match_line_pairs to decide if patterns in two | 
| 3332 |  |  |  |  |  |  | # lines match well enough..Given | 
| 3333 |  |  |  |  |  |  | #   $tok_m, $pat_m = token and pattern of first line | 
| 3334 |  |  |  |  |  |  | #   $tok, $pat     = token and pattern of second line | 
| 3335 |  |  |  |  |  |  | #   $pad           = 0 if no padding is needed, !=0 otherwise | 
| 3336 |  |  |  |  |  |  | # return code: | 
| 3337 |  |  |  |  |  |  | #   0 = patterns match, continue | 
| 3338 |  |  |  |  |  |  | #   1 = no match | 
| 3339 |  |  |  |  |  |  | #   2 = no match, and lines do not match at all | 
| 3340 |  |  |  |  |  |  |  | 
| 3341 | 166 |  |  |  |  | 311 | my $GoToMsg     = EMPTY_STRING; | 
| 3342 | 166 |  |  |  |  | 253 | my $return_code = 0; | 
| 3343 |  |  |  |  |  |  |  | 
| 3344 | 39 |  |  | 39 |  | 409 | use constant EXPLAIN_COMPARE_PATTERNS => 0; | 
|  | 39 |  |  |  |  | 102 |  | 
|  | 39 |  |  |  |  | 50633 |  | 
| 3345 |  |  |  |  |  |  |  | 
| 3346 | 166 |  |  |  |  | 606 | my ( $alignment_token, $lev, $tag, $tok_count ) = | 
| 3347 |  |  |  |  |  |  | decode_alignment_token($tok); | 
| 3348 |  |  |  |  |  |  |  | 
| 3349 |  |  |  |  |  |  | # We have to be very careful about aligning commas | 
| 3350 |  |  |  |  |  |  | # when the pattern's don't match, because it can be | 
| 3351 |  |  |  |  |  |  | # worse to create an alignment where none is needed | 
| 3352 |  |  |  |  |  |  | # than to omit one.  Here's an example where the ','s | 
| 3353 |  |  |  |  |  |  | # are not in named containers.  The first line below | 
| 3354 |  |  |  |  |  |  | # should not match the next two: | 
| 3355 |  |  |  |  |  |  | #   ( $a, $b ) = ( $b, $r ); | 
| 3356 |  |  |  |  |  |  | #   ( $x1, $x2 ) = ( $x2 - $q * $x1, $x1 ); | 
| 3357 |  |  |  |  |  |  | #   ( $y1, $y2 ) = ( $y2 - $q * $y1, $y1 ); | 
| 3358 | 166 | 100 |  |  |  | 839 | if ( $alignment_token eq ',' ) { | 
|  |  | 100 |  |  |  |  |  | 
|  |  | 100 |  |  |  |  |  | 
| 3359 |  |  |  |  |  |  |  | 
| 3360 |  |  |  |  |  |  | # do not align commas unless they are in named | 
| 3361 |  |  |  |  |  |  | # containers | 
| 3362 | 26 | 100 |  |  |  | 140 | if ( $tok !~ /[A-Za-z]/ ) { | 
| 3363 | 3 |  |  |  |  | 5 | $return_code = 1; | 
| 3364 | 3 |  |  |  |  | 8 | $GoToMsg     = "do not align commas in unnamed containers"; | 
| 3365 |  |  |  |  |  |  | } | 
| 3366 |  |  |  |  |  |  | else { | 
| 3367 | 23 |  |  |  |  | 44 | $return_code = 0; | 
| 3368 |  |  |  |  |  |  | } | 
| 3369 |  |  |  |  |  |  | } | 
| 3370 |  |  |  |  |  |  |  | 
| 3371 |  |  |  |  |  |  | # do not align parens unless patterns match; | 
| 3372 |  |  |  |  |  |  | # large ugly spaces can occur in math expressions. | 
| 3373 |  |  |  |  |  |  | elsif ( $alignment_token eq '(' ) { | 
| 3374 |  |  |  |  |  |  |  | 
| 3375 |  |  |  |  |  |  | # But we can allow a match if the parens don't | 
| 3376 |  |  |  |  |  |  | # require any padding. | 
| 3377 | 4 | 50 |  |  |  | 17 | if ( $pad != 0 ) { | 
| 3378 | 4 |  |  |  |  | 10 | $return_code = 1; | 
| 3379 | 4 |  |  |  |  | 10 | $GoToMsg     = "do not align '(' unless patterns match or pad=0"; | 
| 3380 |  |  |  |  |  |  | } | 
| 3381 |  |  |  |  |  |  | else { | 
| 3382 | 0 |  |  |  |  | 0 | $return_code = 0; | 
| 3383 |  |  |  |  |  |  | } | 
| 3384 |  |  |  |  |  |  | } | 
| 3385 |  |  |  |  |  |  |  | 
| 3386 |  |  |  |  |  |  | # Handle an '=' alignment with different patterns to | 
| 3387 |  |  |  |  |  |  | # the left. | 
| 3388 |  |  |  |  |  |  | elsif ( $alignment_token eq '=' ) { | 
| 3389 |  |  |  |  |  |  |  | 
| 3390 |  |  |  |  |  |  | # It is best to be a little restrictive when | 
| 3391 |  |  |  |  |  |  | # aligning '=' tokens.  Here is an example of | 
| 3392 |  |  |  |  |  |  | # two lines that we will not align: | 
| 3393 |  |  |  |  |  |  | #       my $variable=6; | 
| 3394 |  |  |  |  |  |  | #       $bb=4; | 
| 3395 |  |  |  |  |  |  | # The problem is that one is a 'my' declaration, | 
| 3396 |  |  |  |  |  |  | # and the other isn't, so they're not very similar. | 
| 3397 |  |  |  |  |  |  | # We will filter these out by comparing the first | 
| 3398 |  |  |  |  |  |  | # letter of the pattern.  This is crude, but works | 
| 3399 |  |  |  |  |  |  | # well enough. | 
| 3400 | 16 | 50 |  |  |  | 141 | if ( substr( $pat_m, 0, 1 ) ne substr( $pat, 0, 1 ) ) { | 
|  |  | 100 |  |  |  |  |  | 
| 3401 | 0 |  |  |  |  | 0 | $GoToMsg     = "first character before equals differ"; | 
| 3402 | 0 |  |  |  |  | 0 | $return_code = 1; | 
| 3403 |  |  |  |  |  |  | } | 
| 3404 |  |  |  |  |  |  |  | 
| 3405 |  |  |  |  |  |  | # The introduction of sub 'prune_alignment_tree' | 
| 3406 |  |  |  |  |  |  | # enabled alignment of lists left of the equals with | 
| 3407 |  |  |  |  |  |  | # other scalar variables. For example: | 
| 3408 |  |  |  |  |  |  | # my ( $D, $s, $e ) = @_; | 
| 3409 |  |  |  |  |  |  | # my $d             = length $D; | 
| 3410 |  |  |  |  |  |  | # my $c             = $e - $s - $d; | 
| 3411 |  |  |  |  |  |  |  | 
| 3412 |  |  |  |  |  |  | # But this would change formatting of a lot of scripts, | 
| 3413 |  |  |  |  |  |  | # so for now we prevent alignment of comma lists on the | 
| 3414 |  |  |  |  |  |  | # left with scalars on the left.  We will also prevent | 
| 3415 |  |  |  |  |  |  | # any partial alignments. | 
| 3416 |  |  |  |  |  |  |  | 
| 3417 |  |  |  |  |  |  | # set return code 2 if the = is at line level, but | 
| 3418 |  |  |  |  |  |  | # set return code 1 if the = is below line level, i.e. | 
| 3419 |  |  |  |  |  |  | #  sub new { my ( $p, $v ) = @_; bless \$v, $p } | 
| 3420 |  |  |  |  |  |  | #  sub iter { my ($x) = @_; return undef if $$x < 0; return $$x--; } | 
| 3421 |  |  |  |  |  |  |  | 
| 3422 |  |  |  |  |  |  | elsif ( ( index( $pat_m, ',' ) >= 0 ) ne ( index( $pat, ',' ) >= 0 ) ) { | 
| 3423 | 1 |  |  |  |  | 5 | $GoToMsg     = "mixed commas/no-commas before equals"; | 
| 3424 | 1 |  |  |  |  | 3 | $return_code = 1; | 
| 3425 | 1 | 50 |  |  |  | 5 | if ( $lev eq $group_level ) { | 
| 3426 | 1 |  |  |  |  | 3 | $return_code = 2; | 
| 3427 |  |  |  |  |  |  | } | 
| 3428 |  |  |  |  |  |  | } | 
| 3429 |  |  |  |  |  |  | else { | 
| 3430 | 15 |  |  |  |  | 44 | $return_code = 0; | 
| 3431 |  |  |  |  |  |  | } | 
| 3432 |  |  |  |  |  |  | } | 
| 3433 |  |  |  |  |  |  | else { | 
| 3434 | 120 |  |  |  |  | 186 | $return_code = 0; | 
| 3435 |  |  |  |  |  |  | } | 
| 3436 |  |  |  |  |  |  |  | 
| 3437 |  |  |  |  |  |  | EXPLAIN_COMPARE_PATTERNS | 
| 3438 |  |  |  |  |  |  | && $return_code | 
| 3439 | 166 |  |  |  |  | 231 | && print {*STDOUT} "no match because $GoToMsg\n"; | 
| 3440 |  |  |  |  |  |  |  | 
| 3441 | 166 |  |  |  |  | 431 | return ( $return_code, \$GoToMsg ); | 
| 3442 |  |  |  |  |  |  |  | 
| 3443 |  |  |  |  |  |  | } ## end sub compare_patterns | 
| 3444 |  |  |  |  |  |  |  | 
| 3445 |  |  |  |  |  |  | sub fat_comma_to_comma { | 
| 3446 | 765 |  |  | 765 | 0 | 1427 | my ($str) = @_; | 
| 3447 |  |  |  |  |  |  |  | 
| 3448 |  |  |  |  |  |  | # We are changing '=>' to ',' and removing any trailing decimal count | 
| 3449 |  |  |  |  |  |  | # because currently fat commas have a count and commas do not. | 
| 3450 |  |  |  |  |  |  | # For example, we will change '=>2+{-3.2' into ',2+{-3' | 
| 3451 | 765 | 100 |  |  |  | 2199 | if ( $str =~ /^=>([^\.]*)/ ) { $str = ',' . $1 } | 
|  | 181 |  |  |  |  | 543 |  | 
| 3452 | 765 |  |  |  |  | 2155 | return $str; | 
| 3453 |  |  |  |  |  |  | } ## end sub fat_comma_to_comma | 
| 3454 |  |  |  |  |  |  |  | 
| 3455 |  |  |  |  |  |  | sub get_line_token_info { | 
| 3456 |  |  |  |  |  |  |  | 
| 3457 |  |  |  |  |  |  | # scan lines of tokens and return summary information about the range of | 
| 3458 |  |  |  |  |  |  | # levels and patterns. | 
| 3459 | 154 |  |  | 154 | 0 | 401 | my ($rlines) = @_; | 
| 3460 |  |  |  |  |  |  |  | 
| 3461 |  |  |  |  |  |  | # First scan to check monotonicity. Here is an example of several | 
| 3462 |  |  |  |  |  |  | # lines which are monotonic. The = is the lowest level, and | 
| 3463 |  |  |  |  |  |  | # the commas are all one level deeper. So this is not nonmonotonic. | 
| 3464 |  |  |  |  |  |  | #  $$d{"weeks"}   = [ "w",  "wk",  "wks", "week", "weeks" ]; | 
| 3465 |  |  |  |  |  |  | #  $$d{"days"}    = [ "d",  "day", "days" ]; | 
| 3466 |  |  |  |  |  |  | #  $$d{"hours"}   = [ "h",  "hr",  "hrs", "hour", "hours" ]; | 
| 3467 | 154 |  |  |  |  | 316 | my @all_token_info; | 
| 3468 | 154 |  |  |  |  | 332 | my $all_monotonic = 1; | 
| 3469 | 154 |  |  |  |  | 743 | foreach my $jj ( 0 .. @{$rlines} - 1 ) { | 
|  | 154 |  |  |  |  | 509 |  | 
| 3470 | 627 |  |  |  |  | 1167 | my ($line) = $rlines->[$jj]; | 
| 3471 | 627 |  |  |  |  | 1106 | my $rtokens = $line->{'rtokens'}; | 
| 3472 | 627 |  |  |  |  | 841 | my $last_lev; | 
| 3473 | 627 |  |  |  |  | 976 | my $is_monotonic = 1; | 
| 3474 | 627 |  |  |  |  | 937 | my $i            = -1; | 
| 3475 | 627 |  |  |  |  | 927 | foreach my $tok ( @{$rtokens} ) { | 
|  | 627 |  |  |  |  | 1160 |  | 
| 3476 | 1649 |  |  |  |  | 2119 | $i++; | 
| 3477 | 1649 |  |  |  |  | 2945 | my ( $raw_tok, $lev, $tag, $tok_count ) = | 
| 3478 |  |  |  |  |  |  | decode_alignment_token($tok); | 
| 3479 | 1649 |  |  |  |  | 2561 | push @{ $all_token_info[$jj] }, | 
|  | 1649 |  |  |  |  | 4806 |  | 
| 3480 |  |  |  |  |  |  | [ $raw_tok, $lev, $tag, $tok_count ]; | 
| 3481 | 1649 | 100 |  |  |  | 4206 | last if ( $tok eq '#' ); | 
| 3482 | 1022 | 100 | 100 |  |  | 3169 | if ( $i > 0 && $lev < $last_lev ) { $is_monotonic = 0 } | 
|  | 81 |  |  |  |  | 194 |  | 
| 3483 | 1022 |  |  |  |  | 1794 | $last_lev = $lev; | 
| 3484 |  |  |  |  |  |  | } | 
| 3485 | 627 | 100 |  |  |  | 1814 | if ( !$is_monotonic ) { $all_monotonic = 0 } | 
|  | 78 |  |  |  |  | 179 |  | 
| 3486 |  |  |  |  |  |  | } | 
| 3487 |  |  |  |  |  |  |  | 
| 3488 | 154 |  |  |  |  | 659 | my $rline_values = []; | 
| 3489 | 154 |  |  |  |  | 1126 | foreach my $jj ( 0 .. @{$rlines} - 1 ) { | 
|  | 154 |  |  |  |  | 595 |  | 
| 3490 | 627 |  |  |  |  | 1212 | my ($line) = $rlines->[$jj]; | 
| 3491 |  |  |  |  |  |  |  | 
| 3492 | 627 |  |  |  |  | 1094 | my $rtokens = $line->{'rtokens'}; | 
| 3493 | 627 |  |  |  |  | 941 | my $i       = -1; | 
| 3494 | 627 |  |  |  |  | 946 | my ( $lev_min, $lev_max ); | 
| 3495 | 627 |  |  |  |  | 988 | my $token_pattern_max = EMPTY_STRING; | 
| 3496 | 627 |  |  |  |  | 876 | my %saw_level; | 
| 3497 | 627 |  |  |  |  | 879 | my $is_monotonic = 1; | 
| 3498 |  |  |  |  |  |  |  | 
| 3499 |  |  |  |  |  |  | # find the index of the last token before the side comment | 
| 3500 | 627 |  |  |  |  | 888 | my $imax      = @{$rtokens} - 2; | 
|  | 627 |  |  |  |  | 1079 |  | 
| 3501 | 627 |  |  |  |  | 949 | my $imax_true = $imax; | 
| 3502 |  |  |  |  |  |  |  | 
| 3503 |  |  |  |  |  |  | # If the entire group is monotonic, and the line ends in a comma list, | 
| 3504 |  |  |  |  |  |  | # walk it back to the first such comma. this will have the effect of | 
| 3505 |  |  |  |  |  |  | # making all trailing ragged comma lists match in the prune tree | 
| 3506 |  |  |  |  |  |  | # routine.  these trailing comma lists can better be handled by later | 
| 3507 |  |  |  |  |  |  | # alignment rules. | 
| 3508 |  |  |  |  |  |  |  | 
| 3509 |  |  |  |  |  |  | # Treat fat commas the same as commas here by converting them to | 
| 3510 |  |  |  |  |  |  | # commas.  This will improve the chance of aligning the leading parts | 
| 3511 |  |  |  |  |  |  | # of ragged lists. | 
| 3512 |  |  |  |  |  |  |  | 
| 3513 | 627 |  |  |  |  | 1590 | my $tok_end = fat_comma_to_comma( $rtokens->[$imax] ); | 
| 3514 | 627 | 100 | 100 |  |  | 2473 | if ( $all_monotonic && $tok_end =~ /^,/ ) { | 
| 3515 | 142 |  |  |  |  | 347 | my $ii = $imax - 1; | 
| 3516 | 142 |  | 100 |  |  | 550 | while ( $ii >= 0 | 
| 3517 |  |  |  |  |  |  | && fat_comma_to_comma( $rtokens->[$ii] ) eq $tok_end ) | 
| 3518 |  |  |  |  |  |  | { | 
| 3519 | 93 |  |  |  |  | 158 | $imax = $ii; | 
| 3520 | 93 |  |  |  |  | 234 | $ii--; | 
| 3521 |  |  |  |  |  |  | } | 
| 3522 |  |  |  |  |  |  | } | 
| 3523 |  |  |  |  |  |  |  | 
| 3524 |  |  |  |  |  |  | # make a first pass to find level range | 
| 3525 | 627 |  |  |  |  | 1010 | my $last_lev; | 
| 3526 | 627 |  |  |  |  | 934 | foreach my $tok ( @{$rtokens} ) { | 
|  | 627 |  |  |  |  | 1160 |  | 
| 3527 | 1556 |  |  |  |  | 2042 | $i++; | 
| 3528 | 1556 | 100 |  |  |  | 2890 | last if ( $i > $imax ); | 
| 3529 | 929 | 50 |  |  |  | 1759 | last if ( $tok eq '#' ); | 
| 3530 |  |  |  |  |  |  | my ( $raw_tok, $lev, $tag, $tok_count ) = | 
| 3531 | 929 |  |  |  |  | 1227 | @{ $all_token_info[$jj]->[$i] }; | 
|  | 929 |  |  |  |  | 2434 |  | 
| 3532 |  |  |  |  |  |  |  | 
| 3533 | 929 | 50 |  |  |  | 1831 | last if ( $tok eq '#' ); | 
| 3534 | 929 |  |  |  |  | 1469 | $token_pattern_max .= $tok; | 
| 3535 | 929 |  |  |  |  | 1699 | $saw_level{$lev}++; | 
| 3536 | 929 | 100 |  |  |  | 1759 | if ( !defined($lev_min) ) { | 
| 3537 | 527 |  |  |  |  | 1192 | $lev_min = $lev; | 
| 3538 | 527 |  |  |  |  | 771 | $lev_max = $lev; | 
| 3539 |  |  |  |  |  |  | } | 
| 3540 |  |  |  |  |  |  | else { | 
| 3541 | 402 | 100 |  |  |  | 1007 | if ( $lev < $lev_min )  { $lev_min      = $lev; } | 
|  | 51 |  |  |  |  | 115 |  | 
| 3542 | 402 | 100 |  |  |  | 813 | if ( $lev > $lev_max )  { $lev_max      = $lev; } | 
|  | 122 |  |  |  |  | 960 |  | 
| 3543 | 402 | 100 |  |  |  | 841 | if ( $lev < $last_lev ) { $is_monotonic = 0 } | 
|  | 81 |  |  |  |  | 139 |  | 
| 3544 |  |  |  |  |  |  | } | 
| 3545 | 929 |  |  |  |  | 1532 | $last_lev = $lev; | 
| 3546 |  |  |  |  |  |  | } | 
| 3547 |  |  |  |  |  |  |  | 
| 3548 |  |  |  |  |  |  | # handle no levels | 
| 3549 | 627 |  |  |  |  | 1266 | my $rtoken_patterns = {}; | 
| 3550 | 627 |  |  |  |  | 1119 | my $rtoken_indexes  = {}; | 
| 3551 | 627 |  |  |  |  | 2363 | my @levs            = sort keys %saw_level; | 
| 3552 | 627 | 100 |  |  |  | 1929 | if ( !defined($lev_min) ) { | 
|  |  | 100 |  |  |  |  |  | 
| 3553 | 100 |  |  |  |  | 191 | $lev_min                     = -1; | 
| 3554 | 100 |  |  |  |  | 186 | $lev_max                     = -1; | 
| 3555 | 100 |  |  |  |  | 224 | $levs[0]                     = -1; | 
| 3556 | 100 |  |  |  |  | 323 | $rtoken_patterns->{$lev_min} = EMPTY_STRING; | 
| 3557 | 100 |  |  |  |  | 253 | $rtoken_indexes->{$lev_min}  = []; | 
| 3558 |  |  |  |  |  |  | } | 
| 3559 |  |  |  |  |  |  |  | 
| 3560 |  |  |  |  |  |  | # handle one level | 
| 3561 |  |  |  |  |  |  | elsif ( $lev_max == $lev_min ) { | 
| 3562 | 359 |  |  |  |  | 861 | $rtoken_patterns->{$lev_max} = $token_pattern_max; | 
| 3563 | 359 |  |  |  |  | 1043 | $rtoken_indexes->{$lev_max}  = [ ( 0 .. $imax ) ]; | 
| 3564 |  |  |  |  |  |  | } | 
| 3565 |  |  |  |  |  |  |  | 
| 3566 |  |  |  |  |  |  | # handle multiple levels | 
| 3567 |  |  |  |  |  |  | else { | 
| 3568 | 168 |  |  |  |  | 438 | $rtoken_patterns->{$lev_max} = $token_pattern_max; | 
| 3569 | 168 |  |  |  |  | 681 | $rtoken_indexes->{$lev_max}  = [ ( 0 .. $imax ) ]; | 
| 3570 |  |  |  |  |  |  |  | 
| 3571 | 168 |  |  |  |  | 376 | my $lev_top = pop @levs;    # already did max level | 
| 3572 | 168 |  |  |  |  | 330 | my $itok    = -1; | 
| 3573 | 168 |  |  |  |  | 264 | foreach my $tok ( @{$rtokens} ) { | 
|  | 168 |  |  |  |  | 395 |  | 
| 3574 | 704 |  |  |  |  | 965 | $itok++; | 
| 3575 | 704 | 100 |  |  |  | 1402 | last if ( $itok > $imax ); | 
| 3576 |  |  |  |  |  |  | my ( $raw_tok, $lev, $tag, $tok_count ) = | 
| 3577 | 536 |  |  |  |  | 753 | @{ $all_token_info[$jj]->[$itok] }; | 
|  | 536 |  |  |  |  | 1209 |  | 
| 3578 | 536 | 50 |  |  |  | 1130 | last if ( $raw_tok eq '#' ); | 
| 3579 | 536 |  |  |  |  | 836 | foreach my $lev_test (@levs) { | 
| 3580 | 564 | 100 |  |  |  | 1882 | next if ( $lev > $lev_test ); | 
| 3581 | 280 |  |  |  |  | 638 | $rtoken_patterns->{$lev_test} .= $tok; | 
| 3582 | 280 |  |  |  |  | 422 | push @{ $rtoken_indexes->{$lev_test} }, $itok; | 
|  | 280 |  |  |  |  | 816 |  | 
| 3583 |  |  |  |  |  |  | } | 
| 3584 |  |  |  |  |  |  | } | 
| 3585 | 168 |  |  |  |  | 497 | push @levs, $lev_top; | 
| 3586 |  |  |  |  |  |  | } | 
| 3587 |  |  |  |  |  |  |  | 
| 3588 | 627 |  |  |  |  | 1053 | push @{$rline_values}, | 
|  | 627 |  |  |  |  | 2448 |  | 
| 3589 |  |  |  |  |  |  | [ | 
| 3590 |  |  |  |  |  |  | $lev_min,        $lev_max,      $rtoken_patterns, \@levs, | 
| 3591 |  |  |  |  |  |  | $rtoken_indexes, $is_monotonic, $imax_true,       $imax, | 
| 3592 |  |  |  |  |  |  | ]; | 
| 3593 |  |  |  |  |  |  |  | 
| 3594 |  |  |  |  |  |  | # debug | 
| 3595 | 627 |  |  |  |  | 1836 | 0 && do { | 
| 3596 |  |  |  |  |  |  | local $LIST_SEPARATOR = ')('; | 
| 3597 |  |  |  |  |  |  | print "lev_min=$lev_min, lev_max=$lev_max, levels=(@levs)\n"; | 
| 3598 |  |  |  |  |  |  | foreach my $key ( sort keys %{$rtoken_patterns} ) { | 
| 3599 |  |  |  |  |  |  | print "$key => $rtoken_patterns->{$key}\n"; | 
| 3600 |  |  |  |  |  |  | print "$key => @{$rtoken_indexes->{$key}}\n"; | 
| 3601 |  |  |  |  |  |  | } | 
| 3602 |  |  |  |  |  |  | }; | 
| 3603 |  |  |  |  |  |  | } ## end loop over lines | 
| 3604 | 154 |  |  |  |  | 1246 | return ( $rline_values, $all_monotonic ); | 
| 3605 |  |  |  |  |  |  | } ## end sub get_line_token_info | 
| 3606 |  |  |  |  |  |  |  | 
| 3607 |  |  |  |  |  |  | sub prune_alignment_tree { | 
| 3608 | 154 |  |  | 154 | 0 | 493 | my ($rlines) = @_; | 
| 3609 | 154 |  |  |  |  | 290 | my $jmax = @{$rlines} - 1; | 
|  | 154 |  |  |  |  | 447 |  | 
| 3610 | 154 | 50 |  |  |  | 600 | return if ( $jmax <= 0 ); | 
| 3611 |  |  |  |  |  |  |  | 
| 3612 |  |  |  |  |  |  | # Vertical alignment in perltidy is done as an iterative process.  The | 
| 3613 |  |  |  |  |  |  | # starting point is to mark all possible alignment tokens ('=', ',', '=>', | 
| 3614 |  |  |  |  |  |  | # etc) for vertical alignment.  Then we have to delete all alignments | 
| 3615 |  |  |  |  |  |  | # which, if actually made, would detract from overall alignment.  This | 
| 3616 |  |  |  |  |  |  | # is done in several phases of which this is one. | 
| 3617 |  |  |  |  |  |  |  | 
| 3618 |  |  |  |  |  |  | # In this routine we look at the alignments of a group of lines as a | 
| 3619 |  |  |  |  |  |  | # hierarchical tree.  We will 'prune' the tree to limited depths if that | 
| 3620 |  |  |  |  |  |  | # will improve overall alignment at the lower depths. | 
| 3621 |  |  |  |  |  |  | # For each line we will be looking at its alignment patterns down to | 
| 3622 |  |  |  |  |  |  | # different fixed depths. For each depth, we include all lower depths and | 
| 3623 |  |  |  |  |  |  | # ignore all higher depths.  We want to see if we can get alignment of a | 
| 3624 |  |  |  |  |  |  | # larger group of lines if we ignore alignments at some lower depth. | 
| 3625 |  |  |  |  |  |  | # Here is an # example: | 
| 3626 |  |  |  |  |  |  |  | 
| 3627 |  |  |  |  |  |  | # for ( | 
| 3628 |  |  |  |  |  |  | #     [ '$var',     sub { join $_, "bar" },            0, "bar" ], | 
| 3629 |  |  |  |  |  |  | #     [ 'CONSTANT', sub { join "foo", "bar" },         0, "bar" ], | 
| 3630 |  |  |  |  |  |  | #     [ 'CONSTANT', sub { join "foo", "bar", 3 },      1, "barfoo3" ], | 
| 3631 |  |  |  |  |  |  | #     [ '$myvar',   sub { my $var; join $var, "bar" }, 0, "bar" ], | 
| 3632 |  |  |  |  |  |  | # ); | 
| 3633 |  |  |  |  |  |  |  | 
| 3634 |  |  |  |  |  |  | # In the above example, all lines have three commas at the lowest depth | 
| 3635 |  |  |  |  |  |  | # (zero), so if there were no other alignments, these lines would all | 
| 3636 |  |  |  |  |  |  | # align considering only the zero depth alignment token.  But some lines | 
| 3637 |  |  |  |  |  |  | # have additional comma alignments at the next depth, so we need to decide | 
| 3638 |  |  |  |  |  |  | # if we should drop those to keep the top level alignments, or keep those | 
| 3639 |  |  |  |  |  |  | # for some additional low level alignments at the expense losing some top | 
| 3640 |  |  |  |  |  |  | # level alignments.  In this case we will drop the deeper level commas to | 
| 3641 |  |  |  |  |  |  | # keep the entire collection aligned.  But in some cases the decision could | 
| 3642 |  |  |  |  |  |  | # go the other way. | 
| 3643 |  |  |  |  |  |  |  | 
| 3644 |  |  |  |  |  |  | # The tree for this example at the zero depth has one node containing | 
| 3645 |  |  |  |  |  |  | # all four lines, since they are identical at zero level (three commas). | 
| 3646 |  |  |  |  |  |  | # At depth one, there are three 'children' nodes, namely: | 
| 3647 |  |  |  |  |  |  | # - lines 1 and 2, which have a single comma in the 'sub' at depth 1 | 
| 3648 |  |  |  |  |  |  | # - line 3, which has 2 commas at depth 1 | 
| 3649 |  |  |  |  |  |  | # - line4, which has a ';' and a ',' at depth 1 | 
| 3650 |  |  |  |  |  |  | # There are no deeper alignments in this example. | 
| 3651 |  |  |  |  |  |  | # so the tree structure for this example is: | 
| 3652 |  |  |  |  |  |  | # | 
| 3653 |  |  |  |  |  |  | #    depth 0         depth 1      depth 2 | 
| 3654 |  |  |  |  |  |  | #    [lines 1-4] --  [line 1-2] -  (empty) | 
| 3655 |  |  |  |  |  |  | #                 |  [line 3]   -  (empty) | 
| 3656 |  |  |  |  |  |  | #                 |  [line 4]   -  (empty) | 
| 3657 |  |  |  |  |  |  |  | 
| 3658 |  |  |  |  |  |  | # We can carry this to any depth, but it is not really useful to go below | 
| 3659 |  |  |  |  |  |  | # depth 2. To cleanly stop there, we will consider depth 2 to contain all | 
| 3660 |  |  |  |  |  |  | # alignments at depth >=2. | 
| 3661 |  |  |  |  |  |  |  | 
| 3662 | 39 |  |  | 39 |  | 365 | use constant EXPLAIN_PRUNE => 0; | 
|  | 39 |  |  |  |  | 121 |  | 
|  | 39 |  |  |  |  | 54189 |  | 
| 3663 |  |  |  |  |  |  |  | 
| 3664 |  |  |  |  |  |  | #------------------------------------------------------------------- | 
| 3665 |  |  |  |  |  |  | # Prune Tree Step 1. Start by scanning the lines and collecting info | 
| 3666 |  |  |  |  |  |  | #------------------------------------------------------------------- | 
| 3667 |  |  |  |  |  |  |  | 
| 3668 |  |  |  |  |  |  | # Note that the caller had this info but we have to redo this now because | 
| 3669 |  |  |  |  |  |  | # alignment tokens may have been deleted. | 
| 3670 | 154 |  |  |  |  | 699 | my ( $rline_values, $all_monotonic ) = get_line_token_info($rlines); | 
| 3671 |  |  |  |  |  |  |  | 
| 3672 |  |  |  |  |  |  | # If all the lines have levels which increase monotonically from left to | 
| 3673 |  |  |  |  |  |  | # right, then the sweep-left-to-right pass can do a better job of alignment | 
| 3674 |  |  |  |  |  |  | # than pruning, and without deleting alignments. | 
| 3675 | 154 | 100 |  |  |  | 1026 | return if ($all_monotonic); | 
| 3676 |  |  |  |  |  |  |  | 
| 3677 |  |  |  |  |  |  | # Contents of $rline_values | 
| 3678 |  |  |  |  |  |  | #   [ | 
| 3679 |  |  |  |  |  |  | #     $lev_min,        $lev_max,      $rtoken_patterns, \@levs, | 
| 3680 |  |  |  |  |  |  | #     $rtoken_indexes, $is_monotonic, $imax_true,       $imax, | 
| 3681 |  |  |  |  |  |  | #   ]; | 
| 3682 |  |  |  |  |  |  |  | 
| 3683 |  |  |  |  |  |  | # We can work to any depth, but there is little advantage to working | 
| 3684 |  |  |  |  |  |  | # to a a depth greater than 2 | 
| 3685 | 31 |  |  |  |  | 95 | my $MAX_DEPTH = 2; | 
| 3686 |  |  |  |  |  |  |  | 
| 3687 |  |  |  |  |  |  | # This arrays will hold the tree of alignment tokens at different depths | 
| 3688 |  |  |  |  |  |  | # for these lines. | 
| 3689 | 31 |  |  |  |  | 77 | my @match_tree; | 
| 3690 |  |  |  |  |  |  |  | 
| 3691 |  |  |  |  |  |  | # Tree nodes contain these values: | 
| 3692 |  |  |  |  |  |  | # $match_tree[$depth] = [$jbeg, $jend, $n_parent, $level, $pattern, | 
| 3693 |  |  |  |  |  |  | #                        $nc_beg_p, $nc_end_p, $rindexes]; | 
| 3694 |  |  |  |  |  |  | # where | 
| 3695 |  |  |  |  |  |  | #      $depth = 0,1,2 = index of depth of the match | 
| 3696 |  |  |  |  |  |  |  | 
| 3697 |  |  |  |  |  |  | #  $jbeg beginning index j of the range of lines in this match | 
| 3698 |  |  |  |  |  |  | #  $jend ending index j of the range of lines in this match | 
| 3699 |  |  |  |  |  |  | #  $n_parent = index of the containing group at $depth-1, if it exists | 
| 3700 |  |  |  |  |  |  | #  $level = actual level of code being matched in this group | 
| 3701 |  |  |  |  |  |  | #  $pattern = alignment pattern being matched | 
| 3702 |  |  |  |  |  |  | #  $nc_beg_p = first child | 
| 3703 |  |  |  |  |  |  | #  $nc_end_p = last child | 
| 3704 |  |  |  |  |  |  | #  $rindexes = ref to token indexes | 
| 3705 |  |  |  |  |  |  |  | 
| 3706 |  |  |  |  |  |  | # the patterns and levels of the current group being formed at each depth | 
| 3707 | 31 |  |  |  |  | 159 | my ( @token_patterns_current, @levels_current, @token_indexes_current ); | 
| 3708 |  |  |  |  |  |  |  | 
| 3709 |  |  |  |  |  |  | # the patterns and levels of the next line being tested at each depth | 
| 3710 | 31 |  |  |  |  | 0 | my ( @token_patterns_next, @levels_next, @token_indexes_next ); | 
| 3711 |  |  |  |  |  |  |  | 
| 3712 |  |  |  |  |  |  | #----------------------------------------------------------- | 
| 3713 |  |  |  |  |  |  | # define a recursive worker subroutine for tree construction | 
| 3714 |  |  |  |  |  |  | #----------------------------------------------------------- | 
| 3715 |  |  |  |  |  |  |  | 
| 3716 |  |  |  |  |  |  | # This is a recursive routine which is called if a match condition changes | 
| 3717 |  |  |  |  |  |  | # at any depth when a new line is encountered.  It ends the match node | 
| 3718 |  |  |  |  |  |  | # which changed plus all deeper nodes attached to it. | 
| 3719 | 31 |  |  |  |  | 0 | my $end_node; | 
| 3720 |  |  |  |  |  |  | $end_node = sub { | 
| 3721 | 321 |  |  | 321 |  | 558 | my ( $depth, $jl, $n_parent ) = @_; | 
| 3722 |  |  |  |  |  |  |  | 
| 3723 |  |  |  |  |  |  | # $depth is the tree depth | 
| 3724 |  |  |  |  |  |  | # $jl is the  index of the line | 
| 3725 |  |  |  |  |  |  | # $n_parent is index of the parent node of this node | 
| 3726 |  |  |  |  |  |  |  | 
| 3727 | 321 | 100 |  |  |  | 636 | return if ( $depth > $MAX_DEPTH ); | 
| 3728 |  |  |  |  |  |  |  | 
| 3729 |  |  |  |  |  |  | # end any current group at this depth | 
| 3730 | 234 | 100 | 100 |  |  | 785 | if (   $jl >= 0 | 
|  |  |  | 66 |  |  |  |  | 
|  |  |  | 100 |  |  |  |  | 
| 3731 |  |  |  |  |  |  | && defined( $match_tree[$depth] ) | 
| 3732 | 75 |  |  |  |  | 366 | && @{ $match_tree[$depth] } | 
| 3733 |  |  |  |  |  |  | && defined( $levels_current[$depth] ) ) | 
| 3734 |  |  |  |  |  |  | { | 
| 3735 | 69 |  |  |  |  | 134 | $match_tree[$depth]->[-1]->[1] = $jl; | 
| 3736 |  |  |  |  |  |  | } | 
| 3737 |  |  |  |  |  |  |  | 
| 3738 |  |  |  |  |  |  | # Define the index of the node we will create below | 
| 3739 | 234 |  |  |  |  | 402 | my $ng_self = 0; | 
| 3740 | 234 | 100 |  |  |  | 468 | if ( defined( $match_tree[$depth] ) ) { | 
| 3741 | 75 |  |  |  |  | 123 | $ng_self = @{ $match_tree[$depth] }; | 
|  | 75 |  |  |  |  | 147 |  | 
| 3742 |  |  |  |  |  |  | } | 
| 3743 |  |  |  |  |  |  |  | 
| 3744 |  |  |  |  |  |  | # end any next deeper child node(s) | 
| 3745 | 234 |  |  |  |  | 773 | $end_node->( $depth + 1, $jl, $ng_self ); | 
| 3746 |  |  |  |  |  |  |  | 
| 3747 |  |  |  |  |  |  | # update the levels being matched | 
| 3748 | 234 |  |  |  |  | 453 | $token_patterns_current[$depth] = $token_patterns_next[$depth]; | 
| 3749 | 234 |  |  |  |  | 422 | $token_indexes_current[$depth]  = $token_indexes_next[$depth]; | 
| 3750 | 234 |  |  |  |  | 372 | $levels_current[$depth]         = $levels_next[$depth]; | 
| 3751 |  |  |  |  |  |  |  | 
| 3752 |  |  |  |  |  |  | # Do not start a new group at this level if it is not being used | 
| 3753 | 234 | 100 | 66 |  |  | 970 | if ( !defined( $levels_next[$depth] ) | 
|  |  |  | 66 |  |  |  |  | 
| 3754 |  |  |  |  |  |  | || $depth > 0 | 
| 3755 |  |  |  |  |  |  | && $levels_next[$depth] <= $levels_next[ $depth - 1 ] ) | 
| 3756 |  |  |  |  |  |  | { | 
| 3757 | 120 |  |  |  |  | 213 | return; | 
| 3758 |  |  |  |  |  |  | } | 
| 3759 |  |  |  |  |  |  |  | 
| 3760 |  |  |  |  |  |  | # Create a node for the next group at this depth. We initially assume | 
| 3761 |  |  |  |  |  |  | # that it will continue to $jmax, and correct that later if the node | 
| 3762 |  |  |  |  |  |  | # ends earlier. | 
| 3763 | 114 |  |  |  |  | 195 | push @{ $match_tree[$depth] }, | 
|  | 114 |  |  |  |  | 549 |  | 
| 3764 |  |  |  |  |  |  | [ | 
| 3765 |  |  |  |  |  |  | $jl + 1, $jmax, $n_parent, $levels_current[$depth], | 
| 3766 |  |  |  |  |  |  | $token_patterns_current[$depth], | 
| 3767 |  |  |  |  |  |  | undef, undef, $token_indexes_current[$depth], | 
| 3768 |  |  |  |  |  |  | ]; | 
| 3769 |  |  |  |  |  |  |  | 
| 3770 | 114 |  |  |  |  | 279 | return; | 
| 3771 | 31 |  |  |  |  | 324 | };    ## end sub end_node | 
| 3772 |  |  |  |  |  |  |  | 
| 3773 |  |  |  |  |  |  | #----------------------------------------------------- | 
| 3774 |  |  |  |  |  |  | # Prune Tree Step 2. Loop to form the tree of matches. | 
| 3775 |  |  |  |  |  |  | #----------------------------------------------------- | 
| 3776 | 31 |  |  |  |  | 132 | foreach my $jp ( 0 .. $jmax ) { | 
| 3777 |  |  |  |  |  |  |  | 
| 3778 |  |  |  |  |  |  | # working with two adjacent line indexes, 'm'=minus, 'p'=plus | 
| 3779 | 236 |  |  |  |  | 364 | my $jm = $jp - 1; | 
| 3780 |  |  |  |  |  |  |  | 
| 3781 |  |  |  |  |  |  | # Pull out needed values for the next line | 
| 3782 |  |  |  |  |  |  | my ( $lev_min, $lev_max, $rtoken_patterns, $rlevs, $rtoken_indexes, | 
| 3783 |  |  |  |  |  |  | $is_monotonic, $imax_true, $imax ) | 
| 3784 | 236 |  |  |  |  | 305 | = @{ $rline_values->[$jp] }; | 
|  | 236 |  |  |  |  | 591 |  | 
| 3785 |  |  |  |  |  |  |  | 
| 3786 |  |  |  |  |  |  | # Transfer levels and patterns for this line to the working arrays. | 
| 3787 |  |  |  |  |  |  | # If the number of levels differs from our chosen MAX_DEPTH ... | 
| 3788 |  |  |  |  |  |  | # if fewer than MAX_DEPTH: leave levels at missing depths undefined | 
| 3789 |  |  |  |  |  |  | # if more than MAX_DEPTH: set the MAX_DEPTH level to be the maximum | 
| 3790 | 236 |  |  |  |  | 419 | @levels_next = @{$rlevs}[ 0 .. $MAX_DEPTH ]; | 
|  | 236 |  |  |  |  | 522 |  | 
| 3791 | 236 | 100 |  |  |  | 354 | if ( @{$rlevs} > $MAX_DEPTH ) { | 
|  | 236 |  |  |  |  | 467 |  | 
| 3792 | 5 |  |  |  |  | 7 | $levels_next[$MAX_DEPTH] = $rlevs->[-1]; | 
| 3793 |  |  |  |  |  |  | } | 
| 3794 | 236 |  |  |  |  | 328 | my $depth = 0; | 
| 3795 | 236 |  |  |  |  | 361 | foreach my $item (@levels_next) { | 
| 3796 |  |  |  |  |  |  | $token_patterns_next[$depth] = | 
| 3797 | 708 | 100 |  |  |  | 1280 | defined($item) ? $rtoken_patterns->{$item} : undef; | 
| 3798 |  |  |  |  |  |  | $token_indexes_next[$depth] = | 
| 3799 | 708 | 100 |  |  |  | 1075 | defined($item) ? $rtoken_indexes->{$item} : undef; | 
| 3800 | 708 |  |  |  |  | 972 | $depth++; | 
| 3801 |  |  |  |  |  |  | } | 
| 3802 |  |  |  |  |  |  |  | 
| 3803 |  |  |  |  |  |  | # Look for a change in match groups... | 
| 3804 |  |  |  |  |  |  |  | 
| 3805 |  |  |  |  |  |  | # Initialize on the first line | 
| 3806 | 236 | 100 |  |  |  | 834 | if ( $jp == 0 ) { | 
|  |  | 100 |  |  |  |  |  | 
|  |  | 50 |  |  |  |  |  | 
| 3807 | 31 |  |  |  |  | 71 | my $n_parent; | 
| 3808 | 31 |  |  |  |  | 134 | $end_node->( 0, $jm, $n_parent ); | 
| 3809 |  |  |  |  |  |  | } | 
| 3810 |  |  |  |  |  |  |  | 
| 3811 |  |  |  |  |  |  | # End groups if a hard flag has been set | 
| 3812 |  |  |  |  |  |  | elsif ( $rlines->[$jm]->{'end_group'} ) { | 
| 3813 | 10 |  |  |  |  | 34 | my $n_parent; | 
| 3814 | 10 |  |  |  |  | 34 | $end_node->( 0, $jm, $n_parent ); | 
| 3815 |  |  |  |  |  |  | } | 
| 3816 |  |  |  |  |  |  |  | 
| 3817 |  |  |  |  |  |  | # Continue at hanging side comment | 
| 3818 |  |  |  |  |  |  | elsif ( $rlines->[$jp]->{'is_hanging_side_comment'} ) { | 
| 3819 | 0 |  |  |  |  | 0 | next; | 
| 3820 |  |  |  |  |  |  | } | 
| 3821 |  |  |  |  |  |  |  | 
| 3822 |  |  |  |  |  |  | # Otherwise see if anything changed and update the tree if so | 
| 3823 |  |  |  |  |  |  | else { | 
| 3824 | 195 |  |  |  |  | 359 | foreach my $depth ( 0 .. $MAX_DEPTH ) { | 
| 3825 |  |  |  |  |  |  |  | 
| 3826 | 401 |  |  |  |  | 566 | my $def_current = defined( $token_patterns_current[$depth] ); | 
| 3827 | 401 |  |  |  |  | 501 | my $def_next    = defined( $token_patterns_next[$depth] ); | 
| 3828 | 401 | 100 | 100 |  |  | 935 | last if ( !$def_current && !$def_next ); | 
| 3829 | 253 | 100 | 100 |  |  | 1031 | if (   !$def_current | 
|  |  |  | 100 |  |  |  |  | 
| 3830 |  |  |  |  |  |  | || !$def_next | 
| 3831 |  |  |  |  |  |  | || $token_patterns_current[$depth] ne | 
| 3832 |  |  |  |  |  |  | $token_patterns_next[$depth] ) | 
| 3833 |  |  |  |  |  |  | { | 
| 3834 | 46 |  |  |  |  | 85 | my $n_parent; | 
| 3835 | 46 | 100 | 66 |  |  | 276 | if ( $depth > 0 && defined( $match_tree[ $depth - 1 ] ) ) { | 
| 3836 | 23 |  |  |  |  | 40 | $n_parent = @{ $match_tree[ $depth - 1 ] } - 1; | 
|  | 23 |  |  |  |  | 55 |  | 
| 3837 |  |  |  |  |  |  | } | 
| 3838 | 46 |  |  |  |  | 171 | $end_node->( $depth, $jm, $n_parent ); | 
| 3839 | 46 |  |  |  |  | 126 | last; | 
| 3840 |  |  |  |  |  |  | } | 
| 3841 |  |  |  |  |  |  | } | 
| 3842 |  |  |  |  |  |  | } | 
| 3843 |  |  |  |  |  |  | } ## end loop to form tree of matches | 
| 3844 |  |  |  |  |  |  |  | 
| 3845 |  |  |  |  |  |  | #--------------------------------------------------------- | 
| 3846 |  |  |  |  |  |  | # Prune Tree Step 3. Make links from parent to child nodes | 
| 3847 |  |  |  |  |  |  | #--------------------------------------------------------- | 
| 3848 |  |  |  |  |  |  |  | 
| 3849 |  |  |  |  |  |  | # It seemed cleaner to do this as a separate step rather than during tree | 
| 3850 |  |  |  |  |  |  | # construction.  The children nodes have links up to the parent node which | 
| 3851 |  |  |  |  |  |  | # created them.  Now make links in the opposite direction, so the parents | 
| 3852 |  |  |  |  |  |  | # can find the children.  We store the range of children nodes ($nc_beg, | 
| 3853 |  |  |  |  |  |  | # $nc_end) of each parent with two additional indexes in the original array. | 
| 3854 |  |  |  |  |  |  | # These will be undef if no children. | 
| 3855 | 31 |  |  |  |  | 179 | foreach my $depth ( reverse( 1 .. $MAX_DEPTH ) ) { | 
| 3856 | 62 | 100 |  |  |  | 205 | next unless defined( $match_tree[$depth] ); | 
| 3857 | 32 |  |  |  |  | 59 | my $nc_max = @{ $match_tree[$depth] } - 1; | 
|  | 32 |  |  |  |  | 95 |  | 
| 3858 | 32 |  |  |  |  | 90 | my $np_now; | 
| 3859 | 32 |  |  |  |  | 104 | foreach my $nc ( 0 .. $nc_max ) { | 
| 3860 | 50 |  |  |  |  | 109 | my $np = $match_tree[$depth]->[$nc]->[2]; | 
| 3861 | 50 | 50 |  |  |  | 149 | if ( !defined($np) ) { | 
| 3862 |  |  |  |  |  |  |  | 
| 3863 |  |  |  |  |  |  | # shouldn't happen | 
| 3864 |  |  |  |  |  |  | #print STDERR "lost child $np at depth $depth\n"; | 
| 3865 | 0 |  |  |  |  | 0 | next; | 
| 3866 |  |  |  |  |  |  | } | 
| 3867 | 50 | 100 | 100 |  |  | 201 | if ( !defined($np_now) || $np != $np_now ) { | 
| 3868 | 35 |  |  |  |  | 71 | $np_now = $np; | 
| 3869 | 35 |  |  |  |  | 114 | $match_tree[ $depth - 1 ]->[$np]->[5] = $nc; | 
| 3870 |  |  |  |  |  |  | } | 
| 3871 | 50 |  |  |  |  | 158 | $match_tree[ $depth - 1 ]->[$np]->[6] = $nc; | 
| 3872 |  |  |  |  |  |  | } | 
| 3873 |  |  |  |  |  |  | } ## end loop to make links down to the child nodes | 
| 3874 |  |  |  |  |  |  |  | 
| 3875 | 31 |  |  |  |  | 70 | EXPLAIN_PRUNE > 0 && do { | 
| 3876 |  |  |  |  |  |  | print "Tree complete. Found these groups:\n"; | 
| 3877 |  |  |  |  |  |  | foreach my $depth ( 0 .. $MAX_DEPTH ) { | 
| 3878 |  |  |  |  |  |  | Dump_tree_groups( \@{ $match_tree[$depth] }, "depth=$depth" ); | 
| 3879 |  |  |  |  |  |  | } | 
| 3880 |  |  |  |  |  |  | }; | 
| 3881 |  |  |  |  |  |  |  | 
| 3882 |  |  |  |  |  |  | #------------------------------------------------------ | 
| 3883 |  |  |  |  |  |  | # Prune Tree Step 4. Make a list of nodes to be deleted | 
| 3884 |  |  |  |  |  |  | #------------------------------------------------------ | 
| 3885 |  |  |  |  |  |  |  | 
| 3886 |  |  |  |  |  |  | #  list of lines with tokens to be deleted: | 
| 3887 |  |  |  |  |  |  | #  [$jbeg, $jend, $level_keep] | 
| 3888 |  |  |  |  |  |  | #  $jbeg..$jend is the range of line indexes, | 
| 3889 |  |  |  |  |  |  | #  $level_keep is the minimum level to keep | 
| 3890 | 31 |  |  |  |  | 105 | my @delete_list; | 
| 3891 |  |  |  |  |  |  |  | 
| 3892 |  |  |  |  |  |  | # Not currently used: | 
| 3893 |  |  |  |  |  |  | #  Groups with ending comma lists and their range of sizes: | 
| 3894 |  |  |  |  |  |  | #  $ragged_comma_group{$id} = [ imax_group_min, imax_group_max ] | 
| 3895 |  |  |  |  |  |  | ## my %ragged_comma_group; | 
| 3896 |  |  |  |  |  |  |  | 
| 3897 |  |  |  |  |  |  | # We work with a list of nodes to visit at the next deeper depth. | 
| 3898 |  |  |  |  |  |  | my @todo_list; | 
| 3899 | 31 | 50 |  |  |  | 142 | if ( defined( $match_tree[0] ) ) { | 
| 3900 | 31 |  |  |  |  | 89 | @todo_list = ( 0 .. @{ $match_tree[0] } - 1 ); | 
|  | 31 |  |  |  |  | 115 |  | 
| 3901 |  |  |  |  |  |  | } | 
| 3902 |  |  |  |  |  |  |  | 
| 3903 | 31 |  |  |  |  | 122 | foreach my $depth ( 0 .. $MAX_DEPTH ) { | 
| 3904 | 86 | 100 |  |  |  | 264 | last if ( !@todo_list ); | 
| 3905 | 55 |  |  |  |  | 107 | my @todo_next; | 
| 3906 | 55 |  |  |  |  | 125 | foreach my $np (@todo_list) { | 
| 3907 |  |  |  |  |  |  | my ( $jbeg_p, $jend_p, $np_p, $lev_p, $pat_p, $nc_beg_p, $nc_end_p, | 
| 3908 |  |  |  |  |  |  | $rindexes_p ) | 
| 3909 | 92 |  |  |  |  | 165 | = @{ $match_tree[$depth]->[$np] }; | 
|  | 92 |  |  |  |  | 344 |  | 
| 3910 | 92 |  |  |  |  | 182 | my $nlines_p = $jend_p - $jbeg_p + 1; | 
| 3911 |  |  |  |  |  |  |  | 
| 3912 |  |  |  |  |  |  | # nothing to do if no children | 
| 3913 | 92 | 100 |  |  |  | 267 | next unless defined($nc_beg_p); | 
| 3914 |  |  |  |  |  |  |  | 
| 3915 |  |  |  |  |  |  | # Define the number of lines to either keep or delete a child node. | 
| 3916 |  |  |  |  |  |  | # This is the key decision we have to make.  We want to delete | 
| 3917 |  |  |  |  |  |  | # short runs of matched lines, and keep long runs.  It seems easier | 
| 3918 |  |  |  |  |  |  | # for the eye to follow breaks in monotonic level changes than | 
| 3919 |  |  |  |  |  |  | # non-monotonic level changes.  For example, the following looks | 
| 3920 |  |  |  |  |  |  | # best if we delete the lower level alignments: | 
| 3921 |  |  |  |  |  |  |  | 
| 3922 |  |  |  |  |  |  | #  [1]                  ~~ []; | 
| 3923 |  |  |  |  |  |  | #  [ ["foo"], ["bar"] ] ~~ [ qr/o/, qr/a/ ]; | 
| 3924 |  |  |  |  |  |  | #  [ qr/o/, qr/a/ ]     ~~ [ ["foo"], ["bar"] ]; | 
| 3925 |  |  |  |  |  |  | #  [ "foo", "bar" ]     ~~ [ qr/o/, qr/a/ ]; | 
| 3926 |  |  |  |  |  |  | #  [ qr/o/, qr/a/ ]     ~~ [ "foo", "bar" ]; | 
| 3927 |  |  |  |  |  |  | #  $deep1               ~~ $deep1; | 
| 3928 |  |  |  |  |  |  |  | 
| 3929 |  |  |  |  |  |  | # So we will use two thresholds. | 
| 3930 | 35 |  |  |  |  | 97 | my $nmin_mono     = $depth + 2; | 
| 3931 | 35 |  |  |  |  | 77 | my $nmin_non_mono = $depth + 6; | 
| 3932 | 35 | 100 |  |  |  | 153 | if ( $nmin_mono > $nlines_p - 1 ) { | 
| 3933 | 21 |  |  |  |  | 47 | $nmin_mono = $nlines_p - 1; | 
| 3934 |  |  |  |  |  |  | } | 
| 3935 | 35 | 100 |  |  |  | 142 | if ( $nmin_non_mono > $nlines_p - 1 ) { | 
| 3936 | 31 |  |  |  |  | 82 | $nmin_non_mono = $nlines_p - 1; | 
| 3937 |  |  |  |  |  |  | } | 
| 3938 |  |  |  |  |  |  |  | 
| 3939 |  |  |  |  |  |  | # loop to keep or delete each child node | 
| 3940 | 35 |  |  |  |  | 114 | foreach my $nc ( $nc_beg_p .. $nc_end_p ) { | 
| 3941 |  |  |  |  |  |  | my ( $jbeg_c, $jend_c, $np_c, $lev_c, $pat_c, $nc_beg_c, | 
| 3942 |  |  |  |  |  |  | $nc_end_c ) | 
| 3943 | 50 |  |  |  |  | 89 | = @{ $match_tree[ $depth + 1 ]->[$nc] }; | 
|  | 50 |  |  |  |  | 174 |  | 
| 3944 | 50 |  |  |  |  | 110 | my $nlines_c     = $jend_c - $jbeg_c + 1; | 
| 3945 | 50 |  |  |  |  | 93 | my $is_monotonic = $rline_values->[$jbeg_c]->[5]; | 
| 3946 | 50 | 100 |  |  |  | 127 | my $nmin         = $is_monotonic ? $nmin_mono : $nmin_non_mono; | 
| 3947 | 50 | 100 |  |  |  | 151 | if ( $nlines_c < $nmin ) { | 
| 3948 |  |  |  |  |  |  | ##print "deleting child, nlines=$nlines_c, nmin=$nmin\n"; | 
| 3949 | 22 |  |  |  |  | 122 | push @delete_list, [ $jbeg_c, $jend_c, $lev_p ]; | 
| 3950 |  |  |  |  |  |  | } | 
| 3951 |  |  |  |  |  |  | else { | 
| 3952 |  |  |  |  |  |  | ##print "keeping child, nlines=$nlines_c, nmin=$nmin\n"; | 
| 3953 | 28 |  |  |  |  | 96 | push @todo_next, $nc; | 
| 3954 |  |  |  |  |  |  | } | 
| 3955 |  |  |  |  |  |  | } | 
| 3956 |  |  |  |  |  |  | } | 
| 3957 | 55 |  |  |  |  | 513 | @todo_list = @todo_next; | 
| 3958 |  |  |  |  |  |  | } ## end loop to mark nodes to delete | 
| 3959 |  |  |  |  |  |  |  | 
| 3960 |  |  |  |  |  |  | #------------------------------------------------------------ | 
| 3961 |  |  |  |  |  |  | # Prune Tree Step 5. Loop to delete selected alignment tokens | 
| 3962 |  |  |  |  |  |  | #------------------------------------------------------------ | 
| 3963 | 31 |  |  |  |  | 140 | foreach my $item (@delete_list) { | 
| 3964 | 22 |  |  |  |  | 38 | my ( $jbeg, $jend, $level_keep ) = @{$item}; | 
|  | 22 |  |  |  |  | 55 |  | 
| 3965 | 22 |  |  |  |  | 50 | foreach my $jj ( $jbeg .. $jend ) { | 
| 3966 | 28 |  |  |  |  | 49 | my $line = $rlines->[$jj]; | 
| 3967 | 28 |  |  |  |  | 45 | my @idel; | 
| 3968 | 28 |  |  |  |  | 48 | my $rtokens = $line->{'rtokens'}; | 
| 3969 | 28 |  |  |  |  | 37 | my $imax    = @{$rtokens} - 2; | 
|  | 28 |  |  |  |  | 57 |  | 
| 3970 | 28 |  |  |  |  | 56 | foreach my $i ( 0 .. $imax ) { | 
| 3971 | 152 |  |  |  |  | 218 | my $tok = $rtokens->[$i]; | 
| 3972 | 152 |  |  |  |  | 249 | my ( $raw_tok, $lev, $tag, $tok_count ) = | 
| 3973 |  |  |  |  |  |  | decode_alignment_token($tok); | 
| 3974 | 152 | 100 |  |  |  | 361 | if ( $lev > $level_keep ) { | 
| 3975 | 83 |  |  |  |  | 153 | push @idel, $i; | 
| 3976 |  |  |  |  |  |  | } | 
| 3977 |  |  |  |  |  |  | } | 
| 3978 | 28 | 50 |  |  |  | 80 | if (@idel) { | 
| 3979 | 28 |  |  |  |  | 104 | delete_selected_tokens( $line, \@idel ); | 
| 3980 |  |  |  |  |  |  | } | 
| 3981 |  |  |  |  |  |  | } | 
| 3982 |  |  |  |  |  |  | } ## end loop to delete selected alignment tokens | 
| 3983 |  |  |  |  |  |  |  | 
| 3984 | 31 |  |  |  |  | 390 | return; | 
| 3985 |  |  |  |  |  |  | } ## end sub prune_alignment_tree | 
| 3986 |  |  |  |  |  |  |  | 
| 3987 |  |  |  |  |  |  | sub Dump_tree_groups { | 
| 3988 | 0 |  |  | 0 | 0 | 0 | my ( $rgroup, $msg ) = @_; | 
| 3989 |  |  |  |  |  |  |  | 
| 3990 |  |  |  |  |  |  | # Debug routine | 
| 3991 | 0 |  |  |  |  | 0 | print "$msg\n"; | 
| 3992 | 0 |  |  |  |  | 0 | local $LIST_SEPARATOR = ')('; | 
| 3993 | 0 |  |  |  |  | 0 | foreach my $item ( @{$rgroup} ) { | 
|  | 0 |  |  |  |  | 0 |  | 
| 3994 | 0 |  |  |  |  | 0 | my @fix = @{$item}; | 
|  | 0 |  |  |  |  | 0 |  | 
| 3995 | 0 | 0 |  |  |  | 0 | foreach my $val (@fix) { $val = "undef" unless defined $val; } | 
|  | 0 |  |  |  |  | 0 |  | 
| 3996 | 0 |  |  |  |  | 0 | $fix[4] = "..."; | 
| 3997 | 0 |  |  |  |  | 0 | print "(@fix)\n"; | 
| 3998 |  |  |  |  |  |  | } | 
| 3999 | 0 |  |  |  |  | 0 | return; | 
| 4000 |  |  |  |  |  |  | } ## end sub Dump_tree_groups | 
| 4001 |  |  |  |  |  |  |  | 
| 4002 |  |  |  |  |  |  | {    ## closure for sub is_marginal_match | 
| 4003 |  |  |  |  |  |  |  | 
| 4004 |  |  |  |  |  |  | my %is_if_or; | 
| 4005 |  |  |  |  |  |  | my %is_assignment; | 
| 4006 |  |  |  |  |  |  | my %is_good_alignment; | 
| 4007 |  |  |  |  |  |  |  | 
| 4008 |  |  |  |  |  |  | # This test did not give sufficiently better results to use as an update, | 
| 4009 |  |  |  |  |  |  | # but the flag is worth keeping as a starting point for future testing. | 
| 4010 | 39 |  |  | 39 |  | 363 | use constant TEST_MARGINAL_EQ_ALIGNMENT => 0; | 
|  | 39 |  |  |  |  | 108 |  | 
|  | 39 |  |  |  |  | 6292 |  | 
| 4011 |  |  |  |  |  |  |  | 
| 4012 |  |  |  |  |  |  | BEGIN { | 
| 4013 |  |  |  |  |  |  |  | 
| 4014 | 39 |  |  | 39 |  | 237 | my @q = qw( | 
| 4015 |  |  |  |  |  |  | if unless or || | 
| 4016 |  |  |  |  |  |  | ); | 
| 4017 | 39 |  |  |  |  | 210 | @is_if_or{@q} = (1) x scalar(@q); | 
| 4018 |  |  |  |  |  |  |  | 
| 4019 | 39 |  |  |  |  | 213 | @q = qw( | 
| 4020 |  |  |  |  |  |  | = **= += *= &= <<= &&= | 
| 4021 |  |  |  |  |  |  | -= /= |= >>= ||= //= | 
| 4022 |  |  |  |  |  |  | .= %= ^= | 
| 4023 |  |  |  |  |  |  | x= | 
| 4024 |  |  |  |  |  |  | ); | 
| 4025 | 39 |  |  |  |  | 587 | @is_assignment{@q} = (1) x scalar(@q); | 
| 4026 |  |  |  |  |  |  |  | 
| 4027 |  |  |  |  |  |  | # Vertically aligning on certain "good" tokens is usually okay | 
| 4028 |  |  |  |  |  |  | # so we can be less restrictive in marginal cases. | 
| 4029 | 39 |  |  |  |  | 235 | @q = qw( { ? => = ); | 
| 4030 | 39 |  |  |  |  | 107 | push @q, (','); | 
| 4031 | 39 |  |  |  |  | 227253 | @is_good_alignment{@q} = (1) x scalar(@q); | 
| 4032 |  |  |  |  |  |  | } ## end BEGIN | 
| 4033 |  |  |  |  |  |  |  | 
| 4034 |  |  |  |  |  |  | sub is_marginal_match { | 
| 4035 |  |  |  |  |  |  |  | 
| 4036 | 256 |  |  | 256 | 0 | 852 | my ( $line_0, $line_1, $group_level, $imax_align, $imax_prev ) = @_; | 
| 4037 |  |  |  |  |  |  |  | 
| 4038 |  |  |  |  |  |  | # Decide if we should undo some or all of the common alignments of a | 
| 4039 |  |  |  |  |  |  | # group of just two lines. | 
| 4040 |  |  |  |  |  |  |  | 
| 4041 |  |  |  |  |  |  | # Given: | 
| 4042 |  |  |  |  |  |  | #   $line_0 and $line_1 - the two lines | 
| 4043 |  |  |  |  |  |  | #   $group_level = the indentation level of the group being processed | 
| 4044 |  |  |  |  |  |  | #   $imax_align = the maximum index of the common alignment tokens | 
| 4045 |  |  |  |  |  |  | #                 of the two lines | 
| 4046 |  |  |  |  |  |  | #   $imax_prev  = the maximum index of the common alignment tokens | 
| 4047 |  |  |  |  |  |  | #                 with the line before $line_0 (=-1 of does not exist) | 
| 4048 |  |  |  |  |  |  |  | 
| 4049 |  |  |  |  |  |  | # Return: | 
| 4050 |  |  |  |  |  |  | #   $is_marginal = true if the two lines should NOT be fully aligned | 
| 4051 |  |  |  |  |  |  | #                = false if the two lines can remain fully aligned | 
| 4052 |  |  |  |  |  |  | #   $imax_align  = the index of the highest alignment token shared by | 
| 4053 |  |  |  |  |  |  | #                  these two lines to keep if the match is marginal. | 
| 4054 |  |  |  |  |  |  |  | 
| 4055 |  |  |  |  |  |  | # When we have an alignment group of just two lines like this, we are | 
| 4056 |  |  |  |  |  |  | # working in the twilight zone of what looks good and what looks bad. | 
| 4057 |  |  |  |  |  |  | # This routine is a collection of rules which work have been found to | 
| 4058 |  |  |  |  |  |  | # work fairly well, but it will need to be updated from time to time. | 
| 4059 |  |  |  |  |  |  |  | 
| 4060 | 256 |  |  |  |  | 515 | my $is_marginal = 0; | 
| 4061 |  |  |  |  |  |  |  | 
| 4062 |  |  |  |  |  |  | #--------------------------------------- | 
| 4063 |  |  |  |  |  |  | # Always align certain special cases ... | 
| 4064 |  |  |  |  |  |  | #--------------------------------------- | 
| 4065 | 256 | 100 | 100 |  |  | 2269 | if ( | 
|  |  |  | 100 |  |  |  |  | 
| 4066 |  |  |  |  |  |  |  | 
| 4067 |  |  |  |  |  |  | # always keep alignments of a terminal else or ternary | 
| 4068 |  |  |  |  |  |  | defined( $line_1->{'j_terminal_match'} ) | 
| 4069 |  |  |  |  |  |  |  | 
| 4070 |  |  |  |  |  |  | # always align lists | 
| 4071 |  |  |  |  |  |  | || $line_0->{'list_type'} | 
| 4072 |  |  |  |  |  |  |  | 
| 4073 |  |  |  |  |  |  | # always align hanging side comments | 
| 4074 |  |  |  |  |  |  | || $line_1->{'is_hanging_side_comment'} | 
| 4075 |  |  |  |  |  |  |  | 
| 4076 |  |  |  |  |  |  | ) | 
| 4077 |  |  |  |  |  |  | { | 
| 4078 | 127 |  |  |  |  | 435 | return ( $is_marginal, $imax_align ); | 
| 4079 |  |  |  |  |  |  | } | 
| 4080 |  |  |  |  |  |  |  | 
| 4081 | 129 |  |  |  |  | 366 | my $jmax_0           = $line_0->{'jmax'}; | 
| 4082 | 129 |  |  |  |  | 1008 | my $jmax_1           = $line_1->{'jmax'}; | 
| 4083 | 129 |  |  |  |  | 333 | my $rtokens_1        = $line_1->{'rtokens'}; | 
| 4084 | 129 |  |  |  |  | 282 | my $rtokens_0        = $line_0->{'rtokens'}; | 
| 4085 | 129 |  |  |  |  | 275 | my $rfield_lengths_0 = $line_0->{'rfield_lengths'}; | 
| 4086 | 129 |  |  |  |  | 290 | my $rfield_lengths_1 = $line_1->{'rfield_lengths'}; | 
| 4087 | 129 |  |  |  |  | 283 | my $rpatterns_0      = $line_0->{'rpatterns'}; | 
| 4088 | 129 |  |  |  |  | 285 | my $rpatterns_1      = $line_1->{'rpatterns'}; | 
| 4089 | 129 |  |  |  |  | 305 | my $imax_next        = $line_1->{'imax_pair'}; | 
| 4090 |  |  |  |  |  |  |  | 
| 4091 |  |  |  |  |  |  | # We will scan the alignment tokens and set a flag '$is_marginal' if | 
| 4092 |  |  |  |  |  |  | # it seems that the an alignment would look bad. | 
| 4093 | 129 |  |  |  |  | 314 | my $max_pad            = 0; | 
| 4094 | 129 |  |  |  |  | 262 | my $saw_good_alignment = 0; | 
| 4095 | 129 |  |  |  |  | 261 | my $saw_if_or;                # if we saw an 'if' or 'or' at group level | 
| 4096 | 129 |  |  |  |  | 308 | my $raw_tokb = EMPTY_STRING;  # first token seen at group level | 
| 4097 | 129 |  |  |  |  | 444 | my $jfirst_bad; | 
| 4098 |  |  |  |  |  |  | my $line_ending_fat_comma;    # is last token just a '=>' ? | 
| 4099 | 129 |  |  |  |  | 0 | my $j0_eq_pad; | 
| 4100 | 129 |  |  |  |  | 296 | my $j0_max_pad = 0; | 
| 4101 |  |  |  |  |  |  |  | 
| 4102 | 129 |  |  |  |  | 489 | foreach my $j ( 0 .. $jmax_1 - 2 ) { | 
| 4103 | 162 |  |  |  |  | 535 | my ( $raw_tok, $lev, $tag, $tok_count ) = | 
| 4104 |  |  |  |  |  |  | decode_alignment_token( $rtokens_1->[$j] ); | 
| 4105 | 162 | 100 | 66 |  |  | 1069 | if ( $raw_tok && $lev == $group_level ) { | 
| 4106 | 140 | 100 |  |  |  | 509 | if ( !$raw_tokb ) { $raw_tokb = $raw_tok } | 
|  | 119 |  |  |  |  | 295 |  | 
| 4107 | 140 |  | 100 |  |  | 692 | $saw_if_or ||= $is_if_or{$raw_tok}; | 
| 4108 |  |  |  |  |  |  | } | 
| 4109 |  |  |  |  |  |  |  | 
| 4110 |  |  |  |  |  |  | # When the first of the two lines ends in a bare '=>' this will | 
| 4111 |  |  |  |  |  |  | # probably be marginal match.  (For a bare =>, the next field length | 
| 4112 |  |  |  |  |  |  | # will be 2 or 3, depending on side comment) | 
| 4113 |  |  |  |  |  |  | $line_ending_fat_comma = | 
| 4114 | 162 |  | 100 |  |  | 1082 | $j == $jmax_1 - 2 | 
| 4115 |  |  |  |  |  |  | && $raw_tok eq '=>' | 
| 4116 |  |  |  |  |  |  | && $rfield_lengths_0->[ $j + 1 ] <= 3; | 
| 4117 |  |  |  |  |  |  |  | 
| 4118 | 162 |  |  |  |  | 465 | my $pad = $rfield_lengths_1->[$j] - $rfield_lengths_0->[$j]; | 
| 4119 | 162 | 100 |  |  |  | 516 | if ( $j == 0 ) { | 
| 4120 |  |  |  |  |  |  | $pad += $line_1->{'leading_space_count'} - | 
| 4121 | 124 |  |  |  |  | 386 | $line_0->{'leading_space_count'}; | 
| 4122 |  |  |  |  |  |  |  | 
| 4123 |  |  |  |  |  |  | # Remember the pad at a leading equals | 
| 4124 | 124 | 100 | 66 |  |  | 679 | if ( $raw_tok eq '=' && $lev == $group_level ) { | 
| 4125 | 73 |  |  |  |  | 163 | $j0_eq_pad = $pad; | 
| 4126 | 73 |  |  |  |  | 276 | $j0_max_pad = | 
| 4127 |  |  |  |  |  |  | 0.5 * ( $rfield_lengths_1->[0] + $rfield_lengths_0->[0] ); | 
| 4128 | 73 | 100 |  |  |  | 299 | $j0_max_pad = 4 if ( $j0_max_pad < 4 ); | 
| 4129 |  |  |  |  |  |  | } | 
| 4130 |  |  |  |  |  |  | } | 
| 4131 |  |  |  |  |  |  |  | 
| 4132 | 162 | 100 |  |  |  | 518 | if ( $pad < 0 )        { $pad     = -$pad } | 
|  | 36 |  |  |  |  | 117 |  | 
| 4133 | 162 | 100 |  |  |  | 496 | if ( $pad > $max_pad ) { $max_pad = $pad } | 
|  | 89 |  |  |  |  | 199 |  | 
| 4134 | 162 | 100 | 100 |  |  | 918 | if ( $is_good_alignment{$raw_tok} && !$line_ending_fat_comma ) { | 
| 4135 | 128 |  |  |  |  | 301 | $saw_good_alignment = 1; | 
| 4136 |  |  |  |  |  |  | } | 
| 4137 |  |  |  |  |  |  | else { | 
| 4138 | 34 | 100 |  |  |  | 124 | $jfirst_bad = $j unless defined($jfirst_bad); | 
| 4139 |  |  |  |  |  |  | } | 
| 4140 | 162 | 100 |  |  |  | 687 | if ( $rpatterns_0->[$j] ne $rpatterns_1->[$j] ) { | 
| 4141 |  |  |  |  |  |  |  | 
| 4142 |  |  |  |  |  |  | # Flag this as a marginal match since patterns differ. | 
| 4143 |  |  |  |  |  |  | # Normally, we will not allow just two lines to match if | 
| 4144 |  |  |  |  |  |  | # marginal. But we can allow matching in some specific cases. | 
| 4145 |  |  |  |  |  |  |  | 
| 4146 | 33 | 100 |  |  |  | 133 | $jfirst_bad  = $j if ( !defined($jfirst_bad) ); | 
| 4147 | 33 | 50 |  |  |  | 125 | $is_marginal = 1  if ( $is_marginal == 0 ); | 
| 4148 | 33 | 100 |  |  |  | 139 | if ( $raw_tok eq '=' ) { | 
| 4149 |  |  |  |  |  |  |  | 
| 4150 |  |  |  |  |  |  | # Here is an example of a marginal match: | 
| 4151 |  |  |  |  |  |  | #       $done{$$op} = 1; | 
| 4152 |  |  |  |  |  |  | #       $op         = compile_bblock($op); | 
| 4153 |  |  |  |  |  |  | # The left tokens are both identifiers, but | 
| 4154 |  |  |  |  |  |  | # one accesses a hash and the other doesn't. | 
| 4155 |  |  |  |  |  |  | # We'll let this be a tentative match and undo | 
| 4156 |  |  |  |  |  |  | # it later if we don't find more than 2 lines | 
| 4157 |  |  |  |  |  |  | # in the group. | 
| 4158 | 12 |  |  |  |  | 37 | $is_marginal = 2; | 
| 4159 |  |  |  |  |  |  | } | 
| 4160 |  |  |  |  |  |  | } | 
| 4161 |  |  |  |  |  |  | } | 
| 4162 |  |  |  |  |  |  |  | 
| 4163 | 129 | 50 | 66 |  |  | 733 | $is_marginal = 1 if ( $is_marginal == 0 && $line_ending_fat_comma ); | 
| 4164 |  |  |  |  |  |  |  | 
| 4165 |  |  |  |  |  |  | # Turn off the "marginal match" flag in some cases... | 
| 4166 |  |  |  |  |  |  | # A "marginal match" occurs when the alignment tokens agree | 
| 4167 |  |  |  |  |  |  | # but there are differences in the other tokens (patterns). | 
| 4168 |  |  |  |  |  |  | # If we leave the marginal match flag set, then the rule is that we | 
| 4169 |  |  |  |  |  |  | # will align only if there are more than two lines in the group. | 
| 4170 |  |  |  |  |  |  | # We will turn of the flag if we almost have a match | 
| 4171 |  |  |  |  |  |  | # and either we have seen a good alignment token or we | 
| 4172 |  |  |  |  |  |  | # just need a small pad (2 spaces) to fit.  These rules are | 
| 4173 |  |  |  |  |  |  | # the result of experimentation.  Tokens which misaligned by just | 
| 4174 |  |  |  |  |  |  | # one or two characters are annoying.  On the other hand, | 
| 4175 |  |  |  |  |  |  | # large gaps to less important alignment tokens are also annoying. | 
| 4176 | 129 | 100 | 100 |  |  | 541 | if ( $is_marginal == 1 | 
|  |  |  | 100 |  |  |  |  | 
| 4177 |  |  |  |  |  |  | && ( $saw_good_alignment || $max_pad < 3 ) ) | 
| 4178 |  |  |  |  |  |  | { | 
| 4179 | 17 |  |  |  |  | 47 | $is_marginal = 0; | 
| 4180 |  |  |  |  |  |  | } | 
| 4181 |  |  |  |  |  |  |  | 
| 4182 |  |  |  |  |  |  | # We will use the line endings to help decide on alignments... | 
| 4183 |  |  |  |  |  |  | # See if the lines end with semicolons... | 
| 4184 | 129 |  |  |  |  | 351 | my $sc_term0; | 
| 4185 |  |  |  |  |  |  | my $sc_term1; | 
| 4186 | 129 | 50 | 33 |  |  | 739 | if ( $jmax_0 < 1 || $jmax_1 < 1 ) { | 
| 4187 |  |  |  |  |  |  |  | 
| 4188 |  |  |  |  |  |  | # shouldn't happen | 
| 4189 |  |  |  |  |  |  | } | 
| 4190 |  |  |  |  |  |  | else { | 
| 4191 | 129 |  |  |  |  | 412 | my $pat0 = $rpatterns_0->[ $jmax_0 - 1 ]; | 
| 4192 | 129 |  |  |  |  | 387 | my $pat1 = $rpatterns_1->[ $jmax_1 - 1 ]; | 
| 4193 | 129 |  |  |  |  | 838 | $sc_term0 = $pat0 =~ /;b?$/; | 
| 4194 | 129 |  |  |  |  | 580 | $sc_term1 = $pat1 =~ /;b?$/; | 
| 4195 |  |  |  |  |  |  | } | 
| 4196 |  |  |  |  |  |  |  | 
| 4197 | 129 | 100 | 100 |  |  | 820 | if ( !$is_marginal && !$sc_term0 ) { | 
| 4198 |  |  |  |  |  |  |  | 
| 4199 |  |  |  |  |  |  | # First line of assignment should be semicolon terminated. | 
| 4200 |  |  |  |  |  |  | # For example, do not align here: | 
| 4201 |  |  |  |  |  |  | #  $$href{-NUM_TEXT_FILES} = $$href{-NUM_BINARY_FILES} = | 
| 4202 |  |  |  |  |  |  | #    $$href{-NUM_DIRS} = 0; | 
| 4203 | 30 | 100 |  |  |  | 177 | if ( $is_assignment{$raw_tokb} ) { | 
| 4204 | 1 |  |  |  |  | 4 | $is_marginal = 1; | 
| 4205 |  |  |  |  |  |  | } | 
| 4206 |  |  |  |  |  |  | } | 
| 4207 |  |  |  |  |  |  |  | 
| 4208 |  |  |  |  |  |  | # Try to avoid some undesirable alignments of opening tokens | 
| 4209 |  |  |  |  |  |  | # for example, the space between grep and { here: | 
| 4210 |  |  |  |  |  |  | #  return map { ( $_ => $_ ) } | 
| 4211 |  |  |  |  |  |  | #    grep     { /$handles/ } $self->_get_delegate_method_list; | 
| 4212 |  |  |  |  |  |  | $is_marginal ||= | 
| 4213 | 129 |  | 100 |  |  | 1382 | ( $raw_tokb eq '(' || $raw_tokb eq '{' ) | 
|  |  |  | 100 |  |  |  |  | 
| 4214 |  |  |  |  |  |  | && $jmax_1 == 2 | 
| 4215 |  |  |  |  |  |  | && $sc_term0 ne $sc_term1; | 
| 4216 |  |  |  |  |  |  |  | 
| 4217 |  |  |  |  |  |  | #--------------------------------------- | 
| 4218 |  |  |  |  |  |  | # return if this is not a marginal match | 
| 4219 |  |  |  |  |  |  | #--------------------------------------- | 
| 4220 | 129 | 100 |  |  |  | 442 | if ( !$is_marginal ) { | 
| 4221 | 111 |  |  |  |  | 534 | return ( $is_marginal, $imax_align ); | 
| 4222 |  |  |  |  |  |  | } | 
| 4223 |  |  |  |  |  |  |  | 
| 4224 |  |  |  |  |  |  | # Undo the marginal match flag in certain cases, | 
| 4225 |  |  |  |  |  |  |  | 
| 4226 |  |  |  |  |  |  | # Two lines with a leading equals-like operator are allowed to | 
| 4227 |  |  |  |  |  |  | # align if the patterns to the left of the equals are the same. | 
| 4228 |  |  |  |  |  |  | # For example the following two lines are a marginal match but have | 
| 4229 |  |  |  |  |  |  | # the same left side patterns, so we will align the equals. | 
| 4230 |  |  |  |  |  |  | #     my $orig = my $format = "^<<<<< ~~\n"; | 
| 4231 |  |  |  |  |  |  | #     my $abc  = "abc"; | 
| 4232 |  |  |  |  |  |  | # But these have a different left pattern so they will not be | 
| 4233 |  |  |  |  |  |  | # aligned | 
| 4234 |  |  |  |  |  |  | #     $xmldoc .= $`; | 
| 4235 |  |  |  |  |  |  | #     $self->{'leftovers'} .= "<bx-seq:seq" . $'; | 
| 4236 |  |  |  |  |  |  |  | 
| 4237 |  |  |  |  |  |  | # First line semicolon terminated but second not, usually ok: | 
| 4238 |  |  |  |  |  |  | #               my $want = "'ab', 'a', 'b'"; | 
| 4239 |  |  |  |  |  |  | #               my $got  = join( ", ", | 
| 4240 |  |  |  |  |  |  | #                    map { defined($_) ? "'$_'" : "undef" } | 
| 4241 |  |  |  |  |  |  | #                          @got ); | 
| 4242 |  |  |  |  |  |  | #  First line not semicolon terminated, Not OK to match: | 
| 4243 |  |  |  |  |  |  | #   $$href{-NUM_TEXT_FILES} = $$href{-NUM_BINARY_FILES} = | 
| 4244 |  |  |  |  |  |  | #      $$href{-NUM_DIRS} = 0; | 
| 4245 | 18 |  |  |  |  | 54 | my $pat0 = $rpatterns_0->[0]; | 
| 4246 | 18 |  |  |  |  | 46 | my $pat1 = $rpatterns_1->[0]; | 
| 4247 |  |  |  |  |  |  |  | 
| 4248 |  |  |  |  |  |  | #--------------------------------------------------------- | 
| 4249 |  |  |  |  |  |  | # Turn off the marginal flag for some types of assignments | 
| 4250 |  |  |  |  |  |  | #--------------------------------------------------------- | 
| 4251 | 18 | 100 |  |  |  | 98 | if ( $is_assignment{$raw_tokb} ) { | 
|  |  | 50 |  |  |  |  |  | 
|  |  | 50 |  |  |  |  |  | 
| 4252 |  |  |  |  |  |  |  | 
| 4253 |  |  |  |  |  |  | # undo marginal flag if first line is semicolon terminated | 
| 4254 |  |  |  |  |  |  | # and leading patters match | 
| 4255 | 13 | 100 |  |  |  | 43 | if ($sc_term0) {    # && $sc_term1) { | 
| 4256 | 12 |  |  |  |  | 27 | $is_marginal = $pat0 ne $pat1; | 
| 4257 |  |  |  |  |  |  | } | 
| 4258 |  |  |  |  |  |  | } | 
| 4259 |  |  |  |  |  |  | elsif ( $raw_tokb eq '=>' ) { | 
| 4260 |  |  |  |  |  |  |  | 
| 4261 |  |  |  |  |  |  | # undo marginal flag if patterns match | 
| 4262 | 0 |  | 0 |  |  | 0 | $is_marginal = $pat0 ne $pat1 || $line_ending_fat_comma; | 
| 4263 |  |  |  |  |  |  | } | 
| 4264 |  |  |  |  |  |  | elsif ( $raw_tokb eq '=~' ) { | 
| 4265 |  |  |  |  |  |  |  | 
| 4266 |  |  |  |  |  |  | # undo marginal flag if both lines are semicolon terminated | 
| 4267 |  |  |  |  |  |  | # and leading patters match | 
| 4268 | 0 | 0 | 0 |  |  | 0 | if ( $sc_term1 && $sc_term0 ) { | 
| 4269 | 0 |  |  |  |  | 0 | $is_marginal = $pat0 ne $pat1; | 
| 4270 |  |  |  |  |  |  | } | 
| 4271 |  |  |  |  |  |  | } | 
| 4272 |  |  |  |  |  |  | else { | 
| 4273 |  |  |  |  |  |  | ##ok: (none of the above) | 
| 4274 |  |  |  |  |  |  | } | 
| 4275 |  |  |  |  |  |  |  | 
| 4276 |  |  |  |  |  |  | #----------------------------------------------------- | 
| 4277 |  |  |  |  |  |  | # Turn off the marginal flag if we saw an 'if' or 'or' | 
| 4278 |  |  |  |  |  |  | #----------------------------------------------------- | 
| 4279 |  |  |  |  |  |  |  | 
| 4280 |  |  |  |  |  |  | # A trailing 'if' and 'or' often gives a good alignment | 
| 4281 |  |  |  |  |  |  | # For example, we can align these: | 
| 4282 |  |  |  |  |  |  | #  return -1     if $_[0] =~ m/^CHAPT|APPENDIX/; | 
| 4283 |  |  |  |  |  |  | #  return $1 + 0 if $_[0] =~ m/^SECT(\d*)$/; | 
| 4284 |  |  |  |  |  |  |  | 
| 4285 |  |  |  |  |  |  | # or | 
| 4286 |  |  |  |  |  |  | #  $d_in_m[2] = 29          if ( &Date_LeapYear($y) ); | 
| 4287 |  |  |  |  |  |  | #  $d         = $d_in_m[$m] if ( $d > $d_in_m[$m] ); | 
| 4288 |  |  |  |  |  |  |  | 
| 4289 | 18 | 100 |  |  |  | 70 | if ($saw_if_or) { | 
| 4290 |  |  |  |  |  |  |  | 
| 4291 |  |  |  |  |  |  | # undo marginal flag if both lines are semicolon terminated | 
| 4292 | 4 | 50 | 33 |  |  | 26 | if ( $sc_term0 && $sc_term1 ) { | 
| 4293 | 4 |  |  |  |  | 11 | $is_marginal = 0; | 
| 4294 |  |  |  |  |  |  | } | 
| 4295 |  |  |  |  |  |  | } | 
| 4296 |  |  |  |  |  |  |  | 
| 4297 |  |  |  |  |  |  | # For a marginal match, only keep matches before the first 'bad' match | 
| 4298 | 18 | 50 | 100 |  |  | 146 | if (   $is_marginal | 
|  |  |  | 66 |  |  |  |  | 
| 4299 |  |  |  |  |  |  | && defined($jfirst_bad) | 
| 4300 |  |  |  |  |  |  | && $imax_align > $jfirst_bad - 1 ) | 
| 4301 |  |  |  |  |  |  | { | 
| 4302 | 0 |  |  |  |  | 0 | $imax_align = $jfirst_bad - 1; | 
| 4303 |  |  |  |  |  |  | } | 
| 4304 |  |  |  |  |  |  |  | 
| 4305 |  |  |  |  |  |  | #---------------------------------------------------------- | 
| 4306 |  |  |  |  |  |  | # Allow sweep to match lines with leading '=' in some cases | 
| 4307 |  |  |  |  |  |  | #---------------------------------------------------------- | 
| 4308 | 18 | 100 | 66 |  |  | 136 | if ( $imax_align < 0 && defined($j0_eq_pad) ) { | 
| 4309 |  |  |  |  |  |  |  | 
| 4310 | 13 | 0 | 50 |  |  | 127 | if ( | 
|  |  |  | 33 |  |  |  |  | 
|  |  |  | 33 |  |  |  |  | 
| 4311 |  |  |  |  |  |  |  | 
| 4312 |  |  |  |  |  |  | # If there is a following line with leading equals, or | 
| 4313 |  |  |  |  |  |  | # preceding line with leading equals, then let the sweep align | 
| 4314 |  |  |  |  |  |  | # them without restriction.  For example, the first two lines | 
| 4315 |  |  |  |  |  |  | # here are a marginal match, but they are followed by a line | 
| 4316 |  |  |  |  |  |  | # with leading equals, so the sweep-lr logic can align all of | 
| 4317 |  |  |  |  |  |  | # the lines: | 
| 4318 |  |  |  |  |  |  |  | 
| 4319 |  |  |  |  |  |  | #  $date[1] = $month_to_num{ $date[1] };            # <--line_0 | 
| 4320 |  |  |  |  |  |  | #  @xdate   = split( /[:\/\s]/, $log->field('t') ); # <--line_1 | 
| 4321 |  |  |  |  |  |  | #  $day     = sprintf( "%04d/%02d/%02d", @date[ 2, 1, 0 ] ); | 
| 4322 |  |  |  |  |  |  | #  $time    = sprintf( "%02d:%02d:%02d", @date[ 3 .. 5 ] ); | 
| 4323 |  |  |  |  |  |  |  | 
| 4324 |  |  |  |  |  |  | # Likewise, if we reverse the two pairs we want the same result | 
| 4325 |  |  |  |  |  |  |  | 
| 4326 |  |  |  |  |  |  | #  $day     = sprintf( "%04d/%02d/%02d", @date[ 2, 1, 0 ] ); | 
| 4327 |  |  |  |  |  |  | #  $time    = sprintf( "%02d:%02d:%02d", @date[ 3 .. 5 ] ); | 
| 4328 |  |  |  |  |  |  | #  $date[1] = $month_to_num{ $date[1] };            # <--line_0 | 
| 4329 |  |  |  |  |  |  | #  @xdate   = split( /[:\/\s]/, $log->field('t') ); # <--line_1 | 
| 4330 |  |  |  |  |  |  |  | 
| 4331 |  |  |  |  |  |  | ( | 
| 4332 |  |  |  |  |  |  | $imax_next >= 0 | 
| 4333 |  |  |  |  |  |  | || $imax_prev >= 0 | 
| 4334 |  |  |  |  |  |  | || TEST_MARGINAL_EQ_ALIGNMENT | 
| 4335 |  |  |  |  |  |  | ) | 
| 4336 |  |  |  |  |  |  | && $j0_eq_pad >= -$j0_max_pad | 
| 4337 |  |  |  |  |  |  | && $j0_eq_pad <= $j0_max_pad | 
| 4338 |  |  |  |  |  |  | ) | 
| 4339 |  |  |  |  |  |  | { | 
| 4340 |  |  |  |  |  |  |  | 
| 4341 |  |  |  |  |  |  | # But do not do this if there is a comma before the '='. | 
| 4342 |  |  |  |  |  |  | # For example, the first two lines below have commas and | 
| 4343 |  |  |  |  |  |  | # therefore are not allowed to align with lines 3 & 4: | 
| 4344 |  |  |  |  |  |  |  | 
| 4345 |  |  |  |  |  |  | # my ( $x, $y ) = $self->Size();                      #<--line_0 | 
| 4346 |  |  |  |  |  |  | # my ( $left, $top, $right, $bottom ) = $self->Window(); #<--l_1 | 
| 4347 |  |  |  |  |  |  | # my $vx = $right - $left; | 
| 4348 |  |  |  |  |  |  | # my $vy = $bottom - $top; | 
| 4349 |  |  |  |  |  |  |  | 
| 4350 | 0 | 0 | 0 |  |  | 0 | if ( $rpatterns_0->[0] !~ /,/ && $rpatterns_1->[0] !~ /,/ ) { | 
| 4351 | 0 |  |  |  |  | 0 | $imax_align = 0; | 
| 4352 |  |  |  |  |  |  | } | 
| 4353 |  |  |  |  |  |  | } | 
| 4354 |  |  |  |  |  |  | } | 
| 4355 |  |  |  |  |  |  |  | 
| 4356 | 18 |  |  |  |  | 88 | return ( $is_marginal, $imax_align ); | 
| 4357 |  |  |  |  |  |  | } ## end sub is_marginal_match | 
| 4358 |  |  |  |  |  |  | } ## end closure for sub is_marginal_match | 
| 4359 |  |  |  |  |  |  |  | 
| 4360 |  |  |  |  |  |  | sub get_extra_leading_spaces { | 
| 4361 |  |  |  |  |  |  |  | 
| 4362 | 376 |  |  | 376 | 0 | 1231 | my ( $rlines, $rgroups ) = @_; | 
| 4363 |  |  |  |  |  |  |  | 
| 4364 |  |  |  |  |  |  | #---------------------------------------------------------- | 
| 4365 |  |  |  |  |  |  | # Define any extra indentation space (for the -lp option). | 
| 4366 |  |  |  |  |  |  | # Here is why: | 
| 4367 |  |  |  |  |  |  | # If a list has side comments, sub scan_list must dump the | 
| 4368 |  |  |  |  |  |  | # list before it sees everything.  When this happens, it sets | 
| 4369 |  |  |  |  |  |  | # the indentation to the standard scheme, but notes how | 
| 4370 |  |  |  |  |  |  | # many spaces it would have liked to use.  We may be able | 
| 4371 |  |  |  |  |  |  | # to recover that space here in the event that all of the | 
| 4372 |  |  |  |  |  |  | # lines of a list are back together again. | 
| 4373 |  |  |  |  |  |  | #---------------------------------------------------------- | 
| 4374 |  |  |  |  |  |  |  | 
| 4375 | 376 | 50 | 33 |  |  | 692 | return 0 if ( !@{$rlines} || !@{$rgroups} ); | 
|  | 376 |  |  |  |  | 2550 |  | 
|  | 376 |  |  |  |  | 1406 |  | 
| 4376 |  |  |  |  |  |  |  | 
| 4377 | 376 |  |  |  |  | 1065 | my $object = $rlines->[0]->{'indentation'}; | 
| 4378 | 376 | 100 |  |  |  | 1242 | return 0 if ( !ref($object) ); | 
| 4379 | 58 |  |  |  |  | 120 | my $extra_leading_spaces            = 0; | 
| 4380 | 58 |  |  |  |  | 205 | my $extra_indentation_spaces_wanted = get_recoverable_spaces($object); | 
| 4381 | 58 | 100 |  |  |  | 241 | return ($extra_leading_spaces) if ( !$extra_indentation_spaces_wanted ); | 
| 4382 |  |  |  |  |  |  |  | 
| 4383 | 13 |  |  |  |  | 42 | my $min_spaces = $extra_indentation_spaces_wanted; | 
| 4384 | 13 | 50 |  |  |  | 64 | if ( $min_spaces > 0 ) { $min_spaces = 0 } | 
|  | 13 |  |  |  |  | 28 |  | 
| 4385 |  |  |  |  |  |  |  | 
| 4386 |  |  |  |  |  |  | # loop over all groups | 
| 4387 | 13 |  |  |  |  | 31 | my $ng      = -1; | 
| 4388 | 13 |  |  |  |  | 24 | my $ngroups = @{$rgroups}; | 
|  | 13 |  |  |  |  | 31 |  | 
| 4389 | 13 |  |  |  |  | 35 | foreach my $item ( @{$rgroups} ) { | 
|  | 13 |  |  |  |  | 41 |  | 
| 4390 | 33 |  |  |  |  | 63 | $ng++; | 
| 4391 | 33 |  |  |  |  | 95 | my ( $jbeg, $jend ) = @{$item}; | 
|  | 33 |  |  |  |  | 81 |  | 
| 4392 | 33 |  |  |  |  | 94 | foreach my $j ( $jbeg .. $jend ) { | 
| 4393 | 44 | 100 |  |  |  | 113 | next if ( $j == 0 ); | 
| 4394 |  |  |  |  |  |  |  | 
| 4395 |  |  |  |  |  |  | # all indentation objects must be the same | 
| 4396 | 31 | 100 |  |  |  | 132 | if ( $object != $rlines->[$j]->{'indentation'} ) { | 
| 4397 | 1 |  |  |  |  | 3 | return 0; | 
| 4398 |  |  |  |  |  |  | } | 
| 4399 |  |  |  |  |  |  | } | 
| 4400 |  |  |  |  |  |  |  | 
| 4401 |  |  |  |  |  |  | # find the maximum space without exceeding the line length for this group | 
| 4402 | 32 |  |  |  |  | 116 | my $avail = $rlines->[$jbeg]->get_available_space_on_right(); | 
| 4403 | 32 | 100 |  |  |  | 127 | my $spaces = | 
| 4404 |  |  |  |  |  |  | ( $avail > $extra_indentation_spaces_wanted ) | 
| 4405 |  |  |  |  |  |  | ? $extra_indentation_spaces_wanted | 
| 4406 |  |  |  |  |  |  | : $avail; | 
| 4407 |  |  |  |  |  |  |  | 
| 4408 |  |  |  |  |  |  | #-------------------------------------------------------- | 
| 4409 |  |  |  |  |  |  | # Note: min spaces can be negative; for example with -gnu | 
| 4410 |  |  |  |  |  |  | # f( | 
| 4411 |  |  |  |  |  |  | #   do { 1; !!(my $x = bless []); } | 
| 4412 |  |  |  |  |  |  | #  ); | 
| 4413 |  |  |  |  |  |  | #-------------------------------------------------------- | 
| 4414 |  |  |  |  |  |  | # The following rule is needed to match older formatting: | 
| 4415 |  |  |  |  |  |  | # For multiple groups, we will keep spaces non-negative. | 
| 4416 |  |  |  |  |  |  | # For a single group, we will allow a negative space. | 
| 4417 | 32 | 50 | 66 |  |  | 141 | if ( $ngroups > 1 && $spaces < 0 ) { $spaces = 0 } | 
|  | 0 |  |  |  |  | 0 |  | 
| 4418 |  |  |  |  |  |  |  | 
| 4419 |  |  |  |  |  |  | # update the minimum spacing | 
| 4420 | 32 | 100 | 66 |  |  | 150 | if ( $ng == 0 || $spaces < $extra_leading_spaces ) { | 
| 4421 | 13 |  |  |  |  | 35 | $extra_leading_spaces = $spaces; | 
| 4422 |  |  |  |  |  |  | } | 
| 4423 |  |  |  |  |  |  | } | 
| 4424 |  |  |  |  |  |  |  | 
| 4425 |  |  |  |  |  |  | # update the indentation object because with -icp the terminal | 
| 4426 |  |  |  |  |  |  | # ');' will use the same adjustment. | 
| 4427 | 12 |  |  |  |  | 176 | $object->permanently_decrease_available_spaces( -$extra_leading_spaces ); | 
| 4428 | 12 |  |  |  |  | 34 | return $extra_leading_spaces; | 
| 4429 |  |  |  |  |  |  | } ## end sub get_extra_leading_spaces | 
| 4430 |  |  |  |  |  |  |  | 
| 4431 |  |  |  |  |  |  | sub forget_side_comment { | 
| 4432 | 111 |  |  | 111 | 0 | 368 | my ($self) = @_; | 
| 4433 | 111 |  |  |  |  | 283 | $self->[_last_side_comment_column_] = 0; | 
| 4434 | 111 |  |  |  |  | 228 | return; | 
| 4435 |  |  |  |  |  |  | } | 
| 4436 |  |  |  |  |  |  |  | 
| 4437 |  |  |  |  |  |  | sub is_good_side_comment_column { | 
| 4438 | 199 |  |  | 199 | 0 | 609 | my ( $self, $line, $line_number, $level, $num5 ) = @_; | 
| 4439 |  |  |  |  |  |  |  | 
| 4440 |  |  |  |  |  |  | # Upon encountering the first side comment of a group, decide if | 
| 4441 |  |  |  |  |  |  | # a previous side comment should be forgotten.  This involves | 
| 4442 |  |  |  |  |  |  | # checking several rules. | 
| 4443 |  |  |  |  |  |  |  | 
| 4444 |  |  |  |  |  |  | # Return true to KEEP old comment location | 
| 4445 |  |  |  |  |  |  | # Return false to FORGET old comment location | 
| 4446 | 199 |  |  |  |  | 383 | my $KEEP   = 1; | 
| 4447 | 199 |  |  |  |  | 373 | my $FORGET = 0; | 
| 4448 |  |  |  |  |  |  |  | 
| 4449 | 199 |  |  |  |  | 412 | my $rfields                 = $line->{'rfields'}; | 
| 4450 | 199 |  |  |  |  | 425 | my $is_hanging_side_comment = $line->{'is_hanging_side_comment'}; | 
| 4451 |  |  |  |  |  |  |  | 
| 4452 |  |  |  |  |  |  | # RULE1: Never forget comment before a hanging side comment | 
| 4453 | 199 | 100 |  |  |  | 556 | return $KEEP if ($is_hanging_side_comment); | 
| 4454 |  |  |  |  |  |  |  | 
| 4455 |  |  |  |  |  |  | # RULE2: Forget a side comment after a short line difference, | 
| 4456 |  |  |  |  |  |  | # where 'short line difference' is computed from a formula. | 
| 4457 |  |  |  |  |  |  | # Using a smooth formula helps minimize sudden large changes. | 
| 4458 | 189 |  |  |  |  | 470 | my $line_diff = $line_number - $self->[_last_side_comment_line_number_]; | 
| 4459 | 189 |  |  |  |  | 473 | my $alev_diff = abs( $level - $self->[_last_side_comment_level_] ); | 
| 4460 |  |  |  |  |  |  |  | 
| 4461 |  |  |  |  |  |  | # '$num5' is the number of comments in the first 5 lines after the first | 
| 4462 |  |  |  |  |  |  | # comment.  It is needed to keep a compact group of side comments from | 
| 4463 |  |  |  |  |  |  | # being influenced by a more distant side comment. | 
| 4464 | 189 | 50 |  |  |  | 521 | $num5 = 1 if ( !$num5 ); | 
| 4465 |  |  |  |  |  |  |  | 
| 4466 |  |  |  |  |  |  | # Some values: | 
| 4467 |  |  |  |  |  |  |  | 
| 4468 |  |  |  |  |  |  | #        $adiff  $num5   $short_diff | 
| 4469 |  |  |  |  |  |  | #        0       *       12 | 
| 4470 |  |  |  |  |  |  | #        1       1       6 | 
| 4471 |  |  |  |  |  |  | #        1       2       4 | 
| 4472 |  |  |  |  |  |  | #        1       3       3 | 
| 4473 |  |  |  |  |  |  | #        1       4       2 | 
| 4474 |  |  |  |  |  |  | #        2       1       4 | 
| 4475 |  |  |  |  |  |  | #        2       2       2 | 
| 4476 |  |  |  |  |  |  | #        2       3       1 | 
| 4477 |  |  |  |  |  |  | #        3       1       3 | 
| 4478 |  |  |  |  |  |  | #        3       2       1 | 
| 4479 |  |  |  |  |  |  |  | 
| 4480 | 189 |  |  |  |  | 549 | my $short_diff = SC_LONG_LINE_DIFF / ( 1 + $alev_diff * $num5 ); | 
| 4481 |  |  |  |  |  |  |  | 
| 4482 | 189 | 100 | 100 |  |  | 1057 | return $FORGET | 
| 4483 |  |  |  |  |  |  | if ( $line_diff > $short_diff | 
| 4484 |  |  |  |  |  |  | || !$self->[_rOpts_valign_side_comments_] ); | 
| 4485 |  |  |  |  |  |  |  | 
| 4486 |  |  |  |  |  |  | # RULE3: Forget a side comment if this line is at lower level and | 
| 4487 |  |  |  |  |  |  | # ends a block | 
| 4488 | 122 |  |  |  |  | 297 | my $last_sc_level = $self->[_last_side_comment_level_]; | 
| 4489 |  |  |  |  |  |  | return $FORGET | 
| 4490 |  |  |  |  |  |  | if ( $level < $last_sc_level | 
| 4491 | 122 | 100 | 100 |  |  | 688 | && $is_closing_block_type{ substr( $rfields->[0], 0, 1 ) } ); | 
| 4492 |  |  |  |  |  |  |  | 
| 4493 |  |  |  |  |  |  | # RULE 4: Forget the last side comment if this comment might join a cached | 
| 4494 |  |  |  |  |  |  | # line ... | 
| 4495 | 104 | 100 |  |  |  | 503 | if ( my $cached_line_type = get_cached_line_type() ) { | 
| 4496 |  |  |  |  |  |  |  | 
| 4497 |  |  |  |  |  |  | # ... otherwise side comment alignment will get messed up. | 
| 4498 |  |  |  |  |  |  | # For example, in the following test script | 
| 4499 |  |  |  |  |  |  | # with using 'perltidy -sct -act=2', the last comment would try to | 
| 4500 |  |  |  |  |  |  | # align with the previous and then be in the wrong column when | 
| 4501 |  |  |  |  |  |  | # the lines are combined: | 
| 4502 |  |  |  |  |  |  |  | 
| 4503 |  |  |  |  |  |  | # foreach $line ( | 
| 4504 |  |  |  |  |  |  | #    [0, 1, 2], [3, 4, 5], [6, 7, 8],    # rows | 
| 4505 |  |  |  |  |  |  | #    [0, 3, 6], [1, 4, 7], [2, 5, 8],    # columns | 
| 4506 |  |  |  |  |  |  | #    [0, 4, 8], [2, 4, 6] | 
| 4507 |  |  |  |  |  |  | #  )                                     # diagonals | 
| 4508 | 4 | 50 | 33 |  |  | 26 | return $FORGET | 
| 4509 |  |  |  |  |  |  | if ( $cached_line_type == 2 || $cached_line_type == 4 ); | 
| 4510 |  |  |  |  |  |  | } | 
| 4511 |  |  |  |  |  |  |  | 
| 4512 |  |  |  |  |  |  | # Otherwise, keep it alive | 
| 4513 | 104 |  |  |  |  | 276 | return $KEEP; | 
| 4514 |  |  |  |  |  |  | } ## end sub is_good_side_comment_column | 
| 4515 |  |  |  |  |  |  |  | 
| 4516 |  |  |  |  |  |  | sub align_side_comments { | 
| 4517 |  |  |  |  |  |  |  | 
| 4518 | 199 |  |  | 199 | 0 | 541 | my ( $self, $rlines, $rgroups ) = @_; | 
| 4519 |  |  |  |  |  |  |  | 
| 4520 |  |  |  |  |  |  | # Align any side comments in this batch of lines | 
| 4521 |  |  |  |  |  |  |  | 
| 4522 |  |  |  |  |  |  | # Given: | 
| 4523 |  |  |  |  |  |  | #  $rlines  - the lines | 
| 4524 |  |  |  |  |  |  | #  $rgroups - the partition of the lines into groups | 
| 4525 |  |  |  |  |  |  | # | 
| 4526 |  |  |  |  |  |  | # We will be working group-by-group because all side comments | 
| 4527 |  |  |  |  |  |  | # (real or fake) in each group are already aligned. So we just have | 
| 4528 |  |  |  |  |  |  | # to make alignments between groups wherever possible. | 
| 4529 |  |  |  |  |  |  |  | 
| 4530 |  |  |  |  |  |  | # An unusual aspect is that within each group we have aligned both real | 
| 4531 |  |  |  |  |  |  | # and fake side comments.  This has the consequence that the lengths of | 
| 4532 |  |  |  |  |  |  | # long lines without real side comments can cause 'push' all side comments | 
| 4533 |  |  |  |  |  |  | # to the right.  This seems unusual, but testing with and without this | 
| 4534 |  |  |  |  |  |  | # feature shows that it is usually better this way.  Otherwise, side | 
| 4535 |  |  |  |  |  |  | # comments can be hidden between long lines without side comments and | 
| 4536 |  |  |  |  |  |  | # thus be harder to read. | 
| 4537 |  |  |  |  |  |  |  | 
| 4538 | 199 |  |  |  |  | 476 | my $group_level        = $self->[_group_level_]; | 
| 4539 | 199 |  | 100 |  |  | 842 | my $continuing_sc_flow = $self->[_last_side_comment_length_] > 0 | 
| 4540 |  |  |  |  |  |  | && $group_level == $self->[_last_level_written_]; | 
| 4541 |  |  |  |  |  |  |  | 
| 4542 |  |  |  |  |  |  | # Find groups with side comments, and remember the first nonblank comment | 
| 4543 | 199 |  |  |  |  | 437 | my $j_sc_beg; | 
| 4544 |  |  |  |  |  |  | my @todo; | 
| 4545 | 199 |  |  |  |  | 384 | my $ng = -1; | 
| 4546 | 199 |  |  |  |  | 412 | foreach my $item ( @{$rgroups} ) { | 
|  | 199 |  |  |  |  | 509 |  | 
| 4547 | 312 |  |  |  |  | 502 | $ng++; | 
| 4548 | 312 |  |  |  |  | 521 | my ( $jbeg, $jend ) = @{$item}; | 
|  | 312 |  |  |  |  | 685 |  | 
| 4549 | 312 |  |  |  |  | 742 | foreach my $j ( $jbeg .. $jend ) { | 
| 4550 | 346 |  |  |  |  | 684 | my $line = $rlines->[$j]; | 
| 4551 | 346 |  |  |  |  | 622 | my $jmax = $line->{'jmax'}; | 
| 4552 | 346 | 100 |  |  |  | 995 | if ( $line->{'rfield_lengths'}->[$jmax] ) { | 
| 4553 |  |  |  |  |  |  |  | 
| 4554 |  |  |  |  |  |  | # this group has a line with a side comment | 
| 4555 | 228 |  |  |  |  | 551 | push @todo, $ng; | 
| 4556 | 228 | 100 |  |  |  | 936 | if ( !defined($j_sc_beg) ) { | 
| 4557 | 199 |  |  |  |  | 377 | $j_sc_beg = $j; | 
| 4558 |  |  |  |  |  |  | } | 
| 4559 | 228 |  |  |  |  | 558 | last; | 
| 4560 |  |  |  |  |  |  | } | 
| 4561 |  |  |  |  |  |  | } | 
| 4562 |  |  |  |  |  |  | } | 
| 4563 |  |  |  |  |  |  |  | 
| 4564 |  |  |  |  |  |  | # done if no groups with side comments | 
| 4565 | 199 | 50 |  |  |  | 680 | return unless @todo; | 
| 4566 |  |  |  |  |  |  |  | 
| 4567 |  |  |  |  |  |  | # Count $num5 = number of comments in the 5 lines after the first comment | 
| 4568 |  |  |  |  |  |  | # This is an important factor in a decision formula | 
| 4569 | 199 |  |  |  |  | 421 | my $num5 = 1; | 
| 4570 | 199 |  |  |  |  | 492 | foreach my $jj ( $j_sc_beg + 1 .. @{$rlines} - 1 ) { | 
|  | 199 |  |  |  |  | 652 |  | 
| 4571 | 194 |  |  |  |  | 357 | my $ldiff = $jj - $j_sc_beg; | 
| 4572 | 194 | 100 |  |  |  | 520 | last if ( $ldiff > 5 ); | 
| 4573 | 190 |  |  |  |  | 334 | my $line   = $rlines->[$jj]; | 
| 4574 | 190 |  |  |  |  | 321 | my $jmax   = $line->{'jmax'}; | 
| 4575 | 190 |  |  |  |  | 375 | my $sc_len = $line->{'rfield_lengths'}->[$jmax]; | 
| 4576 | 190 | 100 |  |  |  | 451 | next if ( !$sc_len ); | 
| 4577 | 121 |  |  |  |  | 272 | $num5++; | 
| 4578 |  |  |  |  |  |  | } | 
| 4579 |  |  |  |  |  |  |  | 
| 4580 |  |  |  |  |  |  | # Forget the old side comment location if necessary | 
| 4581 | 199 |  |  |  |  | 572 | my $line_0 = $rlines->[$j_sc_beg]; | 
| 4582 | 199 |  |  |  |  | 1237 | my $lnum = | 
| 4583 |  |  |  |  |  |  | $j_sc_beg + $self->[_file_writer_object_]->get_output_line_number(); | 
| 4584 | 199 |  |  |  |  | 1821 | my $keep_it = | 
| 4585 |  |  |  |  |  |  | $self->is_good_side_comment_column( $line_0, $lnum, $group_level, $num5 ); | 
| 4586 | 199 | 100 |  |  |  | 617 | my $last_side_comment_column = | 
| 4587 |  |  |  |  |  |  | $keep_it ? $self->[_last_side_comment_column_] : 0; | 
| 4588 |  |  |  |  |  |  |  | 
| 4589 |  |  |  |  |  |  | # If there are multiple groups we will do two passes | 
| 4590 |  |  |  |  |  |  | # so that we can find a common alignment for all groups. | 
| 4591 | 199 | 100 |  |  |  | 601 | my $MAX_PASS = @todo > 1 ? 2 : 1; | 
| 4592 |  |  |  |  |  |  |  | 
| 4593 |  |  |  |  |  |  | # Loop over passes | 
| 4594 | 199 |  |  |  |  | 386 | my $max_comment_column = $last_side_comment_column; | 
| 4595 | 199 |  |  |  |  | 512 | foreach my $PASS ( 1 .. $MAX_PASS ) { | 
| 4596 |  |  |  |  |  |  |  | 
| 4597 |  |  |  |  |  |  | # If there are two passes, then on the last pass make the old column | 
| 4598 |  |  |  |  |  |  | # equal to the largest of the group.  This will result in the comments | 
| 4599 |  |  |  |  |  |  | # being aligned if possible. | 
| 4600 | 223 | 100 |  |  |  | 664 | if ( $PASS == $MAX_PASS ) { | 
| 4601 | 199 |  |  |  |  | 384 | $last_side_comment_column = $max_comment_column; | 
| 4602 |  |  |  |  |  |  | } | 
| 4603 |  |  |  |  |  |  |  | 
| 4604 |  |  |  |  |  |  | # Loop over the groups with side comments | 
| 4605 | 223 |  |  |  |  | 365 | my $column_limit; | 
| 4606 | 223 |  |  |  |  | 485 | foreach my $ng (@todo) { | 
| 4607 | 281 |  |  |  |  | 504 | my ( $jbeg, $jend ) = @{ $rgroups->[$ng] }; | 
|  | 281 |  |  |  |  | 654 |  | 
| 4608 |  |  |  |  |  |  |  | 
| 4609 |  |  |  |  |  |  | # Note that since all lines in a group have common alignments, we | 
| 4610 |  |  |  |  |  |  | # just have to work on one of the lines (the first line). | 
| 4611 | 281 |  |  |  |  | 570 | my $line                    = $rlines->[$jbeg]; | 
| 4612 | 281 |  |  |  |  | 558 | my $jmax                    = $line->{'jmax'}; | 
| 4613 | 281 |  |  |  |  | 551 | my $is_hanging_side_comment = $line->{'is_hanging_side_comment'}; | 
| 4614 |  |  |  |  |  |  | last | 
| 4615 | 281 | 100 | 100 |  |  | 942 | if ( $PASS < $MAX_PASS && $is_hanging_side_comment ); | 
| 4616 |  |  |  |  |  |  |  | 
| 4617 |  |  |  |  |  |  | # the maximum space without exceeding the line length: | 
| 4618 | 277 |  |  |  |  | 1046 | my $avail = $line->get_available_space_on_right(); | 
| 4619 |  |  |  |  |  |  |  | 
| 4620 |  |  |  |  |  |  | # try to use the previous comment column | 
| 4621 | 277 |  |  |  |  | 1029 | my $side_comment_column = $line->get_column( $jmax - 1 ); | 
| 4622 | 277 |  |  |  |  | 752 | my $move = $last_side_comment_column - $side_comment_column; | 
| 4623 |  |  |  |  |  |  |  | 
| 4624 |  |  |  |  |  |  | # Remember the maximum possible column of the first line with | 
| 4625 |  |  |  |  |  |  | # side comment | 
| 4626 | 277 | 100 |  |  |  | 834 | if ( !defined($column_limit) ) { | 
| 4627 | 223 |  |  |  |  | 440 | $column_limit = $side_comment_column + $avail; | 
| 4628 |  |  |  |  |  |  | } | 
| 4629 |  |  |  |  |  |  |  | 
| 4630 | 277 | 50 |  |  |  | 857 | next if ( $jmax <= 0 ); | 
| 4631 |  |  |  |  |  |  |  | 
| 4632 |  |  |  |  |  |  | # but if this doesn't work, give up and use the minimum space | 
| 4633 | 277 |  |  |  |  | 561 | my $min_move = $self->[_rOpts_minimum_space_to_comment_] - 1; | 
| 4634 | 277 | 100 |  |  |  | 731 | if ( $move > $avail ) { | 
| 4635 | 13 |  |  |  |  | 27 | $move = $min_move; | 
| 4636 |  |  |  |  |  |  | } | 
| 4637 |  |  |  |  |  |  |  | 
| 4638 |  |  |  |  |  |  | # but we want some minimum space to the comment | 
| 4639 | 277 | 100 | 100 |  |  | 1293 | if (   $move >= 0 | 
|  |  |  | 100 |  |  |  |  | 
| 4640 |  |  |  |  |  |  | && $j_sc_beg == 0 | 
| 4641 |  |  |  |  |  |  | && $continuing_sc_flow ) | 
| 4642 |  |  |  |  |  |  | { | 
| 4643 | 3 |  |  |  |  | 10 | $min_move = 0; | 
| 4644 |  |  |  |  |  |  | } | 
| 4645 |  |  |  |  |  |  |  | 
| 4646 |  |  |  |  |  |  | # remove constraints on hanging side comments | 
| 4647 | 277 | 100 |  |  |  | 664 | if ($is_hanging_side_comment) { $min_move = 0 } | 
|  | 14 |  |  |  |  | 35 |  | 
| 4648 |  |  |  |  |  |  |  | 
| 4649 | 277 | 100 |  |  |  | 767 | if ( $move < $min_move ) { | 
| 4650 | 194 |  |  |  |  | 319 | $move = $min_move; | 
| 4651 |  |  |  |  |  |  | } | 
| 4652 |  |  |  |  |  |  |  | 
| 4653 |  |  |  |  |  |  | # don't exceed the available space | 
| 4654 | 277 | 100 |  |  |  | 680 | if ( $move > $avail ) { $move = $avail } | 
|  | 11 |  |  |  |  | 26 |  | 
| 4655 |  |  |  |  |  |  |  | 
| 4656 |  |  |  |  |  |  | # We can only increase space, never decrease. | 
| 4657 | 277 | 100 |  |  |  | 730 | if ( $move < 0 ) { $move = 0 } | 
|  | 8 |  |  |  |  | 17 |  | 
| 4658 |  |  |  |  |  |  |  | 
| 4659 |  |  |  |  |  |  | # Discover the largest column on the preliminary  pass | 
| 4660 | 277 | 100 |  |  |  | 644 | if ( $PASS < $MAX_PASS ) { | 
| 4661 | 49 |  |  |  |  | 145 | my $col = $line->get_column( $jmax - 1 ) + $move; | 
| 4662 |  |  |  |  |  |  |  | 
| 4663 |  |  |  |  |  |  | # but ignore columns too large for the starting line | 
| 4664 | 49 | 100 | 66 |  |  | 304 | if ( $col > $max_comment_column && $col < $column_limit ) { | 
| 4665 | 23 |  |  |  |  | 64 | $max_comment_column = $col; | 
| 4666 |  |  |  |  |  |  | } | 
| 4667 |  |  |  |  |  |  | } | 
| 4668 |  |  |  |  |  |  |  | 
| 4669 |  |  |  |  |  |  | # Make the changes on the final pass | 
| 4670 |  |  |  |  |  |  | else { | 
| 4671 | 228 |  |  |  |  | 932 | $line->increase_field_width( $jmax - 1, $move ); | 
| 4672 |  |  |  |  |  |  |  | 
| 4673 |  |  |  |  |  |  | # remember this column for the next group | 
| 4674 | 228 |  |  |  |  | 791 | $last_side_comment_column = $line->get_column( $jmax - 1 ); | 
| 4675 |  |  |  |  |  |  | } | 
| 4676 |  |  |  |  |  |  | } ## end loop over groups | 
| 4677 |  |  |  |  |  |  | } ## end loop over passes | 
| 4678 |  |  |  |  |  |  |  | 
| 4679 |  |  |  |  |  |  | # Find the last side comment | 
| 4680 | 199 |  |  |  |  | 414 | my $j_sc_last; | 
| 4681 | 199 |  |  |  |  | 443 | my $ng_last = $todo[-1]; | 
| 4682 | 199 |  |  |  |  | 351 | my ( $jbeg, $jend ) = @{ $rgroups->[$ng_last] }; | 
|  | 199 |  |  |  |  | 509 |  | 
| 4683 | 199 |  |  |  |  | 652 | foreach my $jj ( reverse( $jbeg .. $jend ) ) { | 
| 4684 | 201 |  |  |  |  | 450 | my $line = $rlines->[$jj]; | 
| 4685 | 201 |  |  |  |  | 384 | my $jmax = $line->{'jmax'}; | 
| 4686 | 201 | 100 |  |  |  | 614 | if ( $line->{'rfield_lengths'}->[$jmax] ) { | 
| 4687 | 199 |  |  |  |  | 396 | $j_sc_last = $jj; | 
| 4688 | 199 |  |  |  |  | 438 | last; | 
| 4689 |  |  |  |  |  |  | } | 
| 4690 |  |  |  |  |  |  | } | 
| 4691 |  |  |  |  |  |  |  | 
| 4692 |  |  |  |  |  |  | # Save final side comment info for possible use by the next batch | 
| 4693 | 199 | 50 |  |  |  | 588 | if ( defined($j_sc_last) ) { | 
| 4694 | 199 |  |  |  |  | 674 | my $line_number = | 
| 4695 |  |  |  |  |  |  | $self->[_file_writer_object_]->get_output_line_number() + $j_sc_last; | 
| 4696 | 199 |  |  |  |  | 457 | $self->[_last_side_comment_column_]      = $last_side_comment_column; | 
| 4697 | 199 |  |  |  |  | 381 | $self->[_last_side_comment_line_number_] = $line_number; | 
| 4698 | 199 |  |  |  |  | 411 | $self->[_last_side_comment_level_]       = $group_level; | 
| 4699 |  |  |  |  |  |  | } | 
| 4700 | 199 |  |  |  |  | 488 | return; | 
| 4701 |  |  |  |  |  |  | } ## end sub align_side_comments | 
| 4702 |  |  |  |  |  |  |  | 
| 4703 |  |  |  |  |  |  | ############################### | 
| 4704 |  |  |  |  |  |  | # CODE SECTION 6: Output Step A | 
| 4705 |  |  |  |  |  |  | ############################### | 
| 4706 |  |  |  |  |  |  |  | 
| 4707 |  |  |  |  |  |  | sub valign_output_step_A { | 
| 4708 |  |  |  |  |  |  |  | 
| 4709 |  |  |  |  |  |  | #------------------------------------------------------------ | 
| 4710 |  |  |  |  |  |  | # This is Step A in writing vertically aligned lines. | 
| 4711 |  |  |  |  |  |  | # The line is prepared according to the alignments which have | 
| 4712 |  |  |  |  |  |  | # been found. Then it is shipped to the next step. | 
| 4713 |  |  |  |  |  |  | #------------------------------------------------------------ | 
| 4714 |  |  |  |  |  |  |  | 
| 4715 | 3065 |  |  | 3065 | 0 | 6637 | my ( $self, $rinput_hash ) = @_; | 
| 4716 |  |  |  |  |  |  |  | 
| 4717 | 3065 |  |  |  |  | 5751 | my $line                 = $rinput_hash->{line}; | 
| 4718 | 3065 |  |  |  |  | 5072 | my $min_ci_gap           = $rinput_hash->{min_ci_gap}; | 
| 4719 | 3065 |  |  |  |  | 4914 | my $do_not_align         = $rinput_hash->{do_not_align}; | 
| 4720 | 3065 |  |  |  |  | 4811 | my $group_leader_length  = $rinput_hash->{group_leader_length}; | 
| 4721 | 3065 |  |  |  |  | 4825 | my $extra_leading_spaces = $rinput_hash->{extra_leading_spaces}; | 
| 4722 | 3065 |  |  |  |  | 4943 | my $level                = $rinput_hash->{level}; | 
| 4723 | 3065 |  |  |  |  | 4921 | my $maximum_line_length  = $rinput_hash->{maximum_line_length}; | 
| 4724 |  |  |  |  |  |  |  | 
| 4725 | 3065 |  |  |  |  | 5244 | my $rfields                   = $line->{'rfields'}; | 
| 4726 | 3065 |  |  |  |  | 4972 | my $rfield_lengths            = $line->{'rfield_lengths'}; | 
| 4727 | 3065 |  |  |  |  | 4831 | my $leading_space_count       = $line->{'leading_space_count'}; | 
| 4728 | 3065 |  |  |  |  | 5373 | my $outdent_long_lines        = $line->{'outdent_long_lines'}; | 
| 4729 | 3065 |  |  |  |  | 5044 | my $maximum_field_index       = $line->{'jmax'}; | 
| 4730 | 3065 |  |  |  |  | 4967 | my $rvertical_tightness_flags = $line->{'rvertical_tightness_flags'}; | 
| 4731 | 3065 |  |  |  |  | 4993 | my $Kend                      = $line->{'Kend'}; | 
| 4732 | 3065 |  |  |  |  | 5290 | my $level_end                 = $line->{'level_end'}; | 
| 4733 |  |  |  |  |  |  |  | 
| 4734 |  |  |  |  |  |  | # Check for valid hash keys at end of lifetime of $line during development | 
| 4735 | 3065 |  |  |  |  | 4302 | DEVEL_MODE | 
| 4736 |  |  |  |  |  |  | && check_keys( $line, \%valid_LINE_keys, | 
| 4737 |  |  |  |  |  |  | "Checking line keys at valign_output_step_A", 1 ); | 
| 4738 |  |  |  |  |  |  |  | 
| 4739 |  |  |  |  |  |  | # add any extra spaces | 
| 4740 | 3065 | 100 |  |  |  | 6706 | if ( $leading_space_count > $group_leader_length ) { | 
| 4741 | 47 |  |  |  |  | 148 | $leading_space_count += $min_ci_gap; | 
| 4742 |  |  |  |  |  |  | } | 
| 4743 |  |  |  |  |  |  |  | 
| 4744 | 3065 |  |  |  |  | 6040 | my $str     = $rfields->[0]; | 
| 4745 | 3065 |  |  |  |  | 4917 | my $str_len = $rfield_lengths->[0]; | 
| 4746 |  |  |  |  |  |  |  | 
| 4747 | 3065 |  |  |  |  | 4769 | my @alignments = @{ $line->{'ralignments'} }; | 
|  | 3065 |  |  |  |  | 7293 |  | 
| 4748 | 3065 | 50 |  |  |  | 8241 | if ( @alignments != $maximum_field_index + 1 ) { | 
| 4749 |  |  |  |  |  |  |  | 
| 4750 |  |  |  |  |  |  | # Shouldn't happen: sub install_new_alignments makes jmax alignments | 
| 4751 | 0 |  |  |  |  | 0 | my $jmax_alignments = @alignments - 1; | 
| 4752 | 0 |  |  |  |  | 0 | if (DEVEL_MODE) { | 
| 4753 |  |  |  |  |  |  | Fault( | 
| 4754 |  |  |  |  |  |  | "alignment jmax=$jmax_alignments should equal $maximum_field_index\n" | 
| 4755 |  |  |  |  |  |  | ); | 
| 4756 |  |  |  |  |  |  | } | 
| 4757 | 0 |  |  |  |  | 0 | $do_not_align = 1; | 
| 4758 |  |  |  |  |  |  | } | 
| 4759 |  |  |  |  |  |  |  | 
| 4760 |  |  |  |  |  |  | # loop to concatenate all fields of this line and needed padding | 
| 4761 | 3065 |  |  |  |  | 5104 | my $total_pad_count = 0; | 
| 4762 | 3065 |  |  |  |  | 6796 | for my $j ( 1 .. $maximum_field_index ) { | 
| 4763 |  |  |  |  |  |  |  | 
| 4764 |  |  |  |  |  |  | # skip zero-length side comments | 
| 4765 |  |  |  |  |  |  | last | 
| 4766 |  |  |  |  |  |  | if ( | 
| 4767 | 7282 | 100 | 66 |  |  | 24262 | ( $j == $maximum_field_index ) | 
|  |  |  | 100 |  |  |  |  | 
| 4768 |  |  |  |  |  |  | && ( !defined( $rfields->[$j] ) | 
| 4769 |  |  |  |  |  |  | || ( $rfield_lengths->[$j] == 0 ) ) | 
| 4770 |  |  |  |  |  |  | ); | 
| 4771 |  |  |  |  |  |  |  | 
| 4772 |  |  |  |  |  |  | # compute spaces of padding before this field | 
| 4773 | 4542 |  |  |  |  | 9020 | my $col = $alignments[ $j - 1 ]->{'column'}; | 
| 4774 | 4542 |  |  |  |  | 7275 | my $pad = $col - ( $str_len + $leading_space_count ); | 
| 4775 |  |  |  |  |  |  |  | 
| 4776 | 4542 | 50 |  |  |  | 8574 | if ($do_not_align) { | 
| 4777 | 0 | 0 |  |  |  | 0 | $pad = | 
| 4778 |  |  |  |  |  |  | ( $j < $maximum_field_index ) | 
| 4779 |  |  |  |  |  |  | ? 0 | 
| 4780 |  |  |  |  |  |  | : $self->[_rOpts_minimum_space_to_comment_] - 1; | 
| 4781 |  |  |  |  |  |  | } | 
| 4782 |  |  |  |  |  |  |  | 
| 4783 |  |  |  |  |  |  | # if the -fpsc flag is set, move the side comment to the selected | 
| 4784 |  |  |  |  |  |  | # column if and only if it is possible, ignoring constraints on | 
| 4785 |  |  |  |  |  |  | # line length and minimum space to comment | 
| 4786 | 4542 | 100 | 100 |  |  | 10291 | if (   $self->[_rOpts_fixed_position_side_comment_] | 
| 4787 |  |  |  |  |  |  | && $j == $maximum_field_index ) | 
| 4788 |  |  |  |  |  |  | { | 
| 4789 | 9 |  |  |  |  | 20 | my $newpad = | 
| 4790 |  |  |  |  |  |  | $pad + $self->[_rOpts_fixed_position_side_comment_] - $col - 1; | 
| 4791 | 9 | 50 |  |  |  | 22 | if ( $newpad >= 0 ) { $pad = $newpad; } | 
|  | 9 |  |  |  |  | 12 |  | 
| 4792 |  |  |  |  |  |  | } | 
| 4793 |  |  |  |  |  |  |  | 
| 4794 |  |  |  |  |  |  | # accumulate the padding | 
| 4795 | 4542 | 100 |  |  |  | 9169 | if ( $pad > 0 ) { $total_pad_count += $pad; } | 
|  | 1321 |  |  |  |  | 2151 |  | 
| 4796 |  |  |  |  |  |  |  | 
| 4797 |  |  |  |  |  |  | # only add padding when we have a finite field; | 
| 4798 |  |  |  |  |  |  | # this avoids extra terminal spaces if we have empty fields | 
| 4799 | 4542 | 100 |  |  |  | 8731 | if ( $rfield_lengths->[$j] > 0 ) { | 
| 4800 | 4531 |  |  |  |  | 9024 | $str .= SPACE x $total_pad_count; | 
| 4801 | 4531 |  |  |  |  | 6305 | $str_len += $total_pad_count; | 
| 4802 | 4531 |  |  |  |  | 6300 | $total_pad_count = 0; | 
| 4803 | 4531 |  |  |  |  | 7702 | $str .= $rfields->[$j]; | 
| 4804 | 4531 |  |  |  |  | 7700 | $str_len += $rfield_lengths->[$j]; | 
| 4805 |  |  |  |  |  |  | } | 
| 4806 |  |  |  |  |  |  | else { | 
| 4807 | 11 |  |  |  |  | 27 | $total_pad_count = 0; | 
| 4808 |  |  |  |  |  |  | } | 
| 4809 |  |  |  |  |  |  | } | 
| 4810 |  |  |  |  |  |  |  | 
| 4811 | 3065 |  |  |  |  | 5650 | my $side_comment_length = $rfield_lengths->[$maximum_field_index]; | 
| 4812 |  |  |  |  |  |  |  | 
| 4813 |  |  |  |  |  |  | # ship this line off | 
| 4814 | 3065 |  |  |  |  | 25622 | $self->valign_output_step_B( | 
| 4815 |  |  |  |  |  |  | { | 
| 4816 |  |  |  |  |  |  | leading_space_count => $leading_space_count + $extra_leading_spaces, | 
| 4817 |  |  |  |  |  |  | line                => $str, | 
| 4818 |  |  |  |  |  |  | line_length         => $str_len, | 
| 4819 |  |  |  |  |  |  | side_comment_length => $side_comment_length, | 
| 4820 |  |  |  |  |  |  | outdent_long_lines  => $outdent_long_lines, | 
| 4821 |  |  |  |  |  |  | rvertical_tightness_flags => $rvertical_tightness_flags, | 
| 4822 |  |  |  |  |  |  | level                     => $level, | 
| 4823 |  |  |  |  |  |  | level_end                 => $level_end, | 
| 4824 |  |  |  |  |  |  | Kend                      => $Kend, | 
| 4825 |  |  |  |  |  |  | maximum_line_length       => $maximum_line_length, | 
| 4826 |  |  |  |  |  |  | } | 
| 4827 |  |  |  |  |  |  | ); | 
| 4828 | 3065 |  |  |  |  | 14980 | return; | 
| 4829 |  |  |  |  |  |  | } ## end sub valign_output_step_A | 
| 4830 |  |  |  |  |  |  |  | 
| 4831 |  |  |  |  |  |  | sub combine_fields { | 
| 4832 |  |  |  |  |  |  |  | 
| 4833 |  |  |  |  |  |  | # We have a group of two lines for which we do not want to align tokens | 
| 4834 |  |  |  |  |  |  | # between index $imax_align and the side comment.  So we will delete fields | 
| 4835 |  |  |  |  |  |  | # between $imax_align and the side comment.  Alignments have already | 
| 4836 |  |  |  |  |  |  | # been set so we have to adjust them. | 
| 4837 |  |  |  |  |  |  |  | 
| 4838 | 14 |  |  | 14 | 0 | 46 | my ( $line_0, $line_1, $imax_align ) = @_; | 
| 4839 |  |  |  |  |  |  |  | 
| 4840 | 14 | 50 |  |  |  | 58 | if ( !defined($imax_align) ) { $imax_align = -1 } | 
|  | 0 |  |  |  |  | 0 |  | 
| 4841 |  |  |  |  |  |  |  | 
| 4842 |  |  |  |  |  |  | # First delete the unwanted tokens | 
| 4843 | 14 |  |  |  |  | 45 | my $jmax_old = $line_0->{'jmax'}; | 
| 4844 | 14 |  |  |  |  | 56 | my @idel     = ( $imax_align + 1 .. $jmax_old - 2 ); | 
| 4845 | 14 | 50 |  |  |  | 52 | return if ( !@idel ); | 
| 4846 |  |  |  |  |  |  |  | 
| 4847 |  |  |  |  |  |  | # Get old alignments before any changes are made | 
| 4848 | 14 |  |  |  |  | 31 | my @old_alignments = @{ $line_0->{'ralignments'} }; | 
|  | 14 |  |  |  |  | 45 |  | 
| 4849 |  |  |  |  |  |  |  | 
| 4850 | 14 |  |  |  |  | 53 | foreach my $line ( $line_0, $line_1 ) { | 
| 4851 | 28 |  |  |  |  | 104 | delete_selected_tokens( $line, \@idel ); | 
| 4852 |  |  |  |  |  |  | } | 
| 4853 |  |  |  |  |  |  |  | 
| 4854 |  |  |  |  |  |  | # Now adjust the alignments.  Note that the side comment alignment | 
| 4855 |  |  |  |  |  |  | # is always at jmax-1, and there is an ending alignment at jmax. | 
| 4856 | 14 |  |  |  |  | 43 | my @new_alignments; | 
| 4857 | 14 | 50 |  |  |  | 76 | if ( $imax_align >= 0 ) { | 
| 4858 | 0 |  |  |  |  | 0 | @new_alignments[ 0 .. $imax_align ] = | 
| 4859 |  |  |  |  |  |  | @old_alignments[ 0 .. $imax_align ]; | 
| 4860 |  |  |  |  |  |  | } | 
| 4861 |  |  |  |  |  |  |  | 
| 4862 | 14 |  |  |  |  | 47 | my $jmax_new = $line_0->{'jmax'}; | 
| 4863 |  |  |  |  |  |  |  | 
| 4864 | 14 |  |  |  |  | 56 | $new_alignments[ $jmax_new - 1 ] = $old_alignments[ $jmax_old - 1 ]; | 
| 4865 | 14 |  |  |  |  | 33 | $new_alignments[$jmax_new]       = $old_alignments[$jmax_old]; | 
| 4866 | 14 |  |  |  |  | 53 | $line_0->{'ralignments'}         = \@new_alignments; | 
| 4867 | 14 |  |  |  |  | 44 | $line_1->{'ralignments'}         = \@new_alignments; | 
| 4868 | 14 |  |  |  |  | 56 | return; | 
| 4869 |  |  |  |  |  |  | } ## end sub combine_fields | 
| 4870 |  |  |  |  |  |  |  | 
| 4871 |  |  |  |  |  |  | sub get_output_line_number { | 
| 4872 |  |  |  |  |  |  |  | 
| 4873 |  |  |  |  |  |  | # The output line number reported to a caller = | 
| 4874 |  |  |  |  |  |  | # the number of items still in the buffer + | 
| 4875 |  |  |  |  |  |  | # the number of items written. | 
| 4876 | 49 |  |  | 49 | 0 | 157 | return $_[0]->group_line_count() + | 
| 4877 |  |  |  |  |  |  | $_[0]->[_file_writer_object_]->get_output_line_number(); | 
| 4878 |  |  |  |  |  |  | } ## end sub get_output_line_number | 
| 4879 |  |  |  |  |  |  |  | 
| 4880 |  |  |  |  |  |  | ############################### | 
| 4881 |  |  |  |  |  |  | # CODE SECTION 7: Output Step B | 
| 4882 |  |  |  |  |  |  | ############################### | 
| 4883 |  |  |  |  |  |  |  | 
| 4884 |  |  |  |  |  |  | {    ## closure for sub valign_output_step_B | 
| 4885 |  |  |  |  |  |  |  | 
| 4886 |  |  |  |  |  |  | # These are values for a cache used by valign_output_step_B. | 
| 4887 |  |  |  |  |  |  | my $cached_line_text; | 
| 4888 |  |  |  |  |  |  | my $cached_line_text_length; | 
| 4889 |  |  |  |  |  |  | my $cached_line_type; | 
| 4890 |  |  |  |  |  |  | my $cached_line_opening_flag; | 
| 4891 |  |  |  |  |  |  | my $cached_line_closing_flag; | 
| 4892 |  |  |  |  |  |  | my $cached_seqno; | 
| 4893 |  |  |  |  |  |  | my $cached_line_valid; | 
| 4894 |  |  |  |  |  |  | my $cached_line_leading_space_count; | 
| 4895 |  |  |  |  |  |  | my $cached_seqno_string; | 
| 4896 |  |  |  |  |  |  | my $cached_line_Kend; | 
| 4897 |  |  |  |  |  |  | my $cached_line_maximum_length; | 
| 4898 |  |  |  |  |  |  |  | 
| 4899 |  |  |  |  |  |  | # These are passed to step_C: | 
| 4900 |  |  |  |  |  |  | my $seqno_string; | 
| 4901 |  |  |  |  |  |  | my $last_nonblank_seqno_string; | 
| 4902 |  |  |  |  |  |  |  | 
| 4903 |  |  |  |  |  |  | sub set_last_nonblank_seqno_string { | 
| 4904 | 394 |  |  | 394 | 0 | 854 | my ($val) = @_; | 
| 4905 | 394 |  |  |  |  | 648 | $last_nonblank_seqno_string = $val; | 
| 4906 | 394 |  |  |  |  | 643 | return; | 
| 4907 |  |  |  |  |  |  | } | 
| 4908 |  |  |  |  |  |  |  | 
| 4909 |  |  |  |  |  |  | sub get_cached_line_opening_flag { | 
| 4910 | 224 |  |  | 224 | 0 | 485 | return $cached_line_opening_flag; | 
| 4911 |  |  |  |  |  |  | } | 
| 4912 |  |  |  |  |  |  |  | 
| 4913 |  |  |  |  |  |  | sub get_cached_line_type { | 
| 4914 | 7481 |  |  | 7481 | 0 | 13708 | return $cached_line_type; | 
| 4915 |  |  |  |  |  |  | } | 
| 4916 |  |  |  |  |  |  |  | 
| 4917 |  |  |  |  |  |  | sub set_cached_line_valid { | 
| 4918 | 3 |  |  | 3 | 0 | 14 | my ($val) = @_; | 
| 4919 | 3 |  |  |  |  | 7 | $cached_line_valid = $val; | 
| 4920 | 3 |  |  |  |  | 9 | return; | 
| 4921 |  |  |  |  |  |  | } | 
| 4922 |  |  |  |  |  |  |  | 
| 4923 |  |  |  |  |  |  | sub get_cached_seqno { | 
| 4924 | 224 |  |  | 224 | 0 | 512 | return $cached_seqno; | 
| 4925 |  |  |  |  |  |  | } | 
| 4926 |  |  |  |  |  |  |  | 
| 4927 |  |  |  |  |  |  | sub initialize_step_B_cache { | 
| 4928 |  |  |  |  |  |  |  | 
| 4929 |  |  |  |  |  |  | # valign_output_step_B cache: | 
| 4930 | 560 |  |  | 560 | 0 | 1887 | $cached_line_text                = EMPTY_STRING; | 
| 4931 | 560 |  |  |  |  | 1269 | $cached_line_text_length         = 0; | 
| 4932 | 560 |  |  |  |  | 1179 | $cached_line_type                = 0; | 
| 4933 | 560 |  |  |  |  | 1245 | $cached_line_opening_flag        = 0; | 
| 4934 | 560 |  |  |  |  | 1262 | $cached_line_closing_flag        = 0; | 
| 4935 | 560 |  |  |  |  | 1256 | $cached_seqno                    = 0; | 
| 4936 | 560 |  |  |  |  | 1125 | $cached_line_valid               = 0; | 
| 4937 | 560 |  |  |  |  | 1121 | $cached_line_leading_space_count = 0; | 
| 4938 | 560 |  |  |  |  | 1162 | $cached_seqno_string             = EMPTY_STRING; | 
| 4939 | 560 |  |  |  |  | 1199 | $cached_line_Kend                = undef; | 
| 4940 | 560 |  |  |  |  | 1099 | $cached_line_maximum_length      = undef; | 
| 4941 |  |  |  |  |  |  |  | 
| 4942 |  |  |  |  |  |  | # These vars hold a string of sequence numbers joined together used by | 
| 4943 |  |  |  |  |  |  | # the cache | 
| 4944 | 560 |  |  |  |  | 1405 | $seqno_string               = EMPTY_STRING; | 
| 4945 | 560 |  |  |  |  | 1316 | $last_nonblank_seqno_string = EMPTY_STRING; | 
| 4946 | 560 |  |  |  |  | 1169 | return; | 
| 4947 |  |  |  |  |  |  | } ## end sub initialize_step_B_cache | 
| 4948 |  |  |  |  |  |  |  | 
| 4949 |  |  |  |  |  |  | sub _flush_step_B_cache { | 
| 4950 | 1817 |  |  | 1817 |  | 3952 | my ($self) = @_; | 
| 4951 |  |  |  |  |  |  |  | 
| 4952 |  |  |  |  |  |  | # Send any text in the step_B cache on to step_C | 
| 4953 | 1817 | 100 |  |  |  | 4470 | if ($cached_line_type) { | 
| 4954 | 1 |  |  |  |  | 4 | $seqno_string = $cached_seqno_string; | 
| 4955 | 1 |  |  |  |  | 7 | $self->valign_output_step_C( | 
| 4956 |  |  |  |  |  |  | $seqno_string, | 
| 4957 |  |  |  |  |  |  | $last_nonblank_seqno_string, | 
| 4958 |  |  |  |  |  |  |  | 
| 4959 |  |  |  |  |  |  | $cached_line_text, | 
| 4960 |  |  |  |  |  |  | $cached_line_leading_space_count, | 
| 4961 |  |  |  |  |  |  | $self->[_last_level_written_], | 
| 4962 |  |  |  |  |  |  | $cached_line_Kend, | 
| 4963 |  |  |  |  |  |  | ); | 
| 4964 | 1 |  |  |  |  | 2 | $cached_line_type           = 0; | 
| 4965 | 1 |  |  |  |  | 2 | $cached_line_text           = EMPTY_STRING; | 
| 4966 | 1 |  |  |  |  | 3 | $cached_line_text_length    = 0; | 
| 4967 | 1 |  |  |  |  | 3 | $cached_seqno_string        = EMPTY_STRING; | 
| 4968 | 1 |  |  |  |  | 2 | $cached_line_Kend           = undef; | 
| 4969 | 1 |  |  |  |  | 2 | $cached_line_maximum_length = undef; | 
| 4970 |  |  |  |  |  |  | } | 
| 4971 | 1817 |  |  |  |  | 3083 | return; | 
| 4972 |  |  |  |  |  |  | } ## end sub _flush_step_B_cache | 
| 4973 |  |  |  |  |  |  |  | 
| 4974 |  |  |  |  |  |  | sub handle_cached_line { | 
| 4975 |  |  |  |  |  |  |  | 
| 4976 | 158 |  |  | 158 | 0 | 515 | my ( $self, $rinput, $leading_string, $leading_string_length ) = @_; | 
| 4977 |  |  |  |  |  |  |  | 
| 4978 |  |  |  |  |  |  | # The cached line will either be: | 
| 4979 |  |  |  |  |  |  | # - passed along to step_C, or | 
| 4980 |  |  |  |  |  |  | # - or combined with the current line | 
| 4981 |  |  |  |  |  |  |  | 
| 4982 | 158 |  |  |  |  | 327 | my $last_level_written = $self->[_last_level_written_]; | 
| 4983 |  |  |  |  |  |  |  | 
| 4984 | 158 |  |  |  |  | 302 | my $leading_space_count       = $rinput->{leading_space_count}; | 
| 4985 | 158 |  |  |  |  | 347 | my $str                       = $rinput->{line}; | 
| 4986 | 158 |  |  |  |  | 282 | my $str_length                = $rinput->{line_length}; | 
| 4987 | 158 |  |  |  |  | 293 | my $rvertical_tightness_flags = $rinput->{rvertical_tightness_flags}; | 
| 4988 | 158 |  |  |  |  | 300 | my $level                     = $rinput->{level}; | 
| 4989 | 158 |  |  |  |  | 302 | my $level_end                 = $rinput->{level_end}; | 
| 4990 | 158 |  |  |  |  | 292 | my $maximum_line_length       = $rinput->{maximum_line_length}; | 
| 4991 |  |  |  |  |  |  |  | 
| 4992 | 158 |  |  |  |  | 345 | my ( $open_or_close, $opening_flag, $closing_flag, $seqno, $valid, | 
| 4993 |  |  |  |  |  |  | $seqno_beg, $seqno_end ); | 
| 4994 | 158 | 50 |  |  |  | 391 | if ($rvertical_tightness_flags) { | 
| 4995 |  |  |  |  |  |  |  | 
| 4996 | 158 |  |  |  |  | 268 | $open_or_close = $rvertical_tightness_flags->{_vt_type}; | 
| 4997 | 158 |  |  |  |  | 332 | $seqno_beg     = $rvertical_tightness_flags->{_vt_seqno_beg}; | 
| 4998 |  |  |  |  |  |  | } | 
| 4999 |  |  |  |  |  |  |  | 
| 5000 |  |  |  |  |  |  | # Dump an invalid cached line | 
| 5001 | 158 | 100 | 100 |  |  | 714 | if ( !$cached_line_valid ) { | 
|  |  | 100 |  |  |  |  |  | 
| 5002 | 91 |  |  |  |  | 280 | $self->valign_output_step_C( | 
| 5003 |  |  |  |  |  |  | $seqno_string, | 
| 5004 |  |  |  |  |  |  | $last_nonblank_seqno_string, | 
| 5005 |  |  |  |  |  |  |  | 
| 5006 |  |  |  |  |  |  | $cached_line_text, | 
| 5007 |  |  |  |  |  |  | $cached_line_leading_space_count, | 
| 5008 |  |  |  |  |  |  | $last_level_written, | 
| 5009 |  |  |  |  |  |  | $cached_line_Kend, | 
| 5010 |  |  |  |  |  |  | ); | 
| 5011 |  |  |  |  |  |  | } | 
| 5012 |  |  |  |  |  |  |  | 
| 5013 |  |  |  |  |  |  | # Handle cached line ending in OPENING tokens | 
| 5014 |  |  |  |  |  |  | elsif ( $cached_line_type == 1 || $cached_line_type == 3 ) { | 
| 5015 |  |  |  |  |  |  |  | 
| 5016 | 30 |  |  |  |  | 94 | my $gap = $leading_space_count - $cached_line_text_length; | 
| 5017 |  |  |  |  |  |  |  | 
| 5018 |  |  |  |  |  |  | # handle option of just one tight opening per line: | 
| 5019 | 30 | 100 |  |  |  | 96 | if ( $cached_line_opening_flag == 1 ) { | 
| 5020 | 14 | 50 | 33 |  |  | 61 | if ( defined($open_or_close) && $open_or_close == 1 ) { | 
| 5021 | 0 |  |  |  |  | 0 | $gap = -1; | 
| 5022 |  |  |  |  |  |  | } | 
| 5023 |  |  |  |  |  |  | } | 
| 5024 |  |  |  |  |  |  |  | 
| 5025 |  |  |  |  |  |  | # Do not join the lines if this might produce a one-line | 
| 5026 |  |  |  |  |  |  | # container which exceeds the maximum line length.  This is | 
| 5027 |  |  |  |  |  |  | # necessary prevent blinking, particularly with the combination | 
| 5028 |  |  |  |  |  |  | # -xci -pvt=2.  In that case a one-line block alternately forms | 
| 5029 |  |  |  |  |  |  | # and breaks, causing -xci to alternately turn on and off (case | 
| 5030 |  |  |  |  |  |  | # b765). | 
| 5031 |  |  |  |  |  |  | # Patched to fix cases b656 b862 b971 b972: always do the check | 
| 5032 |  |  |  |  |  |  | # if the maximum line length changes (due to -vmll). | 
| 5033 | 30 | 50 | 33 |  |  | 252 | if ( | 
|  |  |  | 66 |  |  |  |  | 
| 5034 |  |  |  |  |  |  | $gap >= 0 | 
| 5035 |  |  |  |  |  |  | && ( $maximum_line_length != $cached_line_maximum_length | 
| 5036 |  |  |  |  |  |  | || ( defined($level_end) && $level > $level_end ) ) | 
| 5037 |  |  |  |  |  |  | ) | 
| 5038 |  |  |  |  |  |  | { | 
| 5039 | 0 |  |  |  |  | 0 | my $test_line_length = | 
| 5040 |  |  |  |  |  |  | $cached_line_text_length + $gap + $str_length; | 
| 5041 |  |  |  |  |  |  |  | 
| 5042 |  |  |  |  |  |  | # Add a small tolerance in the length test (fixes case b862) | 
| 5043 | 0 | 0 |  |  |  | 0 | if ( $test_line_length > $cached_line_maximum_length - 2 ) { | 
| 5044 | 0 |  |  |  |  | 0 | $gap = -1; | 
| 5045 |  |  |  |  |  |  | } | 
| 5046 |  |  |  |  |  |  | } | 
| 5047 |  |  |  |  |  |  |  | 
| 5048 | 30 | 100 | 66 |  |  | 148 | if ( $gap >= 0 && defined($seqno_beg) ) { | 
| 5049 | 18 |  |  |  |  | 48 | $maximum_line_length   = $cached_line_maximum_length; | 
| 5050 | 18 |  |  |  |  | 62 | $leading_string        = $cached_line_text . SPACE x $gap; | 
| 5051 | 18 |  |  |  |  | 33 | $leading_string_length = $cached_line_text_length + $gap; | 
| 5052 | 18 |  |  |  |  | 34 | $leading_space_count   = $cached_line_leading_space_count; | 
| 5053 | 18 |  |  |  |  | 66 | $seqno_string = $cached_seqno_string . ':' . $seqno_beg; | 
| 5054 | 18 |  |  |  |  | 49 | $level        = $last_level_written; | 
| 5055 |  |  |  |  |  |  | } | 
| 5056 |  |  |  |  |  |  | else { | 
| 5057 | 12 |  |  |  |  | 44 | $self->valign_output_step_C( | 
| 5058 |  |  |  |  |  |  | $seqno_string, | 
| 5059 |  |  |  |  |  |  | $last_nonblank_seqno_string, | 
| 5060 |  |  |  |  |  |  |  | 
| 5061 |  |  |  |  |  |  | $cached_line_text, | 
| 5062 |  |  |  |  |  |  | $cached_line_leading_space_count, | 
| 5063 |  |  |  |  |  |  | $last_level_written, | 
| 5064 |  |  |  |  |  |  | $cached_line_Kend, | 
| 5065 |  |  |  |  |  |  | ); | 
| 5066 |  |  |  |  |  |  | } | 
| 5067 |  |  |  |  |  |  | } | 
| 5068 |  |  |  |  |  |  |  | 
| 5069 |  |  |  |  |  |  | # Handle cached line ending in CLOSING tokens | 
| 5070 |  |  |  |  |  |  | else { | 
| 5071 | 37 |  |  |  |  | 196 | my $test_line = | 
| 5072 |  |  |  |  |  |  | $cached_line_text . SPACE x $cached_line_closing_flag . $str; | 
| 5073 | 37 |  |  |  |  | 94 | my $test_line_length = | 
| 5074 |  |  |  |  |  |  | $cached_line_text_length + | 
| 5075 |  |  |  |  |  |  | $cached_line_closing_flag + | 
| 5076 |  |  |  |  |  |  | $str_length; | 
| 5077 | 37 | 100 | 66 |  |  | 480 | if ( | 
|  |  |  | 66 |  |  |  |  | 
|  |  |  | 100 |  |  |  |  | 
| 5078 |  |  |  |  |  |  |  | 
| 5079 |  |  |  |  |  |  | # The new line must start with container | 
| 5080 |  |  |  |  |  |  | $seqno_beg | 
| 5081 |  |  |  |  |  |  |  | 
| 5082 |  |  |  |  |  |  | # The container combination must be okay.. | 
| 5083 |  |  |  |  |  |  | && ( | 
| 5084 |  |  |  |  |  |  |  | 
| 5085 |  |  |  |  |  |  | # okay to combine like types | 
| 5086 |  |  |  |  |  |  | ( $open_or_close == $cached_line_type ) | 
| 5087 |  |  |  |  |  |  |  | 
| 5088 |  |  |  |  |  |  | # closing block brace may append to non-block | 
| 5089 |  |  |  |  |  |  | || ( $cached_line_type == 2 && $open_or_close == 4 ) | 
| 5090 |  |  |  |  |  |  |  | 
| 5091 |  |  |  |  |  |  | # something like ');' | 
| 5092 |  |  |  |  |  |  | || ( !$open_or_close && $cached_line_type == 2 ) | 
| 5093 |  |  |  |  |  |  |  | 
| 5094 |  |  |  |  |  |  | ) | 
| 5095 |  |  |  |  |  |  |  | 
| 5096 |  |  |  |  |  |  | # The combined line must fit | 
| 5097 |  |  |  |  |  |  | && ( $test_line_length <= $cached_line_maximum_length ) | 
| 5098 |  |  |  |  |  |  | ) | 
| 5099 |  |  |  |  |  |  | { | 
| 5100 |  |  |  |  |  |  |  | 
| 5101 | 33 |  |  |  |  | 91 | $seqno_string = $cached_seqno_string . ':' . $seqno_beg; | 
| 5102 |  |  |  |  |  |  |  | 
| 5103 |  |  |  |  |  |  | # Patch to outdent closing tokens ending # in ');' If we | 
| 5104 |  |  |  |  |  |  | # are joining a line like ');' to a previous stacked set of | 
| 5105 |  |  |  |  |  |  | # closing tokens, then decide if we may outdent the | 
| 5106 |  |  |  |  |  |  | # combined stack to the indentation of the ');'.  Since we | 
| 5107 |  |  |  |  |  |  | # should not normally outdent any of the other tokens more | 
| 5108 |  |  |  |  |  |  | # than the indentation of the lines that contained them, we | 
| 5109 |  |  |  |  |  |  | # will only do this if all of the corresponding opening | 
| 5110 |  |  |  |  |  |  | # tokens were on the same line.  This can happen with -sot | 
| 5111 |  |  |  |  |  |  | # and -sct. | 
| 5112 |  |  |  |  |  |  |  | 
| 5113 |  |  |  |  |  |  | # For example, it is ok here: | 
| 5114 |  |  |  |  |  |  | #   __PACKAGE__->load_components( qw( | 
| 5115 |  |  |  |  |  |  | #         PK::Auto | 
| 5116 |  |  |  |  |  |  | #         Core | 
| 5117 |  |  |  |  |  |  | #   )); | 
| 5118 |  |  |  |  |  |  | # | 
| 5119 |  |  |  |  |  |  | # But, for example, we do not outdent in this example | 
| 5120 |  |  |  |  |  |  | # because that would put the closing sub brace out farther | 
| 5121 |  |  |  |  |  |  | # than the opening sub brace: | 
| 5122 |  |  |  |  |  |  | # | 
| 5123 |  |  |  |  |  |  | #   perltidy -sot -sct | 
| 5124 |  |  |  |  |  |  | #   $c->Tk::bind( | 
| 5125 |  |  |  |  |  |  | #       '<Control-f>' => sub { | 
| 5126 |  |  |  |  |  |  | #           my ($c) = @_; | 
| 5127 |  |  |  |  |  |  | #           my $e = $c->XEvent; | 
| 5128 |  |  |  |  |  |  | #           itemsUnderArea $c; | 
| 5129 |  |  |  |  |  |  | #       } ); | 
| 5130 |  |  |  |  |  |  | # | 
| 5131 | 33 | 100 | 100 |  |  | 310 | if (   $str =~ /^\);/ | 
| 5132 |  |  |  |  |  |  | && $cached_line_text =~ /^[\)\}\]\s]*$/ ) | 
| 5133 |  |  |  |  |  |  | { | 
| 5134 |  |  |  |  |  |  |  | 
| 5135 |  |  |  |  |  |  | # The way to tell this is if the stacked sequence | 
| 5136 |  |  |  |  |  |  | # numbers of this output line are the reverse of the | 
| 5137 |  |  |  |  |  |  | # stacked sequence numbers of the previous non-blank | 
| 5138 |  |  |  |  |  |  | # line of sequence numbers.  So we can join if the | 
| 5139 |  |  |  |  |  |  | # previous nonblank string of tokens is the mirror | 
| 5140 |  |  |  |  |  |  | # image.  For example if stack )}] is 13:8:6 then we | 
| 5141 |  |  |  |  |  |  | # are looking for a leading stack like [{( which | 
| 5142 |  |  |  |  |  |  | # is 6:8:13. We only need to check the two ends, | 
| 5143 |  |  |  |  |  |  | # because the intermediate tokens must fall in order. | 
| 5144 |  |  |  |  |  |  | # Note on speed: having to split on colons and | 
| 5145 |  |  |  |  |  |  | # eliminate multiple colons might appear to be slow, | 
| 5146 |  |  |  |  |  |  | # but it's not an issue because we almost never come | 
| 5147 |  |  |  |  |  |  | # through here.  In a typical file we don't. | 
| 5148 |  |  |  |  |  |  |  | 
| 5149 | 4 |  |  |  |  | 19 | $seqno_string               =~ s/^:+//; | 
| 5150 | 4 |  |  |  |  | 11 | $last_nonblank_seqno_string =~ s/^:+//; | 
| 5151 | 4 |  |  |  |  | 18 | $seqno_string               =~ s/:+/:/g; | 
| 5152 | 4 |  |  |  |  | 18 | $last_nonblank_seqno_string =~ s/:+/:/g; | 
| 5153 |  |  |  |  |  |  |  | 
| 5154 |  |  |  |  |  |  | # how many spaces can we outdent? | 
| 5155 | 4 |  |  |  |  | 9 | my $diff = | 
| 5156 |  |  |  |  |  |  | $cached_line_leading_space_count - $leading_space_count; | 
| 5157 | 4 | 100 | 33 |  |  | 35 | if (   $diff > 0 | 
|  |  |  | 66 |  |  |  |  | 
| 5158 |  |  |  |  |  |  | && length($seqno_string) | 
| 5159 |  |  |  |  |  |  | && length($last_nonblank_seqno_string) == | 
| 5160 |  |  |  |  |  |  | length($seqno_string) ) | 
| 5161 |  |  |  |  |  |  | { | 
| 5162 | 3 |  |  |  |  | 21 | my @seqno_last = | 
| 5163 |  |  |  |  |  |  | ( split /:/, $last_nonblank_seqno_string ); | 
| 5164 | 3 |  |  |  |  | 11 | my @seqno_now = ( split /:/, $seqno_string ); | 
| 5165 | 3 | 50 | 33 |  |  | 49 | if (   @seqno_now | 
|  |  |  | 33 |  |  |  |  | 
|  |  |  | 33 |  |  |  |  | 
| 5166 |  |  |  |  |  |  | && @seqno_last | 
| 5167 |  |  |  |  |  |  | && $seqno_now[-1] == $seqno_last[0] | 
| 5168 |  |  |  |  |  |  | && $seqno_now[0] == $seqno_last[-1] ) | 
| 5169 |  |  |  |  |  |  | { | 
| 5170 |  |  |  |  |  |  |  | 
| 5171 |  |  |  |  |  |  | # OK to outdent .. | 
| 5172 |  |  |  |  |  |  | # for absolute safety, be sure we only remove | 
| 5173 |  |  |  |  |  |  | # whitespace | 
| 5174 | 3 |  |  |  |  | 10 | my $ws = substr( $test_line, 0, $diff ); | 
| 5175 | 3 | 50 | 33 |  |  | 33 | if ( ( length($ws) == $diff ) | 
| 5176 |  |  |  |  |  |  | && $ws =~ /^\s+$/ ) | 
| 5177 |  |  |  |  |  |  | { | 
| 5178 |  |  |  |  |  |  |  | 
| 5179 | 3 |  |  |  |  | 8 | $test_line = substr( $test_line, $diff ); | 
| 5180 | 3 |  |  |  |  | 9 | $cached_line_leading_space_count -= $diff; | 
| 5181 | 3 |  |  |  |  | 16 | $last_level_written = | 
| 5182 |  |  |  |  |  |  | $self->level_change( | 
| 5183 |  |  |  |  |  |  | $cached_line_leading_space_count, | 
| 5184 |  |  |  |  |  |  | $diff, $last_level_written ); | 
| 5185 | 3 |  |  |  |  | 20 | $self->reduce_valign_buffer_indentation($diff); | 
| 5186 |  |  |  |  |  |  | } | 
| 5187 |  |  |  |  |  |  |  | 
| 5188 |  |  |  |  |  |  | # shouldn't happen, but not critical: | 
| 5189 |  |  |  |  |  |  | ##else { | 
| 5190 |  |  |  |  |  |  | ## ERROR transferring indentation here | 
| 5191 |  |  |  |  |  |  | ##} | 
| 5192 |  |  |  |  |  |  | } | 
| 5193 |  |  |  |  |  |  | } | 
| 5194 |  |  |  |  |  |  | } | 
| 5195 |  |  |  |  |  |  |  | 
| 5196 |  |  |  |  |  |  | # Change the args to look like we received the combined line | 
| 5197 | 33 |  |  |  |  | 79 | $str                   = $test_line; | 
| 5198 | 33 |  |  |  |  | 67 | $str_length            = $test_line_length; | 
| 5199 | 33 |  |  |  |  | 70 | $leading_string        = EMPTY_STRING; | 
| 5200 | 33 |  |  |  |  | 63 | $leading_string_length = 0; | 
| 5201 | 33 |  |  |  |  | 66 | $leading_space_count   = $cached_line_leading_space_count; | 
| 5202 | 33 |  |  |  |  | 64 | $level                 = $last_level_written; | 
| 5203 | 33 |  |  |  |  | 75 | $maximum_line_length   = $cached_line_maximum_length; | 
| 5204 |  |  |  |  |  |  | } | 
| 5205 |  |  |  |  |  |  | else { | 
| 5206 | 4 |  |  |  |  | 26 | $self->valign_output_step_C( | 
| 5207 |  |  |  |  |  |  | $seqno_string, | 
| 5208 |  |  |  |  |  |  | $last_nonblank_seqno_string, | 
| 5209 |  |  |  |  |  |  |  | 
| 5210 |  |  |  |  |  |  | $cached_line_text, | 
| 5211 |  |  |  |  |  |  | $cached_line_leading_space_count, | 
| 5212 |  |  |  |  |  |  | $last_level_written, | 
| 5213 |  |  |  |  |  |  | $cached_line_Kend, | 
| 5214 |  |  |  |  |  |  | ); | 
| 5215 |  |  |  |  |  |  | } | 
| 5216 |  |  |  |  |  |  | } | 
| 5217 | 158 |  |  |  |  | 927 | return ( $str, $str_length, $leading_string, $leading_string_length, | 
| 5218 |  |  |  |  |  |  | $leading_space_count, $level, $maximum_line_length, ); | 
| 5219 |  |  |  |  |  |  |  | 
| 5220 |  |  |  |  |  |  | } ## end sub handle_cached_line | 
| 5221 |  |  |  |  |  |  |  | 
| 5222 |  |  |  |  |  |  | sub valign_output_step_B { | 
| 5223 |  |  |  |  |  |  |  | 
| 5224 |  |  |  |  |  |  | #--------------------------------------------------------- | 
| 5225 |  |  |  |  |  |  | # This is Step B in writing vertically aligned lines. | 
| 5226 |  |  |  |  |  |  | # Vertical tightness is applied according to preset flags. | 
| 5227 |  |  |  |  |  |  | # In particular this routine handles stacking of opening | 
| 5228 |  |  |  |  |  |  | # and closing tokens. | 
| 5229 |  |  |  |  |  |  | #--------------------------------------------------------- | 
| 5230 |  |  |  |  |  |  |  | 
| 5231 | 7376 |  |  | 7376 | 0 | 14702 | my ( $self, $rinput ) = @_; | 
| 5232 |  |  |  |  |  |  |  | 
| 5233 | 7376 |  |  |  |  | 13611 | my $leading_space_count       = $rinput->{leading_space_count}; | 
| 5234 | 7376 |  |  |  |  | 12755 | my $str                       = $rinput->{line}; | 
| 5235 | 7376 |  |  |  |  | 11428 | my $str_length                = $rinput->{line_length}; | 
| 5236 | 7376 |  |  |  |  | 10866 | my $side_comment_length       = $rinput->{side_comment_length}; | 
| 5237 | 7376 |  |  |  |  | 11982 | my $outdent_long_lines        = $rinput->{outdent_long_lines}; | 
| 5238 | 7376 |  |  |  |  | 11096 | my $rvertical_tightness_flags = $rinput->{rvertical_tightness_flags}; | 
| 5239 | 7376 |  |  |  |  | 11671 | my $level                     = $rinput->{level}; | 
| 5240 | 7376 |  |  |  |  | 11365 | my $level_end                 = $rinput->{level_end}; | 
| 5241 | 7376 |  |  |  |  | 11114 | my $Kend                      = $rinput->{Kend}; | 
| 5242 | 7376 |  |  |  |  | 10914 | my $maximum_line_length       = $rinput->{maximum_line_length}; | 
| 5243 |  |  |  |  |  |  |  | 
| 5244 |  |  |  |  |  |  | # Useful -gcs test cases for wide characters are | 
| 5245 |  |  |  |  |  |  | # perl527/(method.t.2, reg_mesg.t, mime-header.t) | 
| 5246 |  |  |  |  |  |  |  | 
| 5247 |  |  |  |  |  |  | # handle outdenting of long lines: | 
| 5248 | 7376 |  |  |  |  | 10882 | my $is_outdented_line; | 
| 5249 | 7376 | 100 |  |  |  | 14985 | if ($outdent_long_lines) { | 
| 5250 | 276 |  |  |  |  | 776 | my $excess = | 
| 5251 |  |  |  |  |  |  | $str_length - | 
| 5252 |  |  |  |  |  |  | $side_comment_length + | 
| 5253 |  |  |  |  |  |  | $leading_space_count - | 
| 5254 |  |  |  |  |  |  | $maximum_line_length; | 
| 5255 | 276 | 100 |  |  |  | 941 | if ( $excess > 0 ) { | 
| 5256 | 10 |  |  |  |  | 22 | $leading_space_count = 0; | 
| 5257 | 10 |  |  |  |  | 34 | my $file_writer_object = $self->[_file_writer_object_]; | 
| 5258 | 10 |  |  |  |  | 45 | my $last_outdented_line_at = | 
| 5259 |  |  |  |  |  |  | $file_writer_object->get_output_line_number(); | 
| 5260 | 10 |  |  |  |  | 25 | $self->[_last_outdented_line_at_] = $last_outdented_line_at; | 
| 5261 |  |  |  |  |  |  |  | 
| 5262 | 10 |  |  |  |  | 23 | my $outdented_line_count = $self->[_outdented_line_count_]; | 
| 5263 | 10 | 100 |  |  |  | 34 | if ( !$outdented_line_count ) { | 
| 5264 | 3 |  |  |  |  | 10 | $self->[_first_outdented_line_at_] = | 
| 5265 |  |  |  |  |  |  | $last_outdented_line_at; | 
| 5266 |  |  |  |  |  |  | } | 
| 5267 | 10 |  |  |  |  | 20 | $outdented_line_count++; | 
| 5268 | 10 |  |  |  |  | 16 | $self->[_outdented_line_count_] = $outdented_line_count; | 
| 5269 | 10 |  |  |  |  | 20 | $is_outdented_line = 1; | 
| 5270 |  |  |  |  |  |  | } | 
| 5271 |  |  |  |  |  |  | } | 
| 5272 |  |  |  |  |  |  |  | 
| 5273 |  |  |  |  |  |  | # Make preliminary leading whitespace.  It could get changed | 
| 5274 |  |  |  |  |  |  | # later by entabbing, so we have to keep track of any changes | 
| 5275 |  |  |  |  |  |  | # to the leading_space_count from here on. | 
| 5276 | 7376 | 100 |  |  |  | 18705 | my $leading_string = | 
| 5277 |  |  |  |  |  |  | $leading_space_count > 0 | 
| 5278 |  |  |  |  |  |  | ? ( SPACE x $leading_space_count ) | 
| 5279 |  |  |  |  |  |  | : EMPTY_STRING; | 
| 5280 | 7376 |  |  |  |  | 11777 | my $leading_string_length = length($leading_string); | 
| 5281 |  |  |  |  |  |  |  | 
| 5282 |  |  |  |  |  |  | # Unpack any recombination data; it was packed by | 
| 5283 |  |  |  |  |  |  | # sub 'Formatter::set_vertical_tightness_flags' | 
| 5284 |  |  |  |  |  |  |  | 
| 5285 |  |  |  |  |  |  | # old   hash              Meaning | 
| 5286 |  |  |  |  |  |  | # index key | 
| 5287 |  |  |  |  |  |  | # | 
| 5288 |  |  |  |  |  |  | # 0   _vt_type:           1=opening non-block    2=closing non-block | 
| 5289 |  |  |  |  |  |  | #                         3=opening block brace  4=closing block brace | 
| 5290 |  |  |  |  |  |  | # | 
| 5291 |  |  |  |  |  |  | # 1a  _vt_opening_flag:  1=no multiple steps, 2=multiple steps ok | 
| 5292 |  |  |  |  |  |  | # 1b  _vt_closing_flag:    spaces of padding to use if closing | 
| 5293 |  |  |  |  |  |  | # 2   _vt_seqno:          sequence number of container | 
| 5294 |  |  |  |  |  |  | # 3   _vt_valid flag:     do not append if this flag is false. Will be | 
| 5295 |  |  |  |  |  |  | #           true if appropriate -vt flag is set.  Otherwise, Will be | 
| 5296 |  |  |  |  |  |  | #           made true only for 2 line container in parens with -lp | 
| 5297 |  |  |  |  |  |  | # 4   _vt_seqno_beg:      sequence number of first token of line | 
| 5298 |  |  |  |  |  |  | # 5   _vt_seqno_end:      sequence number of last token of line | 
| 5299 |  |  |  |  |  |  | # 6   _vt_min_lines:      min number of lines for joining opening cache, | 
| 5300 |  |  |  |  |  |  | #                           0=no constraint | 
| 5301 |  |  |  |  |  |  | # 7   _vt_max_lines:      max number of lines for joining opening cache, | 
| 5302 |  |  |  |  |  |  | #                           0=no constraint | 
| 5303 |  |  |  |  |  |  |  | 
| 5304 | 7376 |  |  |  |  | 12521 | my ( $open_or_close, $opening_flag, $closing_flag, $seqno, $valid, | 
| 5305 |  |  |  |  |  |  | $seqno_beg, $seqno_end ); | 
| 5306 | 7376 | 100 |  |  |  | 14675 | if ($rvertical_tightness_flags) { | 
| 5307 |  |  |  |  |  |  |  | 
| 5308 | 1308 |  |  |  |  | 2268 | $open_or_close = $rvertical_tightness_flags->{_vt_type}; | 
| 5309 | 1308 |  |  |  |  | 2071 | $opening_flag  = $rvertical_tightness_flags->{_vt_opening_flag}; | 
| 5310 | 1308 |  |  |  |  | 2001 | $closing_flag  = $rvertical_tightness_flags->{_vt_closing_flag}; | 
| 5311 | 1308 |  |  |  |  | 2112 | $seqno         = $rvertical_tightness_flags->{_vt_seqno}; | 
| 5312 | 1308 |  |  |  |  | 2085 | $valid         = $rvertical_tightness_flags->{_vt_valid_flag}; | 
| 5313 | 1308 |  |  |  |  | 2151 | $seqno_beg     = $rvertical_tightness_flags->{_vt_seqno_beg}; | 
| 5314 | 1308 |  |  |  |  | 2087 | $seqno_end     = $rvertical_tightness_flags->{_vt_seqno_end}; | 
| 5315 |  |  |  |  |  |  | } | 
| 5316 |  |  |  |  |  |  |  | 
| 5317 | 7376 |  |  |  |  | 11590 | $seqno_string = $seqno_end; | 
| 5318 |  |  |  |  |  |  |  | 
| 5319 |  |  |  |  |  |  | # handle any cached line .. | 
| 5320 |  |  |  |  |  |  | # either append this line to it or write it out | 
| 5321 |  |  |  |  |  |  | # Note: the function length() is used in this next test out of caution. | 
| 5322 |  |  |  |  |  |  | # All testing has shown that the variable $cached_line_text_length is | 
| 5323 |  |  |  |  |  |  | # correct, but its calculation is complex and a loss of cached text | 
| 5324 |  |  |  |  |  |  | # would be a disaster. | 
| 5325 | 7376 | 100 |  |  |  | 15286 | if ( length($cached_line_text) ) { | 
| 5326 |  |  |  |  |  |  |  | 
| 5327 |  |  |  |  |  |  | ( | 
| 5328 | 158 |  |  |  |  | 843 | $str, | 
| 5329 |  |  |  |  |  |  | $str_length, | 
| 5330 |  |  |  |  |  |  | $leading_string, | 
| 5331 |  |  |  |  |  |  | $leading_string_length, | 
| 5332 |  |  |  |  |  |  | $leading_space_count, | 
| 5333 |  |  |  |  |  |  | $level, | 
| 5334 |  |  |  |  |  |  | $maximum_line_length | 
| 5335 |  |  |  |  |  |  |  | 
| 5336 |  |  |  |  |  |  | ) = $self->handle_cached_line( $rinput, $leading_string, | 
| 5337 |  |  |  |  |  |  | $leading_string_length ); | 
| 5338 |  |  |  |  |  |  |  | 
| 5339 | 158 |  |  |  |  | 343 | $cached_line_type           = 0; | 
| 5340 | 158 |  |  |  |  | 319 | $cached_line_text           = EMPTY_STRING; | 
| 5341 | 158 |  |  |  |  | 280 | $cached_line_text_length    = 0; | 
| 5342 | 158 |  |  |  |  | 269 | $cached_line_Kend           = undef; | 
| 5343 | 158 |  |  |  |  | 249 | $cached_line_maximum_length = undef; | 
| 5344 |  |  |  |  |  |  |  | 
| 5345 |  |  |  |  |  |  | } | 
| 5346 |  |  |  |  |  |  |  | 
| 5347 |  |  |  |  |  |  | # make the line to be written | 
| 5348 | 7376 |  |  |  |  | 15627 | my $line        = $leading_string . $str; | 
| 5349 | 7376 |  |  |  |  | 11841 | my $line_length = $leading_string_length + $str_length; | 
| 5350 |  |  |  |  |  |  |  | 
| 5351 |  |  |  |  |  |  | # Safety check: be sure that a line to be cached as a stacked block | 
| 5352 |  |  |  |  |  |  | # brace line ends in the appropriate opening or closing block brace. | 
| 5353 |  |  |  |  |  |  | # This should always be the case if the caller set flags correctly. | 
| 5354 |  |  |  |  |  |  | # Code '3' is for -sobb, code '4' is for -scbb. | 
| 5355 | 7376 | 100 |  |  |  | 14109 | if ($open_or_close) { | 
| 5356 | 159 | 50 | 66 |  |  | 1205 | if (   $open_or_close == 3 && $line !~ /\{\s*$/ | 
|  |  |  | 66 |  |  |  |  | 
|  |  |  | 33 |  |  |  |  | 
| 5357 |  |  |  |  |  |  | || $open_or_close == 4 && $line !~ /\}\s*$/ ) | 
| 5358 |  |  |  |  |  |  | { | 
| 5359 | 0 |  |  |  |  | 0 | $open_or_close = 0; | 
| 5360 |  |  |  |  |  |  | } | 
| 5361 |  |  |  |  |  |  | } | 
| 5362 |  |  |  |  |  |  |  | 
| 5363 |  |  |  |  |  |  | # write or cache this line ... | 
| 5364 |  |  |  |  |  |  | # fix for case b999: do not cache an outdented line | 
| 5365 |  |  |  |  |  |  | # fix for b1378: do not cache an empty line | 
| 5366 | 7376 | 100 | 66 |  |  | 21155 | if (  !$open_or_close | 
|  |  |  | 66 |  |  |  |  | 
|  |  |  | 33 |  |  |  |  | 
| 5367 |  |  |  |  |  |  | || $side_comment_length > 0 | 
| 5368 |  |  |  |  |  |  | || $is_outdented_line | 
| 5369 |  |  |  |  |  |  | || !$line_length ) | 
| 5370 |  |  |  |  |  |  | { | 
| 5371 | 7217 |  |  |  |  | 18101 | $self->valign_output_step_C( | 
| 5372 |  |  |  |  |  |  | $seqno_string, | 
| 5373 |  |  |  |  |  |  | $last_nonblank_seqno_string, | 
| 5374 |  |  |  |  |  |  |  | 
| 5375 |  |  |  |  |  |  | $line, | 
| 5376 |  |  |  |  |  |  | $leading_space_count, | 
| 5377 |  |  |  |  |  |  | $level, | 
| 5378 |  |  |  |  |  |  | $Kend, | 
| 5379 |  |  |  |  |  |  | ); | 
| 5380 |  |  |  |  |  |  | } | 
| 5381 |  |  |  |  |  |  | else { | 
| 5382 | 159 |  |  |  |  | 332 | $cached_line_text                = $line; | 
| 5383 | 159 |  |  |  |  | 311 | $cached_line_text_length         = $line_length; | 
| 5384 | 159 |  |  |  |  | 290 | $cached_line_type                = $open_or_close; | 
| 5385 | 159 |  |  |  |  | 352 | $cached_line_opening_flag        = $opening_flag; | 
| 5386 | 159 |  |  |  |  | 286 | $cached_line_closing_flag        = $closing_flag; | 
| 5387 | 159 |  |  |  |  | 284 | $cached_seqno                    = $seqno; | 
| 5388 | 159 |  |  |  |  | 279 | $cached_line_valid               = $valid; | 
| 5389 | 159 |  |  |  |  | 256 | $cached_line_leading_space_count = $leading_space_count; | 
| 5390 | 159 |  |  |  |  | 283 | $cached_seqno_string             = $seqno_string; | 
| 5391 | 159 |  |  |  |  | 246 | $cached_line_Kend                = $Kend; | 
| 5392 | 159 |  |  |  |  | 258 | $cached_line_maximum_length      = $maximum_line_length; | 
| 5393 |  |  |  |  |  |  | } | 
| 5394 |  |  |  |  |  |  |  | 
| 5395 | 7376 |  |  |  |  | 12590 | $self->[_last_level_written_]       = $level; | 
| 5396 | 7376 |  |  |  |  | 11411 | $self->[_last_side_comment_length_] = $side_comment_length; | 
| 5397 | 7376 |  |  |  |  | 16221 | return; | 
| 5398 |  |  |  |  |  |  | } ## end sub valign_output_step_B | 
| 5399 |  |  |  |  |  |  | } | 
| 5400 |  |  |  |  |  |  |  | 
| 5401 |  |  |  |  |  |  | ############################### | 
| 5402 |  |  |  |  |  |  | # CODE SECTION 8: Output Step C | 
| 5403 |  |  |  |  |  |  | ############################### | 
| 5404 |  |  |  |  |  |  |  | 
| 5405 |  |  |  |  |  |  | {    ## closure for sub valign_output_step_C | 
| 5406 |  |  |  |  |  |  |  | 
| 5407 |  |  |  |  |  |  | # Vertical alignment buffer used by valign_output_step_C | 
| 5408 |  |  |  |  |  |  | my $valign_buffer_filling; | 
| 5409 |  |  |  |  |  |  | my @valign_buffer; | 
| 5410 |  |  |  |  |  |  |  | 
| 5411 |  |  |  |  |  |  | sub initialize_valign_buffer { | 
| 5412 | 560 |  |  | 560 | 0 | 1621 | @valign_buffer         = (); | 
| 5413 | 560 |  |  |  |  | 1373 | $valign_buffer_filling = EMPTY_STRING; | 
| 5414 | 560 |  |  |  |  | 1091 | return; | 
| 5415 |  |  |  |  |  |  | } | 
| 5416 |  |  |  |  |  |  |  | 
| 5417 |  |  |  |  |  |  | sub dump_valign_buffer { | 
| 5418 | 1819 |  |  | 1819 | 0 | 3593 | my ($self) = @_; | 
| 5419 |  |  |  |  |  |  |  | 
| 5420 |  |  |  |  |  |  | # Send all lines in the current buffer on to step_D | 
| 5421 | 1819 | 100 |  |  |  | 4682 | if (@valign_buffer) { | 
| 5422 | 2 |  |  |  |  | 7 | foreach (@valign_buffer) { | 
| 5423 | 7 |  |  |  |  | 12 | $self->valign_output_step_D( @{$_} ); | 
|  | 7 |  |  |  |  | 21 |  | 
| 5424 |  |  |  |  |  |  | } | 
| 5425 | 2 |  |  |  |  | 11 | @valign_buffer = (); | 
| 5426 |  |  |  |  |  |  | } | 
| 5427 | 1819 |  |  |  |  | 3509 | $valign_buffer_filling = EMPTY_STRING; | 
| 5428 | 1819 |  |  |  |  | 3021 | return; | 
| 5429 |  |  |  |  |  |  | } ## end sub dump_valign_buffer | 
| 5430 |  |  |  |  |  |  |  | 
| 5431 |  |  |  |  |  |  | sub reduce_valign_buffer_indentation { | 
| 5432 |  |  |  |  |  |  |  | 
| 5433 | 3 |  |  | 3 | 0 | 12 | my ( $self, $diff ) = @_; | 
| 5434 |  |  |  |  |  |  |  | 
| 5435 |  |  |  |  |  |  | # Reduce the leading indentation of lines in the current | 
| 5436 |  |  |  |  |  |  | # buffer by $diff spaces | 
| 5437 | 3 | 100 | 66 |  |  | 17 | if ( $valign_buffer_filling && $diff ) { | 
| 5438 | 2 |  |  |  |  | 7 | my $max_valign_buffer = @valign_buffer; | 
| 5439 | 2 |  |  |  |  | 10 | foreach my $i ( 0 .. $max_valign_buffer - 1 ) { | 
| 5440 |  |  |  |  |  |  | my ( $line, $leading_space_count, $level, $Kend ) = | 
| 5441 | 7 |  |  |  |  | 11 | @{ $valign_buffer[$i] }; | 
|  | 7 |  |  |  |  | 18 |  | 
| 5442 | 7 |  |  |  |  | 19 | my $ws = substr( $line, 0, $diff ); | 
| 5443 | 7 | 50 | 33 |  |  | 42 | if ( ( length($ws) == $diff ) && $ws =~ /^\s+$/ ) { | 
| 5444 | 7 |  |  |  |  | 18 | $line = substr( $line, $diff ); | 
| 5445 |  |  |  |  |  |  | } | 
| 5446 | 7 | 50 |  |  |  | 16 | if ( $leading_space_count >= $diff ) { | 
| 5447 | 7 |  |  |  |  | 13 | $leading_space_count -= $diff; | 
| 5448 | 7 |  |  |  |  | 27 | $level = | 
| 5449 |  |  |  |  |  |  | $self->level_change( $leading_space_count, $diff, | 
| 5450 |  |  |  |  |  |  | $level ); | 
| 5451 |  |  |  |  |  |  | } | 
| 5452 | 7 |  |  |  |  | 49 | $valign_buffer[$i] = | 
| 5453 |  |  |  |  |  |  | [ $line, $leading_space_count, $level, $Kend ]; | 
| 5454 |  |  |  |  |  |  | } | 
| 5455 |  |  |  |  |  |  | } | 
| 5456 | 3 |  |  |  |  | 26 | return; | 
| 5457 |  |  |  |  |  |  | } ## end sub reduce_valign_buffer_indentation | 
| 5458 |  |  |  |  |  |  |  | 
| 5459 |  |  |  |  |  |  | sub valign_output_step_C { | 
| 5460 |  |  |  |  |  |  |  | 
| 5461 |  |  |  |  |  |  | #----------------------------------------------------------------------- | 
| 5462 |  |  |  |  |  |  | # This is Step C in writing vertically aligned lines. | 
| 5463 |  |  |  |  |  |  | # Lines are either stored in a buffer or passed along to the next step. | 
| 5464 |  |  |  |  |  |  | # The reason for storing lines is that we may later want to reduce their | 
| 5465 |  |  |  |  |  |  | # indentation when -sot and -sct are both used. | 
| 5466 |  |  |  |  |  |  | #----------------------------------------------------------------------- | 
| 5467 |  |  |  |  |  |  | my ( | 
| 5468 | 7325 |  |  | 7325 | 0 | 20880 | $self, | 
| 5469 |  |  |  |  |  |  | $seqno_string, | 
| 5470 |  |  |  |  |  |  | $last_nonblank_seqno_string, | 
| 5471 |  |  |  |  |  |  |  | 
| 5472 |  |  |  |  |  |  | @args_to_D, | 
| 5473 |  |  |  |  |  |  | ) = @_; | 
| 5474 |  |  |  |  |  |  |  | 
| 5475 |  |  |  |  |  |  | # Dump any saved lines if we see a line with an unbalanced opening or | 
| 5476 |  |  |  |  |  |  | # closing token. | 
| 5477 | 7325 | 100 | 100 |  |  | 17363 | $self->dump_valign_buffer() | 
| 5478 |  |  |  |  |  |  | if ( $seqno_string && $valign_buffer_filling ); | 
| 5479 |  |  |  |  |  |  |  | 
| 5480 |  |  |  |  |  |  | # Either store or write this line | 
| 5481 | 7325 | 100 |  |  |  | 13341 | if ($valign_buffer_filling) { | 
| 5482 | 7 |  |  |  |  | 40 | push @valign_buffer, [@args_to_D]; | 
| 5483 |  |  |  |  |  |  | } | 
| 5484 |  |  |  |  |  |  | else { | 
| 5485 | 7318 |  |  |  |  | 17040 | $self->valign_output_step_D(@args_to_D); | 
| 5486 |  |  |  |  |  |  | } | 
| 5487 |  |  |  |  |  |  |  | 
| 5488 |  |  |  |  |  |  | # For lines starting or ending with opening or closing tokens.. | 
| 5489 | 7325 | 100 |  |  |  | 14586 | if ($seqno_string) { | 
| 5490 | 394 |  |  |  |  | 711 | $last_nonblank_seqno_string = $seqno_string; | 
| 5491 | 394 |  |  |  |  | 1294 | set_last_nonblank_seqno_string($seqno_string); | 
| 5492 |  |  |  |  |  |  |  | 
| 5493 |  |  |  |  |  |  | # Start storing lines when we see a line with multiple stacked | 
| 5494 |  |  |  |  |  |  | # opening tokens. | 
| 5495 |  |  |  |  |  |  | # patch for RT #94354, requested by Colin Williams | 
| 5496 | 394 | 100 | 100 |  |  | 1886 | if (   index( $seqno_string, ':' ) >= 0 | 
|  |  |  | 100 |  |  |  |  | 
| 5497 |  |  |  |  |  |  | && $seqno_string =~ /^\d+(\:+\d+)+$/ | 
| 5498 |  |  |  |  |  |  | && $args_to_D[0] !~ /^[\}\)\]\:\?]/ ) | 
| 5499 |  |  |  |  |  |  | { | 
| 5500 |  |  |  |  |  |  |  | 
| 5501 |  |  |  |  |  |  | # This test is efficient but a little subtle: The first test | 
| 5502 |  |  |  |  |  |  | # says that we have multiple sequence numbers and hence | 
| 5503 |  |  |  |  |  |  | # multiple opening or closing tokens in this line.  The second | 
| 5504 |  |  |  |  |  |  | # part of the test rejects stacked closing and ternary tokens. | 
| 5505 |  |  |  |  |  |  | # So if we get here then we should have stacked unbalanced | 
| 5506 |  |  |  |  |  |  | # opening tokens. | 
| 5507 |  |  |  |  |  |  |  | 
| 5508 |  |  |  |  |  |  | # Here is a complex example: | 
| 5509 |  |  |  |  |  |  |  | 
| 5510 |  |  |  |  |  |  | # Foo($Bar[0], {  # (side comment) | 
| 5511 |  |  |  |  |  |  | #     baz => 1, | 
| 5512 |  |  |  |  |  |  | # }); | 
| 5513 |  |  |  |  |  |  |  | 
| 5514 |  |  |  |  |  |  | # The first line has sequence 6::4.  It does not begin with | 
| 5515 |  |  |  |  |  |  | # a closing token or ternary, so it passes the test and must be | 
| 5516 |  |  |  |  |  |  | # stacked opening tokens. | 
| 5517 |  |  |  |  |  |  |  | 
| 5518 |  |  |  |  |  |  | # The last line has sequence 4:6 but is a stack of closing | 
| 5519 |  |  |  |  |  |  | # tokens, so it gets rejected. | 
| 5520 |  |  |  |  |  |  |  | 
| 5521 |  |  |  |  |  |  | # Note that the sequence number of an opening token for a qw | 
| 5522 |  |  |  |  |  |  | # quote is a negative number and will be rejected.  For | 
| 5523 |  |  |  |  |  |  | # example, for the following line: skip_symbols([qw( | 
| 5524 |  |  |  |  |  |  | # $seqno_string='10:5:-1'.  It would be okay to accept it but I | 
| 5525 |  |  |  |  |  |  | # decided not to do this after testing. | 
| 5526 |  |  |  |  |  |  |  | 
| 5527 | 8 |  |  |  |  | 25 | $valign_buffer_filling = $seqno_string; | 
| 5528 |  |  |  |  |  |  |  | 
| 5529 |  |  |  |  |  |  | } | 
| 5530 |  |  |  |  |  |  | } | 
| 5531 | 7325 |  |  |  |  | 13755 | return; | 
| 5532 |  |  |  |  |  |  | } ## end sub valign_output_step_C | 
| 5533 |  |  |  |  |  |  | } | 
| 5534 |  |  |  |  |  |  |  | 
| 5535 |  |  |  |  |  |  | ############################### | 
| 5536 |  |  |  |  |  |  | # CODE SECTION 9: Output Step D | 
| 5537 |  |  |  |  |  |  | ############################### | 
| 5538 |  |  |  |  |  |  |  | 
| 5539 |  |  |  |  |  |  | sub valign_output_step_D { | 
| 5540 |  |  |  |  |  |  |  | 
| 5541 |  |  |  |  |  |  | #---------------------------------------------------------------- | 
| 5542 |  |  |  |  |  |  | # This is Step D in writing vertically aligned lines. | 
| 5543 |  |  |  |  |  |  | # It is the end of the vertical alignment pipeline. | 
| 5544 |  |  |  |  |  |  | # Write one vertically aligned line of code to the output object. | 
| 5545 |  |  |  |  |  |  | #---------------------------------------------------------------- | 
| 5546 |  |  |  |  |  |  |  | 
| 5547 | 7325 |  |  | 7325 | 0 | 16312 | my ( $self, $line, $leading_space_count, $level, $Kend ) = @_; | 
| 5548 |  |  |  |  |  |  |  | 
| 5549 |  |  |  |  |  |  | # The line is currently correct if there is no tabbing (recommended!) | 
| 5550 |  |  |  |  |  |  | # We may have to lop off some leading spaces and replace with tabs. | 
| 5551 | 7325 | 100 |  |  |  | 15794 | if ( $leading_space_count > 0 ) { | 
| 5552 |  |  |  |  |  |  |  | 
| 5553 | 4320 |  |  |  |  | 8318 | my $rOpts_indent_columns = $self->[_rOpts_indent_columns_]; | 
| 5554 | 4320 |  |  |  |  | 6942 | my $rOpts_tabs           = $self->[_rOpts_tabs_]; | 
| 5555 | 4320 |  |  |  |  | 7074 | my $rOpts_entab_leading_whitespace = | 
| 5556 |  |  |  |  |  |  | $self->[_rOpts_entab_leading_whitespace_]; | 
| 5557 |  |  |  |  |  |  |  | 
| 5558 |  |  |  |  |  |  | # Nothing to do if no tabs | 
| 5559 | 4320 | 100 | 66 |  |  | 18514 | if ( !( $rOpts_tabs || $rOpts_entab_leading_whitespace ) | 
|  |  | 50 | 66 |  |  |  |  | 
| 5560 |  |  |  |  |  |  | || $rOpts_indent_columns <= 0 ) | 
| 5561 |  |  |  |  |  |  | { | 
| 5562 |  |  |  |  |  |  |  | 
| 5563 |  |  |  |  |  |  | # nothing to do | 
| 5564 |  |  |  |  |  |  | } | 
| 5565 |  |  |  |  |  |  |  | 
| 5566 |  |  |  |  |  |  | # Handle entab option | 
| 5567 |  |  |  |  |  |  | elsif ($rOpts_entab_leading_whitespace) { | 
| 5568 |  |  |  |  |  |  |  | 
| 5569 |  |  |  |  |  |  | # Patch 12-nov-2018 based on report from Glenn. Extra padding was | 
| 5570 |  |  |  |  |  |  | # not correctly entabbed, nor were side comments: Increase leading | 
| 5571 |  |  |  |  |  |  | # space count for a padded line to get correct tabbing | 
| 5572 | 45 | 50 |  |  |  | 213 | if ( $line =~ /^(\s+)(.*)$/ ) { | 
| 5573 | 45 |  |  |  |  | 99 | my $spaces = length($1); | 
| 5574 | 45 | 50 |  |  |  | 86 | if ( $spaces > $leading_space_count ) { | 
| 5575 | 0 |  |  |  |  | 0 | $leading_space_count = $spaces; | 
| 5576 |  |  |  |  |  |  | } | 
| 5577 |  |  |  |  |  |  | } | 
| 5578 |  |  |  |  |  |  |  | 
| 5579 | 45 |  |  |  |  | 71 | my $space_count = | 
| 5580 |  |  |  |  |  |  | $leading_space_count % $rOpts_entab_leading_whitespace; | 
| 5581 | 45 |  |  |  |  | 86 | my $tab_count = | 
| 5582 |  |  |  |  |  |  | int( $leading_space_count / $rOpts_entab_leading_whitespace ); | 
| 5583 | 45 |  |  |  |  | 91 | my $leading_string = "\t" x $tab_count . SPACE x $space_count; | 
| 5584 | 45 | 50 |  |  |  | 464 | if ( $line =~ /^\s{$leading_space_count,$leading_space_count}/ ) { | 
| 5585 | 45 |  |  |  |  | 127 | substr( $line, 0, $leading_space_count ) = $leading_string; | 
| 5586 |  |  |  |  |  |  | } | 
| 5587 |  |  |  |  |  |  | else { | 
| 5588 |  |  |  |  |  |  |  | 
| 5589 |  |  |  |  |  |  | # shouldn't happen - program error counting whitespace | 
| 5590 |  |  |  |  |  |  | # - skip entabbing | 
| 5591 | 0 |  |  |  |  | 0 | DEBUG_TABS | 
| 5592 |  |  |  |  |  |  | && warning( | 
| 5593 |  |  |  |  |  |  | "Error entabbing in valign_output_step_D: expected count=$leading_space_count\n" | 
| 5594 |  |  |  |  |  |  | ); | 
| 5595 |  |  |  |  |  |  | } | 
| 5596 |  |  |  |  |  |  | } | 
| 5597 |  |  |  |  |  |  |  | 
| 5598 |  |  |  |  |  |  | # Handle option of one tab per level | 
| 5599 |  |  |  |  |  |  | else { | 
| 5600 | 0 |  |  |  |  | 0 | my $leading_string = ( "\t" x $level ); | 
| 5601 | 0 |  |  |  |  | 0 | my $space_count = | 
| 5602 |  |  |  |  |  |  | $leading_space_count - $level * $rOpts_indent_columns; | 
| 5603 |  |  |  |  |  |  |  | 
| 5604 |  |  |  |  |  |  | # shouldn't happen: | 
| 5605 | 0 | 0 |  |  |  | 0 | if ( $space_count < 0 ) { | 
| 5606 |  |  |  |  |  |  |  | 
| 5607 |  |  |  |  |  |  | # But it could be an outdented comment | 
| 5608 | 0 | 0 |  |  |  | 0 | if ( $line !~ /^\s*#/ ) { | 
| 5609 | 0 |  |  |  |  | 0 | DEBUG_TABS | 
| 5610 |  |  |  |  |  |  | && warning( | 
| 5611 |  |  |  |  |  |  | "Error entabbing in valign_output_step_D: for level=$level count=$leading_space_count\n" | 
| 5612 |  |  |  |  |  |  | ); | 
| 5613 |  |  |  |  |  |  | } | 
| 5614 | 0 |  |  |  |  | 0 | $leading_string = ( SPACE x $leading_space_count ); | 
| 5615 |  |  |  |  |  |  | } | 
| 5616 |  |  |  |  |  |  | else { | 
| 5617 | 0 |  |  |  |  | 0 | $leading_string .= ( SPACE x $space_count ); | 
| 5618 |  |  |  |  |  |  | } | 
| 5619 | 0 | 0 |  |  |  | 0 | if ( $line =~ /^\s{$leading_space_count,$leading_space_count}/ ) { | 
| 5620 | 0 |  |  |  |  | 0 | substr( $line, 0, $leading_space_count ) = $leading_string; | 
| 5621 |  |  |  |  |  |  | } | 
| 5622 |  |  |  |  |  |  | else { | 
| 5623 |  |  |  |  |  |  |  | 
| 5624 |  |  |  |  |  |  | # shouldn't happen - program error counting whitespace | 
| 5625 |  |  |  |  |  |  | # we'll skip entabbing | 
| 5626 | 0 |  |  |  |  | 0 | DEBUG_TABS | 
| 5627 |  |  |  |  |  |  | && warning( | 
| 5628 |  |  |  |  |  |  | "Error entabbing in valign_output_step_D: expected count=$leading_space_count\n" | 
| 5629 |  |  |  |  |  |  | ); | 
| 5630 |  |  |  |  |  |  | } | 
| 5631 |  |  |  |  |  |  | } | 
| 5632 |  |  |  |  |  |  | } | 
| 5633 | 7325 |  |  |  |  | 13191 | my $file_writer_object = $self->[_file_writer_object_]; | 
| 5634 | 7325 |  |  |  |  | 33529 | $file_writer_object->write_code_line( $line . "\n", $Kend ); | 
| 5635 |  |  |  |  |  |  |  | 
| 5636 | 7325 |  |  |  |  | 14517 | return; | 
| 5637 |  |  |  |  |  |  | } ## end sub valign_output_step_D | 
| 5638 |  |  |  |  |  |  |  | 
| 5639 |  |  |  |  |  |  | ########################## | 
| 5640 |  |  |  |  |  |  | # CODE SECTION 10: Summary | 
| 5641 |  |  |  |  |  |  | ########################## | 
| 5642 |  |  |  |  |  |  |  | 
| 5643 |  |  |  |  |  |  | sub report_anything_unusual { | 
| 5644 | 560 |  |  | 560 | 0 | 1387 | my $self = shift; | 
| 5645 |  |  |  |  |  |  |  | 
| 5646 | 560 |  |  |  |  | 1697 | my $outdented_line_count = $self->[_outdented_line_count_]; | 
| 5647 | 560 | 100 |  |  |  | 2144 | if ( $outdented_line_count > 0 ) { | 
| 5648 | 21 |  |  |  |  | 159 | write_logfile_entry( | 
| 5649 |  |  |  |  |  |  | "$outdented_line_count long lines were outdented:\n"); | 
| 5650 | 21 |  |  |  |  | 107 | my $first_outdented_line_at = $self->[_first_outdented_line_at_]; | 
| 5651 | 21 |  |  |  |  | 155 | write_logfile_entry( | 
| 5652 |  |  |  |  |  |  | "  First at output line $first_outdented_line_at\n"); | 
| 5653 |  |  |  |  |  |  |  | 
| 5654 | 21 | 100 |  |  |  | 198 | if ( $outdented_line_count > 1 ) { | 
| 5655 | 7 |  |  |  |  | 35 | my $last_outdented_line_at = $self->[_last_outdented_line_at_]; | 
| 5656 | 7 |  |  |  |  | 39 | write_logfile_entry( | 
| 5657 |  |  |  |  |  |  | "   Last at output line $last_outdented_line_at\n"); | 
| 5658 |  |  |  |  |  |  | } | 
| 5659 |  |  |  |  |  |  | write_logfile_entry( | 
| 5660 | 21 |  |  |  |  | 160 | "  use -noll to prevent outdenting, -l=n to increase line length\n" | 
| 5661 |  |  |  |  |  |  | ); | 
| 5662 | 21 |  |  |  |  | 154 | write_logfile_entry("\n"); | 
| 5663 |  |  |  |  |  |  | } | 
| 5664 | 560 |  |  |  |  | 1396 | return; | 
| 5665 |  |  |  |  |  |  | } ## end sub report_anything_unusual | 
| 5666 |  |  |  |  |  |  | 1; |