From: Steve Hancock Date: Sat, 25 Dec 2021 19:19:33 +0000 (-0800) Subject: rewrote sub collapsed_lengths, same functionality X-Git-Tag: 20211029.05~19 X-Git-Url: https://git.donarmstrong.com/?a=commitdiff_plain;h=fec62d111f44c583c01dd82260ff9a10d1919295;p=perltidy.git rewrote sub collapsed_lengths, same functionality --- diff --git a/lib/Perl/Tidy/Formatter.pm b/lib/Perl/Tidy/Formatter.pm index 68dc0f0c..5950d8f6 100644 --- a/lib/Perl/Tidy/Formatter.pm +++ b/lib/Perl/Tidy/Formatter.pm @@ -1288,7 +1288,8 @@ arbitrarily large numbers of line breakpoints. This isn't possible with these flags. ----------------------------------------------------------------------- EOM - $rOpts->{'line-up-parentheses'} = 0; + $rOpts->{'line-up-parentheses'} = 0; + $rOpts->{'extended-line-up-parentheses'} = 0; } if ( $rOpts->{'whitespace-cycle'} ) { @@ -5332,7 +5333,7 @@ EOM $self->find_multiline_qw(); $self->collapsed_lengths() - if ($rOpts_extended_line_up_parentheses); + if ( $rOpts_line_up_parentheses && $rOpts_extended_line_up_parentheses ); $self->keep_old_line_breaks(); @@ -10437,6 +10438,9 @@ BEGIN { use constant { _max_prong_len_ => $i++, _handle_len_ => $i++, + _seqno_o_ => $i++, + _iline_o_ => $i++, + _K_o_ => $i++, }; } @@ -10450,12 +10454,13 @@ sub collapsed_lengths { # We need an estimate of the minimum required line length starting at any # opening container for the -xlp style. This is needed to avoid using too - # much indentation space for lower level containers and thereby causing - # outer container tokens to get excessive line breaks due to the maximum - # line length limit. + # much indentation space for lower level containers and thereby running + # out of space for outer container tokens due to the maximum line length + # limit. - # At each node in the tree we imagine that we have a fork with a handle - # and collapsable prongs: + # The basic idea is that at each node in the tree we imagine that we have a + # fork with a handle and collapsable prongs: + # # |------------ # |-------- # ------------|------- @@ -10468,7 +10473,7 @@ sub collapsed_lengths { # the prongs may itself be a tree node. # This is just a rough calculation to get an approximate starting point for - # indentation. Later routines can be more precise. It is important that + # indentation. Later routines will be more precise. It is important that # these estimates be independent of the line breaks of the input stream in # order to avoid instabilities. @@ -10480,61 +10485,199 @@ sub collapsed_lengths { my $rblock_type_of_seqno = $self->[_rblock_type_of_seqno_]; my $rcollapsed_length_by_seqno = $self->[_rcollapsed_length_by_seqno_]; + my $ris_excluded_lp_container = $self->[_ris_excluded_lp_container_]; my $max_prong_len = 0; my $handle_len = 0; my @stack; - push @stack, [ $max_prong_len, $handle_len ]; - - #---------------------------------- - # step through all sequenced tokens - #---------------------------------- - my $last_nonblank_type = 'b'; my $len = 0; - my $KK = -1; - my $KNEXT = $self->[_K_first_seq_item_]; - my $type; - while ( defined($KNEXT) ) { - my $Kstop = $KNEXT; - $KNEXT = $rLL->[$Kstop]->[_KNEXT_SEQ_ITEM_]; + my $last_nonblank_type = 'b'; + push @stack, [ $max_prong_len, $handle_len, SEQ_ROOT, undef, undef ]; - #----------------------------- - # scan to next sequenced token - #----------------------------- - $len = 0; - while ( ++$KK <= $Kstop - 1 ) { - my $rtoken_vars = $rLL->[$KK]; - $type = $rtoken_vars->[_TYPE_]; - if ( $type eq 'b' ) { next } + my $iline = -1; + foreach my $line_of_tokens ( @{$rlines} ) { + $iline++; + my $line_type = $line_of_tokens->{_line_type}; + next if ( $line_type ne 'CODE' ); + my $CODE_type = $line_of_tokens->{_code_type}; - my $token_length = $rtoken_vars->[_TOKEN_LENGTH_]; + # Always skip blank lines + next if ( $CODE_type eq 'BL' ); - # Comments ... - if ( $type eq '#' ) { + # Note on other line types: + # 'FS' (Format Skipping) lines may contain opening/closing tokens so + # we have to process them to keep the stack correctly sequenced. + # 'VB' (Verbatim) lines could be skipped, but testing shows that + # results look better if we include their lengths. - # ignore all comments if -iscl is set (recommended setting) - if ($rOpts_ignore_side_comment_lengths) { - $len = 0; - next; + # Also note that we could exclude -xlp formatting of containers with + # 'FS' and 'VB' lines, but in testing that was not really beneficial. + + # So we process tokens in 'FS' and 'VB' lines like all the rest... + + my $rK_range = $line_of_tokens->{_rK_range}; + my ( $K_first, $K_last ) = @{$rK_range}; + next unless ( defined($K_first) && defined($K_last) ); + + my $has_comment = $rLL->[$K_last]->[_TYPE_] eq '#'; + + # Always ignore block comments + next if ( $has_comment && $K_first == $K_last ); + + # Find the terminal token, before any side comment + my $K_terminal = $K_last; + if ($has_comment) { + $K_terminal -= 1; + $K_terminal -= 1 + if ( $rLL->[$K_terminal]->[_TYPE_] eq 'b' + && $K_terminal > $K_first ); + } + + # Loop over tokens on this line ... + foreach my $KK ( $K_first .. $K_terminal ) { + + my $type = $rLL->[$KK]->[_TYPE_]; + next if ( $type eq 'b' ); + + #------------------------ + # Handle sequenced tokens + #------------------------ + my $seqno = $rLL->[$KK]->[_TYPE_SEQUENCE_]; + if ($seqno) { + + my $token = $rLL->[$KK]->[_TOKEN_]; + + #---------------------------- + # Entering a new container... + #---------------------------- + if ( $is_opening_token{$token} ) { + + # save current prong length + $stack[-1]->[_max_prong_len_] = $max_prong_len; + $max_prong_len = 0; + + # Start new prong one level deeper + my $handle_len = 0; + if ( $rblock_type_of_seqno->{$seqno} ) { + + # code blocks do not use -lp indentation, but behave as + # if they had a handle of one indentation length + $handle_len = $rOpts_indent_columns; + + } + elsif ( $is_handle_type{$last_nonblank_type} ) { + $handle_len = $len; + $handle_len += 1 + if ( $KK > 0 && $rLL->[ $KK - 1 ]->[_TYPE_] eq 'b' ); + } + push @stack, + [ $max_prong_len, $handle_len, $seqno, $iline, $KK ]; } - # block comments lengths are always ignored - my $iline = $rLL->[$KK]->[_LINE_INDEX_]; - my $rK_range = $rlines->[$iline]->{_rK_range}; - my ( $K_first, $K_last ) = @{$rK_range}; - if ( defined($K_first) && $KK == $K_first ) { - $len = 0; - next; + #-------------------- + # Exiting a container + #-------------------- + elsif ( $is_closing_token{$token} ) { + if (@stack) { + + # The current prong ends - get its handle + my $item = pop @stack; + my $handle_len = $item->[_handle_len_]; + my $seqno_o = $item->[_seqno_o_]; + my $iline_o = $item->[_iline_o_]; + my $K_o = $item->[_K_o_]; + my $collapsed_len = $max_prong_len; + + if ( $seqno_o ne $seqno ) { + + # Shouldn't happen - some lines must have been skipped. + # Not fatal but some formatting could get messed up. + if (DEVEL_MODE) { + Fault(<{$seqno} ) { + + my $K_c = $KK; + my $block_length = MIN_BLOCK_LEN; + my $is_one_line_block; + my $level = $rLL->[$K_o]->[_LEVEL_]; + if ( defined($K_o) && defined($K_c) ) { + my $block_length = + $rLL->[ $K_c - 1 ]->[_CUMULATIVE_LENGTH_] - + $rLL->[$K_o]->[_CUMULATIVE_LENGTH_]; + $is_one_line_block = $iline == $iline_o; + } + + # Code block rule 1: Use the total block length if + # it is less than the minimum. + if ( $block_length < MIN_BLOCK_LEN ) { + $collapsed_len = $block_length; + } + + # Code block rule 2: Use the full length of a + # one-line block to avoid breaking it, unless + # extremely long. We do not need to do a precise + # check here, because if it breaks then it will + # stay broken on later iterations. + elsif ($is_one_line_block + && $block_length < + $maximum_line_length_at_level[$level] ) + { + $collapsed_len = $block_length; + } + + # Code block rule 3: Otherwise the length should be + # at least MIN_BLOCK_LEN to avoid scrunching code + # blocks. + elsif ( $collapsed_len < MIN_BLOCK_LEN ) { + $collapsed_len = MIN_BLOCK_LEN; + } + } + + # Store the result. Some extra space, '2', allows for + # length of an opening token, inside space, comma, ... + # This constant has been tuned to give good overall + # results. + $collapsed_len += 2; + $rcollapsed_length_by_seqno->{$seqno} = $collapsed_len; + + # Restart scanning the lower level prong + if (@stack) { + $max_prong_len = $stack[-1]->[_max_prong_len_]; + $collapsed_len += $handle_len; + if ( $collapsed_len > $max_prong_len ) { + $max_prong_len = $collapsed_len; + } + } + } } - # For a side comment when -iscl is NOT set, include length of - # the previous token and 1 space - $len += $token_length + 1; - if ( $len > $max_prong_len ) { $max_prong_len = $len } + # it is a ternary - no special processing for these yet + else { + + } + + $len = 0; + $last_nonblank_type = $type; + next; } + #---------------------------- + # Handle non-container tokens + #---------------------------- + my $token_length = $rLL->[$KK]->[_TOKEN_LENGTH_]; + # Count lengths of things like 'xx => yy' as a single item - elsif ( $type eq '=>' ) { + if ( $type eq '=>' ) { $len += $token_length + 1; if ( $len > $max_prong_len ) { $max_prong_len = $len } } @@ -10542,131 +10685,45 @@ sub collapsed_lengths { $len += $token_length; if ( $len > $max_prong_len ) { $max_prong_len = $len } - # only one => per item + # but only include one => per item if ( $last_nonblank_type eq '=>' ) { $len = $token_length } } + + # include everthing to end of line after a here target elsif ( $type eq 'h' ) { - my $iline = $rLL->[$KK]->[_LINE_INDEX_]; - my $rK_range = $rlines->[$iline]->{_rK_range}; - my ( $K_first, $K_last ) = @{$rK_range}; $len = $rLL->[$K_last]->[_CUMULATIVE_LENGTH_] - $rLL->[ $KK - 1 ]->[_CUMULATIVE_LENGTH_]; if ( $len > $max_prong_len ) { $max_prong_len = $len } } + + # for everything else just use the token length else { $len = $token_length; if ( $len > $max_prong_len ) { $max_prong_len = $len } } - $last_nonblank_type = $type; - } - - #------------------------------ - # now handle the sequenced item - #------------------------------ - my $token = $rLL->[$Kstop]->[_TOKEN_]; - my $seqno = $rLL->[$Kstop]->[_TYPE_SEQUENCE_]; - #---------------------------- - # entering a new container... - #---------------------------- - if ( $is_opening_token{$token} ) { + } ## end loop over tokens on this line - # save current prong length - $stack[-1]->[_max_prong_len_] = $max_prong_len; - $max_prong_len = 0; - - # Start new prong one level deeper - my $handle_len = 0; - if ( $rblock_type_of_seqno->{$seqno} ) { - - # code blocks do not use -lp indentation, but behave as if they - # had a handle of one indentation length - $handle_len = $rOpts_indent_columns; - - } - elsif ( $is_handle_type{$last_nonblank_type} ) { - $handle_len = $len; - $handle_len += 1 if ( $type eq 'b' ); + # Now take care of any side comment + if ($has_comment) { + if ($rOpts_ignore_side_comment_lengths) { + $len = 0; } + else { - push @stack, [ $max_prong_len, $handle_len ]; - } - - #-------------------- - # exiting a container - #-------------------- - elsif ( $is_closing_token{$token} ) { - if (@stack) { - - # The current prong ends - get its handle - my $item = pop @stack; - my $handle_len = $item->[_handle_len_]; - my $collapsed_len = $max_prong_len; - - #------------------------------------------ - # Rules to avoid scrunching code blocks ... - #------------------------------------------ - # Some test cases: - # c098/x107 x108 x110 x112 x114 x115 x117 x118 x119 - if ( $rblock_type_of_seqno->{$seqno} ) { - - my $K_o = $K_opening_container->{$seqno}; - my $K_c = $K_closing_container->{$seqno}; - my $block_length = MIN_BLOCK_LEN; - my $is_one_line_block; - my $level = $rLL->[$K_o]->[_LEVEL_]; - if ( defined($K_o) && defined($K_c) ) { - my $iline_o = $rLL->[$K_o]->[_LINE_INDEX_]; - my $iline_c = $rLL->[$K_c]->[_LINE_INDEX_]; - my $block_length = - $rLL->[ $K_c - 1 ]->[_CUMULATIVE_LENGTH_] - - $rLL->[$K_o]->[_CUMULATIVE_LENGTH_]; - $is_one_line_block = $iline_c == $iline_o; - } - - # Code block rule 1: Use the total block length if it is - # less than the minimum. - if ( $block_length < MIN_BLOCK_LEN ) { - $collapsed_len = $block_length; - } - - # Code block rule 2: Use the full length of a one-line - # block to avoid breaking it, unless extremely long. We do - # not need to do a precise check here, because if it breaks - # then it will stay broken on later iterations. - elsif ($is_one_line_block - && $block_length < - $maximum_line_length_at_level[$level] ) - { - $collapsed_len = $block_length; - } - - # Code block rule 3: Otherwise the length should be at - # least MIN_BLOCK_LEN to avoid scrunching code blocks. - elsif ( $collapsed_len < MIN_BLOCK_LEN ) { - $collapsed_len = MIN_BLOCK_LEN; - } - } - - # Store the result. Some extra space, '2', allows for - # length of an opening token, inside space, comma, ... - # This constant has been tuned to give good overall results. - $collapsed_len += 2; - $rcollapsed_length_by_seqno->{$seqno} = $collapsed_len; - - # Restart scanning the lower level prong - if (@stack) { - $max_prong_len = $stack[-1]->[_max_prong_len_]; - $collapsed_len += $handle_len; - if ( $collapsed_len > $max_prong_len ) { - $max_prong_len = $collapsed_len; - } - } + # For a side comment when -iscl is not set, measure length from + # the start of the previous nonblank token + my $len0 = + $K_terminal > 0 + ? $rLL->[ $K_terminal - 1 ]->[_CUMULATIVE_LENGTH_] + : 0; + $len = $rLL->[$K_last]->[_CUMULATIVE_LENGTH_] - $len0; + if ( $len > $max_prong_len ) { $max_prong_len = $len } } } - $last_nonblank_type = $rLL->[$Kstop]->[_TYPE_]; - } + + } ## end loop over lines if (DEBUG_COLLAPSED_LENGTHS) { print "\nCollapsed lengths--\n"; @@ -10678,7 +10735,6 @@ sub collapsed_lengths { } } - # we could get the collapsed length of the tree root here but do not need it return; }