$rpatterns, $ri_first,
$ri_last, $rindentation_list,
$level_jump, $starting_in_quote,
- $is_static_block_comment,
+ $is_static_block_comment
) = @_;
# Find the last code token of this line
my $seqno_beg = $type_sequence_to_go[$ibeg];
my $is_closing_type_beg = $is_closing_type{$type_beg};
- my $ris_bli_container = $self->[_ris_bli_container_];
- my $is_bli_beg = $seqno_beg ? $ris_bli_container->{$seqno_beg} : 0;
-
# QW INDENTATION PATCH 3:
my $seqno_qw_closing;
if ( $type_beg eq 'q' && $ibeg == 0 ) {
# 2 - vertically align with opening token
# 3 - indent
#---------------------------------------------------------
+
my $adjust_indentation = 0;
- my $default_adjust_indentation = $adjust_indentation;
+ my $default_adjust_indentation = 0;
+ # Parameters needed for option 2, aligning with opening token:
my (
$opening_indentation, $opening_offset,
$is_leading, $opening_exists
);
- # Honor any flag to reduce -ci set by the -bbxi=n option
- if ( $seqno_beg && $self->[_rwant_reduced_ci_]->{$seqno_beg} ) {
+ #-------------------------------------
+ # Section 1A:
+ # if line starts with a sequenced item
+ #-------------------------------------
+ if ( $seqno_beg || $seqno_qw_closing ) {
- # if this is an opening, it must be alone on the line ...
- if ( $is_closing_type{$type_beg} || $ibeg == $i_terminal ) {
- $adjust_indentation = 1;
- }
+ # This can be tedious so we let a sub do it
+ (
+ $adjust_indentation, $default_adjust_indentation,
+ $opening_indentation, $opening_offset,
+ $is_leading, $opening_exists
+ )
+ = $self->get_closing_token_indentation(
+
+ $ibeg,
+ $iend,
+ $ri_first,
+ $ri_last,
+ $rindentation_list,
+ $level_jump,
+ $i_terminal,
+ $is_semicolon_terminated,
+ $seqno_qw_closing,
- # ... or a single welded unit (fix for b1173)
- elsif ($total_weld_count) {
- my $K_beg = $K_to_go[$ibeg];
- my $Kterm = $K_to_go[$i_terminal];
- my $Kterm_test = $self->[_rK_weld_left_]->{$Kterm};
- if ( defined($Kterm_test) && $Kterm_test >= $K_beg ) {
- $Kterm = $Kterm_test;
- }
- if ( $Kterm == $K_beg ) { $adjust_indentation = 1 }
- }
+ );
}
- # Update the $is_bli flag as we go. It is initially 1.
- # We note seeing a leading opening brace by setting it to 2.
- # If we get to the closing brace without seeing the opening then we
- # turn it off. This occurs if the opening brace did not get output
- # at the start of a line, so we will then indent the closing brace
- # in the default way.
- if ( $is_bli_beg && $is_bli_beg == 1 ) {
- my $K_opening_container = $self->[_K_opening_container_];
- my $K_opening = $K_opening_container->{$seqno_beg};
- my $K_beg = $K_to_go[$ibeg];
- if ( $K_beg eq $K_opening ) {
- $ris_bli_container->{$seqno_beg} = $is_bli_beg = 2;
+ #--------------------------------------------------------
+ # Section 1B:
+ # if at ');', '};', '>;', and '];' of a terminal qw quote
+ #--------------------------------------------------------
+ elsif (
+ substr( $rpatterns->[0], 0, 2 ) eq 'qb'
+ && substr( $rfields->[0], -1, 1 ) eq ';'
+ ## $rpatterns->[0] =~ /^qb*;$/
+ && $rfields->[0] =~ /^([\)\}\]\>]);$/
+ )
+ {
+ if ( $closing_token_indentation{$1} == 0 ) {
+ $adjust_indentation = 1;
}
- else { $is_bli_beg = 0 }
- }
-
- # QW PATCH for the combination -lp -wn
- # For -lp formatting use $ibeg_weld_fix to get around the problem
- # that with -lp type formatting the opening and closing tokens to not
- # have sequence numbers.
- my $ibeg_weld_fix = $ibeg;
- if ( $seqno_qw_closing && $total_weld_count ) {
- my $i_plus = $inext_to_go[$ibeg];
- if ( $i_plus <= $max_index_to_go ) {
- my $K_plus = $K_to_go[$i_plus];
- if ( defined( $self->[_rK_weld_left_]->{$K_plus} ) ) {
- $ibeg_weld_fix = $i_plus;
- }
+ else {
+ $adjust_indentation = 3;
}
}
- # if we are at a closing token of some type..
- if ( $is_closing_type_beg || $seqno_qw_closing ) {
-
- my $K_beg = $K_to_go[$ibeg];
-
- # get the indentation of the line containing the corresponding
- # opening token
- (
- $opening_indentation, $opening_offset,
- $is_leading, $opening_exists
- )
- = $self->get_opening_indentation( $ibeg_weld_fix, $ri_first,
- $ri_last, $rindentation_list, $seqno_qw_closing );
-
- my $terminal_is_in_list = $self->is_in_list_by_i($i_terminal);
-
- # First set the default behavior:
- if (
+ #---------------------------------------------------------
+ # Section 2: set indentation according to flag set above
+ #
+ # Select the indentation object to define leading
+ # whitespace. If we are outdenting something like '} } );'
+ # then we want to use one level below the last token
+ # ($i_terminal) in order to get it to fully outdent through
+ # all levels.
+ #---------------------------------------------------------
+ my $indentation;
+ my $lev;
+ my $level_end = $levels_to_go[$iend];
- # default behavior is to outdent closing lines
- # of the form: "); }; ]; )->xxx;"
- $is_semicolon_terminated
+ #------------------------------------
+ # Section 2A: adjust_indentation == 0
+ # No change in indentation
+ #------------------------------------
+ if ( $adjust_indentation == 0 ) {
+ $indentation = $leading_spaces_beg;
+ $lev = $level_beg;
+ }
- # and 'cuddled parens' of the form: ")->pack("
- # Bug fix for RT #123749]: the types here were
- # incorrectly '(' and ')'. Corrected to be '{' and '}'
- || (
- $terminal_type eq '{'
- && $type_beg eq '}'
- && ( $nesting_depth_to_go[$iend] + 1 ==
- $nesting_depth_to_go[$ibeg] )
- )
+ #-------------------------------------------------------------------
+ # Secton 2B: adjust_indentation == 1
+ # Change the indentation to be that of a different token on the line
+ #-------------------------------------------------------------------
+ elsif ( $adjust_indentation == 1 ) {
- # remove continuation indentation for any line like
- # } ... {
- # or without ending '{' and unbalanced, such as
- # such as '}->{$operator}'
- || (
- $type_beg eq '}'
+ # Previously, the indentation of the terminal token was used:
+ # OLD CODING:
+ # $indentation = $reduced_spaces_to_go[$i_terminal];
+ # $lev = $levels_to_go[$i_terminal];
- && ( $types_to_go[$iend] eq '{'
- || $levels_to_go[$iend] < $level_beg )
- )
+ # Generalization for MOJO patch:
+ # Use the lowest level indentation of the tokens on the line.
+ # For example, here we can use the indentation of the ending ';':
+ # } until ($selection > 0 and $selection < 10); # ok to use ';'
+ # But this will not outdent if we use the terminal indentation:
+ # )->then( sub { # use indentation of the ->, not the {
+ # Warning: reduced_spaces_to_go[] may be a reference, do not
+ # do numerical checks with it
- # and when the next line is at a lower indentation level...
+ my $i_ind = $ibeg;
+ $indentation = $reduced_spaces_to_go[$i_ind];
+ $lev = $levels_to_go[$i_ind];
+ while ( $i_ind < $i_terminal ) {
+ $i_ind++;
+ if ( $levels_to_go[$i_ind] < $lev ) {
+ $indentation = $reduced_spaces_to_go[$i_ind];
+ $lev = $levels_to_go[$i_ind];
+ }
+ }
+ }
- # PATCH #1: and only if the style allows undoing continuation
- # for all closing token types. We should really wait until
- # the indentation of the next line is known and then make
- # a decision, but that would require another pass.
+ #--------------------------------------------------------------
+ # Secton 2C: adjust_indentation == 2
+ # Handle indented closing token which aligns with opening token
+ #--------------------------------------------------------------
+ elsif ( $adjust_indentation == 2 ) {
- # PATCH #2: and not if this token is under -xci control
- || ( $level_jump < 0
- && !$some_closing_token_indentation
- && !$self->[_rseqno_controlling_my_ci_]->{$K_beg} )
+ # handle option to align closing token with opening token
+ $lev = $level_beg;
- # Patch for -wn=2, multiple welded closing tokens
- || ( $i_terminal > $ibeg
- && $is_closing_type{ $types_to_go[$iend] } )
+ # calculate spaces needed to align with opening token
+ my $space_count =
+ get_spaces($opening_indentation) + $opening_offset;
- # Alternate Patch for git #51, isolated closing qw token not
- # outdented if no-delete-old-newlines is set. This works, but
- # a more general patch elsewhere fixes the real problem: ljump.
- # || ( $seqno_qw_closing && $ibeg == $i_terminal )
+ # Indent less than the previous line.
+ #
+ # Problem: For -lp we don't exactly know what it was if there
+ # were recoverable spaces sent to the aligner. A good solution
+ # would be to force a flush of the vertical alignment buffer, so
+ # that we would know. For now, this rule is used for -lp:
+ #
+ # When the last line did not start with a closing token we will
+ # be optimistic that the aligner will recover everything wanted.
+ #
+ # This rule will prevent us from breaking a hierarchy of closing
+ # tokens, and in a worst case will leave a closing paren too far
+ # indented, but this is better than frequently leaving it not
+ # indented enough.
+ my $last_spaces = get_spaces($last_indentation_written);
- )
+ if ( ref($last_indentation_written)
+ && !$is_closing_token{$last_leading_token} )
{
- $adjust_indentation = 1;
+ $last_spaces +=
+ get_recoverable_spaces($last_indentation_written);
}
- # outdent something like '),'
- if (
- $terminal_type eq ','
-
- # Removed this constraint for -wn
- # OLD: allow just one character before the comma
- # && $i_terminal == $ibeg + 1
+ # reset the indentation to the new space count if it works
+ # only options are all or none: nothing in-between looks good
+ $lev = $level_beg;
- # require LIST environment; otherwise, we may outdent too much -
- # this can happen in calls without parentheses (overload.t);
- && $terminal_is_in_list
- )
- {
- $adjust_indentation = 1;
+ my $diff = $last_spaces - $space_count;
+ if ( $diff > 0 ) {
+ $indentation = $space_count;
}
+ else {
- # undo continuation indentation of a terminal closing token if
- # it is the last token before a level decrease. This will allow
- # a closing token to line up with its opening counterpart, and
- # avoids an indentation jump larger than 1 level.
- my $rLL = $self->[_rLL_];
- my $Klimit = $self->[_Klimit_];
- if ( $i_terminal == $ibeg
- && $is_closing_type_beg
- && defined($K_beg)
- && $K_beg < $Klimit )
- {
- my $K_plus = $K_beg + 1;
- my $type_plus = $rLL->[$K_plus]->[_TYPE_];
+ # We need to fix things ... but there is no good way to do it.
+ # The best solution is for the user to use a longer maximum
+ # line length. We could get a smooth variation if we just move
+ # the paren in using
+ # $space_count -= ( 1 - $diff );
+ # But unfortunately this can give a rather unbalanced look.
- if ( $type_plus eq 'b' && $K_plus < $Klimit ) {
- $type_plus = $rLL->[ ++$K_plus ]->[_TYPE_];
+ # For -xlp we currently allow a tolerance of one indentation
+ # level and then revert to a simpler default. This will jump
+ # suddenly but keeps a balanced look.
+ if ( $rOpts_extended_line_up_parentheses
+ && $diff >= -$rOpts_indent_columns
+ && $space_count > $leading_spaces_beg )
+ {
+ $indentation = $space_count;
}
- if ( $type_plus eq '#' && $K_plus < $Klimit ) {
- $type_plus = $rLL->[ ++$K_plus ]->[_TYPE_];
- if ( $type_plus eq 'b' && $K_plus < $Klimit ) {
- $type_plus = $rLL->[ ++$K_plus ]->[_TYPE_];
- }
-
- # Note: we have skipped past just one comment (perhaps a
- # side comment). There could be more, and we could easily
- # skip past all the rest with the following code, or with a
- # while loop. It would be rare to have to do this, and
- # those block comments would still be indented, so it would
- # to leave them indented. So it seems best to just stop at
- # a maximum of one comment.
- ##if ($type_plus eq '#') {
- ## $K_plus = $self->K_next_code($K_plus);
- ##}
+ # Otherwise revert to defaults
+ elsif ( $default_adjust_indentation == 0 ) {
+ $indentation = $leading_spaces_beg;
}
+ elsif ( $default_adjust_indentation == 1 ) {
+ $indentation = $reduced_spaces_to_go[$i_terminal];
+ $lev = $levels_to_go[$i_terminal];
+ }
+ }
+ }
- if ( !$is_bli_beg && defined($K_plus) ) {
- my $lev = $level_beg;
- my $level_next = $rLL->[$K_plus]->[_LEVEL_];
+ #-------------------------------------------------------------
+ # Secton 2D: adjust_indentation == 3
+ # Full indentation of closing tokens (-icb and -icp or -cti=2)
+ #-------------------------------------------------------------
+ else {
- # and do not undo ci if it was set by the -xci option
- $adjust_indentation = 1
- if ( $level_next < $lev
- && !$self->[_rseqno_controlling_my_ci_]->{$K_beg} );
- }
+ # handle -icb (indented closing code block braces)
+ # Updated method for indented block braces: indent one full level if
+ # there is no continuation indentation. This will occur for major
+ # structures such as sub, if, else, but not for things like map
+ # blocks.
+ #
+ # Note: only code blocks without continuation indentation are
+ # handled here (if, else, unless, ..). In the following snippet,
+ # the terminal brace of the sort block will have continuation
+ # indentation as shown so it will not be handled by the coding
+ # here. We would have to undo the continuation indentation to do
+ # this, but it probably looks ok as is. This is a possible future
+ # update for semicolon terminated lines.
+ #
+ # if ($sortby eq 'date' or $sortby eq 'size') {
+ # @files = sort {
+ # $file_data{$a}{$sortby} <=> $file_data{$b}{$sortby}
+ # or $a cmp $b
+ # } @files;
+ # }
+ #
+ if ( $block_type_beg
+ && $ci_levels_to_go[$i_terminal] == 0 )
+ {
+ my $spaces = get_spaces( $leading_spaces_to_go[$i_terminal] );
+ $indentation = $spaces + $rOpts_indent_columns;
- # Patch for RT #96101, in which closing brace of anonymous subs
- # was not outdented. We should look ahead and see if there is
- # a level decrease at the next token (i.e., a closing token),
- # but right now we do not have that information. For now
- # we see if we are in a list, and this works well.
- # See test files 'sub*.t' for good test cases.
- if ( $terminal_is_in_list
- && !$rOpts_indent_closing_brace
- && $block_type_beg
- && $block_type_beg =~ /$ASUB_PATTERN/ )
+ # NOTE: for -lp we could create a new indentation object, but
+ # there is probably no need to do it
+ }
+
+ # handle -icp and any -icb block braces which fall through above
+ # test such as the 'sort' block mentioned above.
+ else {
+
+ # There are currently two ways to handle -icp...
+ # One way is to use the indentation of the previous line:
+ # $indentation = $last_indentation_written;
+
+ # The other way is to use the indentation that the previous line
+ # would have had if it hadn't been adjusted:
+ $indentation = $last_unadjusted_indentation;
+
+ # Current method: use the minimum of the two. This avoids
+ # inconsistent indentation.
+ if ( get_spaces($last_indentation_written) <
+ get_spaces($indentation) )
{
- (
- $opening_indentation, $opening_offset,
- $is_leading, $opening_exists
- )
- = $self->get_opening_indentation( $ibeg, $ri_first,
- $ri_last, $rindentation_list );
- my $indentation = $leading_spaces_beg;
- if ( defined($opening_indentation)
- && get_spaces($indentation) >
- get_spaces($opening_indentation) )
- {
- $adjust_indentation = 1;
- }
+ $indentation = $last_indentation_written;
}
}
- # YVES patch 1 of 2:
- # Undo ci of line with leading closing eval brace,
- # but not beyond the indentation of the line with
- # the opening brace.
- if ( $block_type_beg eq 'eval'
- && !ref($leading_spaces_beg)
- && !$rOpts_indent_closing_brace )
+ # use previous indentation but use own level
+ # to cause list to be flushed properly
+ $lev = $level_beg;
+ }
+
+ #-------------------------------------------------------------
+ # Remember indentation except for multi-line quotes, which get
+ # no indentation
+ #-------------------------------------------------------------
+ if ( !( $ibeg == 0 && $starting_in_quote ) ) {
+ $last_indentation_written = $indentation;
+ $last_unadjusted_indentation = $leading_spaces_beg;
+ $last_leading_token = $token_beg;
+
+ # Patch to make a line which is the end of a qw quote work with the
+ # -lp option. Make $token_beg look like a closing token as some
+ # type even if it is not. This variable will become
+ # $last_leading_token at the end of this loop. Then, if the -lp
+ # style is selected, and the next line is also a
+ # closing token, it will not get more indentation than this line.
+ # We need to do this because qw quotes (at present) only get
+ # continuation indentation, not one level of indentation, so we
+ # need to turn off the -lp indentation.
+
+ # ... a picture is worth a thousand words:
+
+ # perltidy -wn -gnu (Without this patch):
+ # ok(defined(
+ # $seqio = $gb->get_Stream_by_batch([qw(J00522 AF303112
+ # 2981014)])
+ # ));
+
+ # perltidy -wn -gnu (With this patch):
+ # ok(defined(
+ # $seqio = $gb->get_Stream_by_batch([qw(J00522 AF303112
+ # 2981014)])
+ # ));
+ if ( $seqno_qw_closing
+ && ( length($token_beg) > 1 || $token_beg eq '>' ) )
{
- (
- $opening_indentation, $opening_offset,
- $is_leading, $opening_exists
- )
- = $self->get_opening_indentation( $ibeg, $ri_first, $ri_last,
- $rindentation_list );
- my $indentation = $leading_spaces_beg;
- if ( defined($opening_indentation)
- && get_spaces($indentation) >
- get_spaces($opening_indentation) )
- {
- $adjust_indentation = 1;
- }
+ $last_leading_token = ')';
}
+ }
- # patch for issue git #40: -bli setting has priority
- $adjust_indentation = 0 if ($is_bli_beg);
+ #---------------------------------------------------------------------
+ # Rule: lines with leading closing tokens should not be outdented more
+ # than the line which contained the corresponding opening token.
+ #---------------------------------------------------------------------
- $default_adjust_indentation = $adjust_indentation;
+ # Updated per bug report in alex_bug.pl: we must not
+ # mess with the indentation of closing logical braces, so
+ # we must treat something like '} else {' as if it were
+ # an isolated brace
+ my $is_isolated_block_brace = $block_type_beg
+ && ( $i_terminal == $ibeg
+ || $is_if_elsif_else_unless_while_until_for_foreach{$block_type_beg}
+ );
- # Now modify default behavior according to user request:
- # handle option to indent non-blocks of the form ); }; ];
- # But don't do special indentation to something like ')->pack('
- if ( !$block_type_beg ) {
+ # only do this for a ':; which is aligned with its leading '?'
+ my $is_unaligned_colon = $type_beg eq ':' && !$is_leading;
- # Note that logical padding has already been applied, so we may
- # need to remove some spaces to get a valid hash key.
- my $tok = $token_beg;
- my $cti = $closing_token_indentation{$tok};
+ if (
+ defined($opening_indentation)
+ && !$leading_paren_arrow # MOJO patch
+ && !$is_isolated_block_brace
+ && !$is_unaligned_colon
+ )
+ {
+ if ( get_spaces($opening_indentation) > get_spaces($indentation) ) {
+ $indentation = $opening_indentation;
+ }
+ }
- # Fix the value of 'cti' for an isolated non-welded closing qw
- # delimiter.
- if ( $seqno_qw_closing && $ibeg_weld_fix == $ibeg ) {
+ #----------------------------------------------------
+ # remember the indentation of each line of this batch
+ #----------------------------------------------------
+ push @{$rindentation_list}, $indentation;
- # A quote delimiter which is not a container will not have
- # a cti value defined. In this case use the style of a
- # paren. For example
- # my @fars = (
- # qw<
- # far
- # farfar
- # farfars-far
- # >,
- # );
- if ( !defined($cti) && length($tok) == 1 ) {
+ #---------------------------------------------
+ # outdent lines with certain leading tokens...
+ #---------------------------------------------
+ if (
- # something other than ')', '}', ']' ; use flag for ')'
- $cti = $closing_token_indentation{')'};
+ # must be first word of this batch
+ $ibeg == 0
- # But for now, do not outdent non-container qw
- # delimiters because it would would change existing
- # formatting.
- if ( $tok ne '>' ) { $cti = 3 }
- }
+ # and ...
+ && (
- # A non-welded closing qw cannot currently use -cti=1
- # because that option requires a sequence number to find
- # the opening indentation, and qw quote delimiters are not
- # sequenced items.
- if ( defined($cti) && $cti == 1 ) { $cti = 0 }
- }
+ # certain leading keywords if requested
+ $rOpts_outdent_keywords
+ && $type_beg eq 'k'
+ && $outdent_keyword{$token_beg}
- if ( !defined($cti) ) {
+ # or labels if requested
+ || $rOpts_outdent_labels && $type_beg eq 'J'
- # $cti may not be defined for several reasons.
- # -padding may have been applied so the character
- # has a length > 1
- # - we may have welded to a closing quote token.
- # Here is an example (perltidy -wn):
- # __PACKAGE__->load_components( qw(
- # > Core
- # >
- # > ) );
- $adjust_indentation = 0;
+ # or static block comments if requested
+ || $is_static_block_comment
+ && $rOpts_outdent_static_block_comments
+ )
+ )
+ {
+ my $space_count = leading_spaces_to_go($ibeg);
+ if ( $space_count > 0 ) {
+ $space_count -= $rOpts_continuation_indentation;
+ $is_outdented_line = 1;
+ if ( $space_count < 0 ) { $space_count = 0 }
+ # do not promote a spaced static block comment to non-spaced;
+ # this is not normally necessary but could be for some
+ # unusual user inputs (such as -ci = -i)
+ if ( $type_beg eq '#' && $space_count == 0 ) {
+ $space_count = 1;
}
- elsif ( $cti == 1 ) {
- if ( $i_terminal <= $ibeg + 1
- || $is_semicolon_terminated )
- {
- $adjust_indentation = 2;
- }
- else {
- $adjust_indentation = 0;
- }
- }
- elsif ( $cti == 2 ) {
- if ($is_semicolon_terminated) {
- $adjust_indentation = 3;
- }
- else {
- $adjust_indentation = 0;
- }
- }
- elsif ( $cti == 3 ) {
- $adjust_indentation = 3;
- }
+
+ $indentation = $space_count;
}
+ }
- # handle option to indent blocks
- else {
- if (
- $rOpts_indent_closing_brace
- && (
- $i_terminal == $ibeg # isolated terminal '}'
- || $is_semicolon_terminated
- )
- ) # } xxxx ;
- {
- $adjust_indentation = 3;
+ return ( $indentation, $lev, $level_end, $i_terminal,
+ $is_outdented_line );
+ } ## end sub get_final_indentation
+
+ sub get_closing_token_indentation {
+
+ # Determine indentation adjustment for a line with a leading closing
+ # token - i.e. one of these: ) ] } :
+
+ my (
+ $self,
+
+ $ibeg,
+ $iend,
+ $ri_first,
+ $ri_last,
+ $rindentation_list,
+ $level_jump,
+ $i_terminal,
+ $is_semicolon_terminated,
+ $seqno_qw_closing,
+
+ ) = @_;
+
+ my $adjust_indentation = 0;
+ my $default_adjust_indentation = $adjust_indentation;
+ my $terminal_type = $types_to_go[$i_terminal];
+
+ my $type_beg = $types_to_go[$ibeg];
+ my $token_beg = $tokens_to_go[$ibeg];
+ my $level_beg = $levels_to_go[$ibeg];
+ my $block_type_beg = $block_type_to_go[$ibeg];
+ my $leading_spaces_beg = $leading_spaces_to_go[$ibeg];
+ my $seqno_beg = $type_sequence_to_go[$ibeg];
+ my $is_closing_type_beg = $is_closing_type{$type_beg};
+
+ my (
+ $opening_indentation, $opening_offset,
+ $is_leading, $opening_exists
+ );
+
+ # Honor any flag to reduce -ci set by the -bbxi=n option
+ if ( $seqno_beg && $self->[_rwant_reduced_ci_]->{$seqno_beg} ) {
+
+ # if this is an opening, it must be alone on the line ...
+ if ( $is_closing_type{$type_beg} || $ibeg == $i_terminal ) {
+ $adjust_indentation = 1;
+ }
+
+ # ... or a single welded unit (fix for b1173)
+ elsif ($total_weld_count) {
+ my $K_beg = $K_to_go[$ibeg];
+ my $Kterm = $K_to_go[$i_terminal];
+ my $Kterm_test = $self->[_rK_weld_left_]->{$Kterm};
+ if ( defined($Kterm_test) && $Kterm_test >= $K_beg ) {
+ $Kterm = $Kterm_test;
}
+ if ( $Kterm == $K_beg ) { $adjust_indentation = 1 }
}
- } ## end if ( $is_closing_type_beg || $seqno_qw_closing )
+ }
- # if at ');', '};', '>;', and '];' of a terminal qw quote
- elsif (
- substr( $rpatterns->[0], 0, 2 ) eq 'qb'
- && substr( $rfields->[0], -1, 1 ) eq ';'
- ##&& $rpatterns->[0] =~ /^qb*;$/
- && $rfields->[0] =~ /^([\)\}\]\>]);$/
- )
- {
- if ( $closing_token_indentation{$1} == 0 ) {
- $adjust_indentation = 1;
+ my $ris_bli_container = $self->[_ris_bli_container_];
+ my $is_bli_beg = $seqno_beg ? $ris_bli_container->{$seqno_beg} : 0;
+
+ # Update the $is_bli flag as we go. It is initially 1.
+ # We note seeing a leading opening brace by setting it to 2.
+ # If we get to the closing brace without seeing the opening then we
+ # turn it off. This occurs if the opening brace did not get output
+ # at the start of a line, so we will then indent the closing brace
+ # in the default way.
+ if ( $is_bli_beg && $is_bli_beg == 1 ) {
+ my $K_opening_container = $self->[_K_opening_container_];
+ my $K_opening = $K_opening_container->{$seqno_beg};
+ my $K_beg = $K_to_go[$ibeg];
+ if ( $K_beg eq $K_opening ) {
+ $ris_bli_container->{$seqno_beg} = $is_bli_beg = 2;
}
- else {
- $adjust_indentation = 3;
+ else { $is_bli_beg = 0 }
+ }
+
+ # QW PATCH for the combination -lp -wn
+ # For -lp formatting use $ibeg_weld_fix to get around the problem
+ # that with -lp type formatting the opening and closing tokens to not
+ # have sequence numbers.
+ my $ibeg_weld_fix = $ibeg;
+ if ( $seqno_qw_closing && $total_weld_count ) {
+ my $i_plus = $inext_to_go[$ibeg];
+ if ( $i_plus <= $max_index_to_go ) {
+ my $K_plus = $K_to_go[$i_plus];
+ if ( defined( $self->[_rK_weld_left_]->{$K_plus} ) ) {
+ $ibeg_weld_fix = $i_plus;
+ }
}
}
- # if line begins with a ':', align it with any
- # previous line leading with corresponding ?
- elsif ( $type_beg eq ':' ) {
+ # if we are at a closing token of some type..
+ if ( $is_closing_type_beg || $seqno_qw_closing ) {
+
+ my $K_beg = $K_to_go[$ibeg];
+
+ # get the indentation of the line containing the corresponding
+ # opening token
(
$opening_indentation, $opening_offset,
$is_leading, $opening_exists
)
- = $self->get_opening_indentation( $ibeg, $ri_first, $ri_last,
- $rindentation_list );
- if ($is_leading) { $adjust_indentation = 2; }
- }
+ = $self->get_opening_indentation( $ibeg_weld_fix, $ri_first,
+ $ri_last, $rindentation_list, $seqno_qw_closing );
- #---------------------------------------------------------
- # Section 2: set indentation according to flag set above
- #
- # Select the indentation object to define leading
- # whitespace. If we are outdenting something like '} } );'
- # then we want to use one level below the last token
- # ($i_terminal) in order to get it to fully outdent through
- # all levels.
- #---------------------------------------------------------
- my $indentation;
- my $lev;
- my $level_end = $levels_to_go[$iend];
+ my $terminal_is_in_list = $self->is_in_list_by_i($i_terminal);
- if ( $adjust_indentation == 0 ) {
- $indentation = $leading_spaces_beg;
- $lev = $level_beg;
- }
- elsif ( $adjust_indentation == 1 ) {
+ # First set the default behavior:
+ if (
- # Change the indentation to be that of a different token on the line
- # Previously, the indentation of the terminal token was used:
- # OLD CODING:
- # $indentation = $reduced_spaces_to_go[$i_terminal];
- # $lev = $levels_to_go[$i_terminal];
+ # default behavior is to outdent closing lines
+ # of the form: "); }; ]; )->xxx;"
+ $is_semicolon_terminated
- # Generalization for MOJO patch:
- # Use the lowest level indentation of the tokens on the line.
- # For example, here we can use the indentation of the ending ';':
- # } until ($selection > 0 and $selection < 10); # ok to use ';'
- # But this will not outdent if we use the terminal indentation:
- # )->then( sub { # use indentation of the ->, not the {
- # Warning: reduced_spaces_to_go[] may be a reference, do not
- # do numerical checks with it
+ # and 'cuddled parens' of the form: ")->pack("
+ # Bug fix for RT #123749]: the types here were
+ # incorrectly '(' and ')'. Corrected to be '{' and '}'
+ || (
+ $terminal_type eq '{'
+ && $type_beg eq '}'
+ && ( $nesting_depth_to_go[$iend] + 1 ==
+ $nesting_depth_to_go[$ibeg] )
+ )
- my $i_ind = $ibeg;
- $indentation = $reduced_spaces_to_go[$i_ind];
- $lev = $levels_to_go[$i_ind];
- while ( $i_ind < $i_terminal ) {
- $i_ind++;
- if ( $levels_to_go[$i_ind] < $lev ) {
- $indentation = $reduced_spaces_to_go[$i_ind];
- $lev = $levels_to_go[$i_ind];
- }
- }
- }
+ # remove continuation indentation for any line like
+ # } ... {
+ # or without ending '{' and unbalanced, such as
+ # such as '}->{$operator}'
+ || (
+ $type_beg eq '}'
- # handle indented closing token which aligns with opening token
- elsif ( $adjust_indentation == 2 ) {
+ && ( $types_to_go[$iend] eq '{'
+ || $levels_to_go[$iend] < $level_beg )
+ )
- # handle option to align closing token with opening token
- $lev = $level_beg;
+ # and when the next line is at a lower indentation level...
- # calculate spaces needed to align with opening token
- my $space_count =
- get_spaces($opening_indentation) + $opening_offset;
+ # PATCH #1: and only if the style allows undoing continuation
+ # for all closing token types. We should really wait until
+ # the indentation of the next line is known and then make
+ # a decision, but that would require another pass.
- # Indent less than the previous line.
- #
- # Problem: For -lp we don't exactly know what it was if there
- # were recoverable spaces sent to the aligner. A good solution
- # would be to force a flush of the vertical alignment buffer, so
- # that we would know. For now, this rule is used for -lp:
- #
- # When the last line did not start with a closing token we will
- # be optimistic that the aligner will recover everything wanted.
- #
- # This rule will prevent us from breaking a hierarchy of closing
- # tokens, and in a worst case will leave a closing paren too far
- # indented, but this is better than frequently leaving it not
- # indented enough.
- my $last_spaces = get_spaces($last_indentation_written);
+ # PATCH #2: and not if this token is under -xci control
+ || ( $level_jump < 0
+ && !$some_closing_token_indentation
+ && !$self->[_rseqno_controlling_my_ci_]->{$K_beg} )
- if ( ref($last_indentation_written)
- && !$is_closing_token{$last_leading_token} )
- {
- $last_spaces +=
- get_recoverable_spaces($last_indentation_written);
- }
+ # Patch for -wn=2, multiple welded closing tokens
+ || ( $i_terminal > $ibeg
+ && $is_closing_type{ $types_to_go[$iend] } )
- # reset the indentation to the new space count if it works
- # only options are all or none: nothing in-between looks good
- $lev = $level_beg;
+ # Alternate Patch for git #51, isolated closing qw token not
+ # outdented if no-delete-old-newlines is set. This works, but
+ # a more general patch elsewhere fixes the real problem: ljump.
+ # || ( $seqno_qw_closing && $ibeg == $i_terminal )
- my $diff = $last_spaces - $space_count;
- if ( $diff > 0 ) {
- $indentation = $space_count;
+ )
+ {
+ $adjust_indentation = 1;
}
- else {
- # We need to fix things ... but there is no good way to do it.
- # The best solution is for the user to use a longer maximum
- # line length. We could get a smooth variation if we just move
- # the paren in using
- # $space_count -= ( 1 - $diff );
- # But unfortunately this can give a rather unbalanced look.
+ # outdent something like '),'
+ if (
+ $terminal_type eq ','
- # For -xlp we currently allow a tolerance of one indentation
- # level and then revert to a simpler default. This will jump
- # suddenly but keeps a balanced look.
- if ( $rOpts_extended_line_up_parentheses
- && $diff >= -$rOpts_indent_columns
- && $space_count > $leading_spaces_beg )
- {
- $indentation = $space_count;
- }
+ # Removed this constraint for -wn
+ # OLD: allow just one character before the comma
+ # && $i_terminal == $ibeg + 1
- # Otherwise revert to defaults
- elsif ( $default_adjust_indentation == 0 ) {
- $indentation = $leading_spaces_beg;
- }
- elsif ( $default_adjust_indentation == 1 ) {
- $indentation = $reduced_spaces_to_go[$i_terminal];
- $lev = $levels_to_go[$i_terminal];
- }
+ # require LIST environment; otherwise, we may outdent too much -
+ # this can happen in calls without parentheses (overload.t);
+ && $terminal_is_in_list
+ )
+ {
+ $adjust_indentation = 1;
}
- }
-
- # Full indentation of closing tokens (-icb and -icp or -cti=2)
- else {
- # handle -icb (indented closing code block braces)
- # Updated method for indented block braces: indent one full level if
- # there is no continuation indentation. This will occur for major
- # structures such as sub, if, else, but not for things like map
- # blocks.
- #
- # Note: only code blocks without continuation indentation are
- # handled here (if, else, unless, ..). In the following snippet,
- # the terminal brace of the sort block will have continuation
- # indentation as shown so it will not be handled by the coding
- # here. We would have to undo the continuation indentation to do
- # this, but it probably looks ok as is. This is a possible future
- # update for semicolon terminated lines.
- #
- # if ($sortby eq 'date' or $sortby eq 'size') {
- # @files = sort {
- # $file_data{$a}{$sortby} <=> $file_data{$b}{$sortby}
- # or $a cmp $b
- # } @files;
- # }
- #
- if ( $block_type_beg
- && $ci_levels_to_go[$i_terminal] == 0 )
+ # undo continuation indentation of a terminal closing token if
+ # it is the last token before a level decrease. This will allow
+ # a closing token to line up with its opening counterpart, and
+ # avoids an indentation jump larger than 1 level.
+ my $rLL = $self->[_rLL_];
+ my $Klimit = $self->[_Klimit_];
+ if ( $i_terminal == $ibeg
+ && $is_closing_type_beg
+ && defined($K_beg)
+ && $K_beg < $Klimit )
{
- my $spaces = get_spaces( $leading_spaces_to_go[$i_terminal] );
- $indentation = $spaces + $rOpts_indent_columns;
+ my $K_plus = $K_beg + 1;
+ my $type_plus = $rLL->[$K_plus]->[_TYPE_];
- # NOTE: for -lp we could create a new indentation object, but
- # there is probably no need to do it
- }
+ if ( $type_plus eq 'b' && $K_plus < $Klimit ) {
+ $type_plus = $rLL->[ ++$K_plus ]->[_TYPE_];
+ }
- # handle -icp and any -icb block braces which fall through above
- # test such as the 'sort' block mentioned above.
- else {
+ if ( $type_plus eq '#' && $K_plus < $Klimit ) {
+ $type_plus = $rLL->[ ++$K_plus ]->[_TYPE_];
+ if ( $type_plus eq 'b' && $K_plus < $Klimit ) {
+ $type_plus = $rLL->[ ++$K_plus ]->[_TYPE_];
+ }
+
+ # Note: we have skipped past just one comment (perhaps a
+ # side comment). There could be more, and we could easily
+ # skip past all the rest with the following code, or with a
+ # while loop. It would be rare to have to do this, and
+ # those block comments would still be indented, so it would
+ # to leave them indented. So it seems best to just stop at
+ # a maximum of one comment.
+ ##if ($type_plus eq '#') {
+ ## $K_plus = $self->K_next_code($K_plus);
+ ##}
+ }
- # There are currently two ways to handle -icp...
- # One way is to use the indentation of the previous line:
- # $indentation = $last_indentation_written;
+ if ( !$is_bli_beg && defined($K_plus) ) {
+ my $lev = $level_beg;
+ my $level_next = $rLL->[$K_plus]->[_LEVEL_];
- # The other way is to use the indentation that the previous line
- # would have had if it hadn't been adjusted:
- $indentation = $last_unadjusted_indentation;
+ # and do not undo ci if it was set by the -xci option
+ $adjust_indentation = 1
+ if ( $level_next < $lev
+ && !$self->[_rseqno_controlling_my_ci_]->{$K_beg} );
+ }
- # Current method: use the minimum of the two. This avoids
- # inconsistent indentation.
- if ( get_spaces($last_indentation_written) <
- get_spaces($indentation) )
+ # Patch for RT #96101, in which closing brace of anonymous subs
+ # was not outdented. We should look ahead and see if there is
+ # a level decrease at the next token (i.e., a closing token),
+ # but right now we do not have that information. For now
+ # we see if we are in a list, and this works well.
+ # See test files 'sub*.t' for good test cases.
+ if ( $terminal_is_in_list
+ && !$rOpts_indent_closing_brace
+ && $block_type_beg
+ && $block_type_beg =~ /$ASUB_PATTERN/ )
{
- $indentation = $last_indentation_written;
+ (
+ $opening_indentation, $opening_offset,
+ $is_leading, $opening_exists
+ )
+ = $self->get_opening_indentation( $ibeg, $ri_first,
+ $ri_last, $rindentation_list );
+ my $indentation = $leading_spaces_beg;
+ if ( defined($opening_indentation)
+ && get_spaces($indentation) >
+ get_spaces($opening_indentation) )
+ {
+ $adjust_indentation = 1;
+ }
}
}
- # use previous indentation but use own level
- # to cause list to be flushed properly
- $lev = $level_beg;
- }
-
- # remember indentation except for multi-line quotes, which get
- # no indentation
- unless ( $ibeg == 0 && $starting_in_quote ) {
- $last_indentation_written = $indentation;
- $last_unadjusted_indentation = $leading_spaces_beg;
- $last_leading_token = $token_beg;
-
- # Patch to make a line which is the end of a qw quote work with the
- # -lp option. Make $token_beg look like a closing token as some
- # type even if it is not. This variable will become
- # $last_leading_token at the end of this loop. Then, if the -lp
- # style is selected, and the next line is also a
- # closing token, it will not get more indentation than this line.
- # We need to do this because qw quotes (at present) only get
- # continuation indentation, not one level of indentation, so we
- # need to turn off the -lp indentation.
-
- # ... a picture is worth a thousand words:
-
- # perltidy -wn -gnu (Without this patch):
- # ok(defined(
- # $seqio = $gb->get_Stream_by_batch([qw(J00522 AF303112
- # 2981014)])
- # ));
-
- # perltidy -wn -gnu (With this patch):
- # ok(defined(
- # $seqio = $gb->get_Stream_by_batch([qw(J00522 AF303112
- # 2981014)])
- # ));
- if ( $seqno_qw_closing
- && ( length($token_beg) > 1 || $token_beg eq '>' ) )
+ # YVES patch 1 of 2:
+ # Undo ci of line with leading closing eval brace,
+ # but not beyond the indentation of the line with
+ # the opening brace.
+ if ( $block_type_beg eq 'eval'
+ && !ref($leading_spaces_beg)
+ && !$rOpts_indent_closing_brace )
{
- $last_leading_token = ')';
+ (
+ $opening_indentation, $opening_offset,
+ $is_leading, $opening_exists
+ )
+ = $self->get_opening_indentation( $ibeg, $ri_first, $ri_last,
+ $rindentation_list );
+ my $indentation = $leading_spaces_beg;
+ if ( defined($opening_indentation)
+ && get_spaces($indentation) >
+ get_spaces($opening_indentation) )
+ {
+ $adjust_indentation = 1;
+ }
}
- }
- # be sure lines with leading closing tokens are not outdented more
- # than the line which contained the corresponding opening token.
+ # patch for issue git #40: -bli setting has priority
+ $adjust_indentation = 0 if ($is_bli_beg);
- #--------------------------------------------------------
- # updated per bug report in alex_bug.pl: we must not
- # mess with the indentation of closing logical braces so
- # we must treat something like '} else {' as if it were
- # an isolated brace
- #--------------------------------------------------------
- my $is_isolated_block_brace = $block_type_beg
- && ( $i_terminal == $ibeg
- || $is_if_elsif_else_unless_while_until_for_foreach{$block_type_beg}
- );
+ $default_adjust_indentation = $adjust_indentation;
- # only do this for a ':; which is aligned with its leading '?'
- my $is_unaligned_colon = $type_beg eq ':' && !$is_leading;
+ # Now modify default behavior according to user request:
+ # handle option to indent non-blocks of the form ); }; ];
+ # But don't do special indentation to something like ')->pack('
+ if ( !$block_type_beg ) {
- if (
- defined($opening_indentation)
- && !$leading_paren_arrow # MOJO patch
- && !$is_isolated_block_brace
- && !$is_unaligned_colon
- )
- {
- if ( get_spaces($opening_indentation) > get_spaces($indentation) ) {
- $indentation = $opening_indentation;
- }
- }
+ # Note that logical padding has already been applied, so we may
+ # need to remove some spaces to get a valid hash key.
+ my $tok = $token_beg;
+ my $cti = $closing_token_indentation{$tok};
- # remember the indentation of each line of this batch
- push @{$rindentation_list}, $indentation;
+ # Fix the value of 'cti' for an isolated non-welded closing qw
+ # delimiter.
+ if ( $seqno_qw_closing && $ibeg_weld_fix == $ibeg ) {
- # outdent lines with certain leading tokens...
- if (
+ # A quote delimiter which is not a container will not have
+ # a cti value defined. In this case use the style of a
+ # paren. For example
+ # my @fars = (
+ # qw<
+ # far
+ # farfar
+ # farfars-far
+ # >,
+ # );
+ if ( !defined($cti) && length($tok) == 1 ) {
- # must be first word of this batch
- $ibeg == 0
+ # something other than ')', '}', ']' ; use flag for ')'
+ $cti = $closing_token_indentation{')'};
- # and ...
- && (
+ # But for now, do not outdent non-container qw
+ # delimiters because it would would change existing
+ # formatting.
+ if ( $tok ne '>' ) { $cti = 3 }
+ }
- # certain leading keywords if requested
- $rOpts_outdent_keywords
- && $type_beg eq 'k'
- && $outdent_keyword{$token_beg}
+ # A non-welded closing qw cannot currently use -cti=1
+ # because that option requires a sequence number to find
+ # the opening indentation, and qw quote delimiters are not
+ # sequenced items.
+ if ( defined($cti) && $cti == 1 ) { $cti = 0 }
+ }
- # or labels if requested
- || $rOpts_outdent_labels && $type_beg eq 'J'
+ if ( !defined($cti) ) {
- # or static block comments if requested
- || $is_static_block_comment
- && $rOpts_outdent_static_block_comments
- )
- )
- {
- my $space_count = leading_spaces_to_go($ibeg);
- if ( $space_count > 0 ) {
- $space_count -= $rOpts_continuation_indentation;
- $is_outdented_line = 1;
- if ( $space_count < 0 ) { $space_count = 0 }
+ # $cti may not be defined for several reasons.
+ # -padding may have been applied so the character
+ # has a length > 1
+ # - we may have welded to a closing quote token.
+ # Here is an example (perltidy -wn):
+ # __PACKAGE__->load_components( qw(
+ # > Core
+ # >
+ # > ) );
+ $adjust_indentation = 0;
- # do not promote a spaced static block comment to non-spaced;
- # this is not normally necessary but could be for some
- # unusual user inputs (such as -ci = -i)
- if ( $type_beg eq '#' && $space_count == 0 ) {
- $space_count = 1;
}
+ elsif ( $cti == 1 ) {
+ if ( $i_terminal <= $ibeg + 1
+ || $is_semicolon_terminated )
+ {
+ $adjust_indentation = 2;
+ }
+ else {
+ $adjust_indentation = 0;
+ }
+ }
+ elsif ( $cti == 2 ) {
+ if ($is_semicolon_terminated) {
+ $adjust_indentation = 3;
+ }
+ else {
+ $adjust_indentation = 0;
+ }
+ }
+ elsif ( $cti == 3 ) {
+ $adjust_indentation = 3;
+ }
+ }
- $indentation = $space_count;
+ # handle option to indent blocks
+ else {
+ if (
+ $rOpts_indent_closing_brace
+ && (
+ $i_terminal == $ibeg # isolated terminal '}'
+ || $is_semicolon_terminated
+ )
+ ) # } xxxx ;
+ {
+ $adjust_indentation = 3;
+ }
}
+ } ## end if ( $is_closing_type_beg || $seqno_qw_closing )
+
+ # if line begins with a ':', align it with any
+ # previous line leading with corresponding ?
+ elsif ( $type_beg eq ':' ) {
+ (
+ $opening_indentation, $opening_offset,
+ $is_leading, $opening_exists
+ )
+ = $self->get_opening_indentation( $ibeg, $ri_first, $ri_last,
+ $rindentation_list );
+ if ($is_leading) { $adjust_indentation = 2; }
}
- return ( $indentation, $lev, $level_end, $i_terminal,
- $is_outdented_line );
- } ## end sub get_final_indentation
+ return ( $adjust_indentation, $default_adjust_indentation,
+ $opening_indentation, $opening_offset,
+ $is_leading, $opening_exists );
+ }
+
} ## end closure get_final_indentation
sub get_opening_indentation {