]> git.donarmstrong.com Git - perltidy.git/commitdiff
add flag -xci to help git #28
authorSteve Hancock <perltidy@users.sourceforge.net>
Thu, 8 Oct 2020 15:41:31 +0000 (08:41 -0700)
committerSteve Hancock <perltidy@users.sourceforge.net>
Thu, 8 Oct 2020 15:41:31 +0000 (08:41 -0700)
CHANGES.md
bin/perltidy
lib/Perl/Tidy.pm
lib/Perl/Tidy/Formatter.pm

index 225c30e12683670b2e092e9ea670f5b46ba56d40..41c98d9408a7d75b51fe412b6b35a6f51d2b1754 100644 (file)
@@ -1,5 +1,7 @@
 # Perltidy Change Log
 
+    - Add flag -xci, --extended-continuation-indentation, regarding issue git #28
+
     - Fix issue git #41, typo in manual regarding -fsb
 
     - Fix issue git #40: when using the -bli option, a closing brace followed by 
index aaa8d7946ddbe1460452d2ada91605961119fda1..0334518449ccf81e2c3d89d49bc5b09545e4a1cd 100755 (executable)
@@ -722,11 +722,66 @@ The value given to B<-ci> is also used by some commands when a small
 space is required.  Examples are commands for outdenting labels,
 B<-ola>, and control keywords, B<-okw>.  
 
-When default values are not used, it is highly recommended that the value B<n>
-given with B<-ci=n> be no more than about one-half of the number of spaces
-assigned to a full indentation level on the B<-i=n> command.  The reason is
-that discontinuities in the definition and control of continuation indentation
-arise in complex code, and this rule helps to smooth out these discontinuities.
+When default values are not used, it is recommended that either 
+
+(1) the value B<n> given with B<-ci=n> be no more than about one-half of the
+number of spaces assigned to a full indentation level on the B<-i=n> command,
+
+or
+
+(2) the flag B<-extended-continuation-indentation> is used (see next section).
+
+=item B<-xci>, B<--extended-continuation-indentation>
+
+This flag causes continuation indentation to "extend" deeper into containers.
+It is a fairly recent addition and is set off by default to avoid disturbing
+existing formatting.  If you use a continuation indentation equal to the
+indentation, you will probably want to set this flag.  
+
+Here is an explanation. There are two common strategies for continuation
+indentation.  One is the strategy recommend in the original perl style
+guidelines, in which B<-ci=2> and B<-i=4>.  The other is the strategy is the
+strategy recommended in the Perl Best Practices (B<pbp>) by Conway, in which
+B<-ci=4> and B<-i=4>.  The default formatting in perltidy works fairly well
+with the orignal perl style, but it runs into problems with the B<pbp> style. 
+The B<-xci> flag was added to fix this.
+
+To illustrate,
+
+        # perltidy default (-ci=2 -i=4)
+        ( /^GL$/ and $dv = "PDL::Graphics::TriD::GL" )
+          or (  /^GLpic$/
+            and $dv = "PDL::Graphics::TriD::GL"
+            and $PDL::Graphics::TriD::offline = 1 )
+          or (  /^VRML$/
+            and $dv = "PDL::Graphics::TriD::VRML"
+            and $PDL::Graphics::TriD::offline = 1 )
+          or ( die "Invalid PDL 3D device '$_' specified!" );
+
+        # perltidy -pbp
+        ( /^GL$/ and $dv = "PDL::Graphics::TriD::GL" )
+            or (/^GLpic$/
+            and $dv = "PDL::Graphics::TriD::GL"
+            and $PDL::Graphics::TriD::offline = 1 )
+            or (/^VRML$/
+            and $dv = "PDL::Graphics::TriD::VRML"
+            and $PDL::Graphics::TriD::offline = 1 )
+            or ( die "Invalid PDL 3D device '$_' specified!" );
+
+        # perltidy -pbp -xci
+        ( /^GL$/ and $dv = "PDL::Graphics::TriD::GL" )
+            or (    /^GLpic$/
+                and $dv = "PDL::Graphics::TriD::GL"
+                and $PDL::Graphics::TriD::offline = 1 )
+            or (    /^VRML$/
+                and $dv = "PDL::Graphics::TriD::VRML"
+                and $PDL::Graphics::TriD::offline = 1 )
+            or ( die "Invalid PDL 3D device '$_' specified!" );
+
+In this last case the B<-xci> flag has helped show the structure by extending
+the continuation indentation down into the structures.  It may be used in all
+cases, but is particularly useful when B<-ci=n> and B<-i=n> are equal.  Another
+example is given in the discussion of the B<-pbp> flag.
 
 =item B<-sil=n> B<--starting-indentation-level=n>   
 
@@ -3453,9 +3508,9 @@ perltidy act as a filter on one file only.  These can be overridden by placing
 B<-nst> and/or B<-nse> after the -pbp parameter. 
 
 Also note that the value of continuation indentation, -ci=4, is equal to the
-value of the full indentation, -i=4.  In some complex statements perltidy will
-produce nicer results with -ci=2. This can be implemented by including -ci=2
-after the -pbp parameter.  For example, 
+value of the full indentation, -i=4.  It is recommended that the either (1)
+the parameter B<-ci=2> be used or the flag B<-xci> be set.  The following snippet
+illustrates these options.
 
     # perltidy -pbp
     $self->{_text} = (
@@ -3481,6 +3536,17 @@ after the -pbp parameter.  For example,
         : ' elsewhere in this document'
       );
 
+    # perltidy -pbp -xci
+    $self->{_text} = (
+         !$section        ? ''
+        : $type eq 'item' ? "the $section entry"
+        :                   "the section on $section"
+        )
+        . ( $page
+            ? ( $section ? ' in ' : '' ) . "the $page$page_ext manpage"
+            : ' elsewhere in this document'
+        );
+
 
 =item  One-line blocks 
 
index f5d255322b74ae1a2d361b5d68983ecf4b188687..a77d25c24d67b406833501f29d28c366b10fe6c8 100644 (file)
@@ -121,7 +121,7 @@ sub AUTOLOAD {
     # some diagnostic information.  This sub should never be called
     # except for a programming error.
     our $AUTOLOAD;
-    return if ( $AUTOLOAD eq 'DESTROY' );
+    return if ( $AUTOLOAD =~ /\bDESTROY$/ );
     my ( $pkg, $fname, $lno ) = caller();
     print STDERR <<EOM;
 ======================================================================
@@ -2168,6 +2168,7 @@ sub generate_options {
     $category = 2;    # Code indentation control
     ########################################
     $add_option->( 'continuation-indentation',           'ci',   '=i' );
+    $add_option->( 'extended-continuation-indentation',  'xci',  '!' );
     $add_option->( 'line-up-parentheses',                'lp',   '!' );
     $add_option->( 'outdent-keyword-list',               'okwl', '=s' );
     $add_option->( 'outdent-keywords',                   'okw',  '!' );
@@ -2491,6 +2492,7 @@ sub generate_options {
       closing-brace-indentation=0
       closing-square-bracket-indentation=0
       continuation-indentation=2
+      noextended-continuation-indentation
       cuddled-break-option=1
       delete-old-newlines
       delete-semicolons
index 47a1b5811646db42d296f5c2ab0d1e48f3195d7f..2080b03d4d85d852b7fb83c94c396ac9c851f172 100644 (file)
@@ -363,6 +363,9 @@ BEGIN {
 
         _rspecial_side_comment_type_ => $i++,
 
+        _rseqno_which_extended_ci_ => $i++,
+        _ris_seqno_controlling_ci_ => $i++,
+
     };
 
     # Array index names for _this_batch_ (in above list)
@@ -370,16 +373,17 @@ BEGIN {
     # holding the batches of tokens being processed.
     $i = 0;
     use constant {
-        _starting_in_quote_       => $i++,
-        _ending_in_quote_         => $i++,
-        _is_static_block_comment_ => $i++,
-        _rlines_K_                => $i++,
-        _do_not_pad_              => $i++,
-        _ibeg0_                   => $i++,
-        _peak_batch_size_         => $i++,
-        _max_index_to_go_         => $i++,
-        _rK_to_go_                => $i++,
-        _batch_count_             => $i++,
+        _starting_in_quote_        => $i++,
+        _ending_in_quote_          => $i++,
+        _is_static_block_comment_  => $i++,
+        _rlines_K_                 => $i++,
+        _do_not_pad_               => $i++,
+        _ibeg0_                    => $i++,
+        _peak_batch_size_          => $i++,
+        _max_index_to_go_          => $i++,
+        _rK_to_go_                 => $i++,
+        _batch_count_              => $i++,
+        _rix_seqno_controlling_ci_ => $i++,
     };
 
     # Sequence number assigned to the root of sequence tree.
@@ -552,6 +556,7 @@ sub new {
     initialize_csc_vars();
     initialize_scan_list();
     initialize_saved_opening_indentation();
+    initialize_undo_ci();
     initialize_process_line_of_CODE();
     initialize_grind_batch_of_CODE();
     initialize_adjusted_indentation();
@@ -647,6 +652,9 @@ sub new {
     $self->[_rweld_len_left_opening_]  = {};
     $self->[_rweld_len_right_opening_] = {};
 
+    $self->[_rseqno_which_extended_ci_] = {};
+    $self->[_ris_seqno_controlling_ci_] = {};
+
     $self->[_rspecial_side_comment_type_] = {};
 
     bless $self, $class;
@@ -1433,7 +1441,7 @@ EOM
 
     # Create a table of maximum line length vs level for later efficient use.
     # This avoids continually checking the -vmll flag. We will make the
-    # table very long to be sure it will not be exceeded.  But we have to 
+    # table very long to be sure it will not be exceeded.  But we have to
     # choose a fixed length.  A check will be made at the start of sub
     # 'finish_formatting' to be sure it is not exceeded.  Note, some
     # of my standard test problems have indentation levels of about 150,
@@ -3990,7 +3998,7 @@ sub finish_formatting {
 
     # Check the maximum level. If it is extremely large we will
     # give up and output the file verbatim.
-    my $maximum_level = Perl::Tidy::Tokenizer::get_maximum_level();
+    my $maximum_level       = Perl::Tidy::Tokenizer::get_maximum_level();
     my $maximum_table_index = $#maximum_line_length;
     if ( !$severe_error && $maximum_level > $maximum_table_index ) {
         $severe_error ||= 1;
@@ -5373,10 +5381,10 @@ sub K_next_nonblank {
     my $Knnb = $KK + 1;
     while ( $Knnb < $Num ) {
 
-       # Safety check, this fault shouldn't happen:  The $rLL array is the
-       # main array of tokens, so all entries should be used.  It is
-       # initialized in sub write_line, and then re-initialized by sub
-       # $store_token() within sub respace_tokens.  Tokens are pushed on
+        # Safety check, this fault shouldn't happen:  The $rLL array is the
+        # main array of tokens, so all entries should be used.  It is
+        # initialized in sub write_line, and then re-initialized by sub
+        # $store_token() within sub respace_tokens.  Tokens are pushed on
         # so there shouldn't be any gaps.
         if ( !defined( $rLL->[$Knnb] ) ) {
             Fault("Undefined entry for k=$Knnb");
@@ -5853,19 +5861,24 @@ sub find_nested_pairs {
         next unless defined($K_outer_opening) && defined($K_inner_opening);
         my $K_diff = $K_inner_opening - $K_outer_opening;
 
-        # Count nonblank characters separating them.  
+        # Count nonblank characters separating them.
         if ( $K_diff < 0 ) { next }    # Shouldn't happen
         my $Kn             = $K_outer_opening;
         my $nonblank_count = 0;
         my $type;
         my $is_name;
 
-       # Here is an example of a long identifier chain which counts as a
-       # single nonblank here (this spans about 10 K indexes):
+        # Here is an example of a long identifier chain which counts as a
+        # single nonblank here (this spans about 10 K indexes):
         #     if ( !Boucherot::SetOfConnections->new->handler->execute(
         #        ^--K_o_o                                             ^--K_i_o
         #       @array) )
-        for ( my $Kn = $K_outer_opening + 1 ; $Kn <= $K_inner_opening ; $Kn += 1 ) {
+        for (
+            my $Kn = $K_outer_opening + 1 ;
+            $Kn <= $K_inner_opening ;
+            $Kn += 1
+          )
+        {
             next if ( $rLL->[$Kn]->[_TYPE_] eq 'b' );
             if ( $Kn eq $K_inner_opening ) { $nonblank_count++; last; }
 
@@ -5959,8 +5972,8 @@ sub weld_nested_containers {
 
     my $length_to_opening_seqno = sub {
         my ($seqno) = @_;
-        my $KK = $K_opening_container->{$seqno};
-        my $lentot = defined($KK)
+        my $KK      = $K_opening_container->{$seqno};
+        my $lentot  = defined($KK)
           && $KK > 0 ? $rLL->[ $KK - 1 ]->[_CUMULATIVE_LENGTH_] : 0;
         return $lentot;
     };
@@ -5968,7 +5981,7 @@ sub weld_nested_containers {
     my $length_to_closing_seqno = sub {
         my ($seqno) = @_;
         my $KK      = $K_closing_container->{$seqno};
-        my $lentot = defined($KK)
+        my $lentot  = defined($KK)
           && $KK > 0 ? $rLL->[ $KK - 1 ]->[_CUMULATIVE_LENGTH_] : 0;
         return $lentot;
     };
@@ -6412,7 +6425,7 @@ sub weld_len_right_to_go {
     my ( $self, $i ) = @_;
 
     # Given the index of a token in the 'to_go' array return the length of any
-    # weld to its right. 
+    # weld to its right.
 
     # Back up at a blank.
     return 0 if ( $i < 0 );
@@ -6594,6 +6607,9 @@ sub adjust_indentation_levels {
     # Adjust continuation indentation if -bli is set
     $self->bli_adjustment();
 
+    $self->extended_ci()
+      if ( $rOpts->{'extended-continuation-indentation'} );
+
     # Now clip any adjusted levels to be non-negative
     $self->clip_adjusted_levels();
 
@@ -6828,6 +6844,64 @@ sub adjust_container_indentation {
     return;
 }
 
+sub extended_ci {
+
+    # Add CI to interior tokens of a container which itself has CI but only if
+    # a token does not already have CI.  This will be adjusted later bu sub
+    # undo_ci
+
+    my ($self) = @_;
+
+    my $rLL = $self->[_rLL_];
+    return unless ( defined($rLL) && @{$rLL} );
+
+    my $ris_seqno_controlling_ci = $self->[_ris_seqno_controlling_ci_];
+    my $rseqno_which_extended_ci = $self->[_rseqno_which_extended_ci_];
+
+    # Loop over all opening container tokens
+    my $K_opening_container  = $self->[_K_opening_container_];
+    my $K_closing_container  = $self->[_K_closing_container_];
+    my $ris_broken_container = $self->[_ris_broken_container_];
+
+    my $KNEXT = 0;
+    while ( defined($KNEXT) ) {
+        my $KK = $KNEXT;
+        $KNEXT = $rLL->[$KNEXT]->[_KNEXT_SEQ_ITEM_];
+
+        # This is only for containers with ci
+        next unless ( $rLL->[$KK]->[_CI_LEVEL_] );
+
+        # We are looking for opening containers
+        my $seqno     = $rLL->[$KK]->[_TYPE_SEQUENCE_];
+        my $K_opening = $K_opening_container->{$seqno};
+        next unless ( defined($K_opening) && $KK == $K_opening );
+
+        # Skip containers which themselves have had ci adjusted
+        # by an outer container
+        next if ( $rseqno_which_extended_ci->{$KK} );
+
+        # Make sure there is a closing container
+        # (could be missing if the script has a brace error)
+        my $K_closing = $K_closing_container->{$seqno};
+        next unless defined($K_closing);
+
+        # Add ci to any interior tokens which do not have it and remember which
+        # container made the change.  We will undo it later if this opening
+        # container token goes out without ci.
+        my $count = 0;
+        for ( my $Kt = $K_opening + 1 ; $Kt < $K_closing ; $Kt++ ) {
+            my $ci_t = $rLL->[$Kt]->[_CI_LEVEL_];
+            if ( !$ci_t ) {
+                $rLL->[$Kt]->[_CI_LEVEL_] = 1;
+                $rseqno_which_extended_ci->{$Kt} = $seqno;
+                $count++;
+            }
+        }
+        $ris_seqno_controlling_ci->{$seqno} = $count;
+    }
+    return;
+}
+
 sub bli_adjustment {
 
     # Called once per file to implement the --brace-left-and-indent option.
@@ -9302,10 +9376,11 @@ sub compare_indentation_levels {
         my $this_batch = $self->[_this_batch_];
         $batch_count++;
 
-        my $starting_in_quote       = $this_batch->[_starting_in_quote_];
-        my $ending_in_quote         = $this_batch->[_ending_in_quote_];
-        my $is_static_block_comment = $this_batch->[_is_static_block_comment_];
-        my $rK_to_go                = $this_batch->[_rK_to_go_];
+        my $starting_in_quote        = $this_batch->[_starting_in_quote_];
+        my $ending_in_quote          = $this_batch->[_ending_in_quote_];
+        my $is_static_block_comment  = $this_batch->[_is_static_block_comment_];
+        my $rK_to_go                 = $this_batch->[_rK_to_go_];
+        my $ris_seqno_controlling_ci = $self->[_ris_seqno_controlling_ci_];
 
         my $rLL = $self->[_rLL_];
 
@@ -9337,6 +9412,7 @@ EOM
         my $comma_count_in_batch = 0;
         my $ilast_nonblank       = -1;
         my @colon_list;
+        my @ix_seqno_controlling_ci;
         for ( my $i = 0 ; $i <= $max_index_to_go ; $i++ ) {
             $bond_strength_to_go[$i] = 0;
             $iprev_to_go[$i]         = $ilast_nonblank;
@@ -9363,6 +9439,13 @@ EOM
                 # gather info needed by sub set_continuation_breaks
                 my $seqno = $type_sequence_to_go[$i];
                 if ($seqno) {
+
+                    # remember indexes of any tokens controlling xci
+                    # in this batch. This list is needed by sub undo_ci.
+                    if ( $ris_seqno_controlling_ci->{$seqno} ) {
+                        push @ix_seqno_controlling_ci, $i;
+                    }
+
                     if ( $type eq '?' ) {
                         push @colon_list, $type;
                     }
@@ -9370,7 +9453,6 @@ EOM
                         push @colon_list, $type;
                     }
                 }
-
             }
         }
 
@@ -9554,8 +9636,8 @@ EOM
                    $is_long_line
                 || $old_line_count_in_batch > 1
 
-               # must always call scan_list() with unbalanced batches because
-               # it is maintaining some stacks
+                # must always call scan_list() with unbalanced batches because
+                # it is maintaining some stacks
                 || is_unbalanced_batch()
 
                 # call scan_list if we might want to break at commas
@@ -9640,7 +9722,7 @@ EOM
 
             # unmask any invisible line-ending semicolon.  They were placed by
             # sub respace_tokens but we only now know if we actually need them.
-            if ( !$tokens_to_go[$imax] && $types_to_go[$imax] eq ';' ) { 
+            if ( !$tokens_to_go[$imax] && $types_to_go[$imax] eq ';' ) {
                 my $i       = $imax;
                 my $tok     = ';';
                 my $tok_len = 1;
@@ -9711,6 +9793,8 @@ EOM
             $this_batch->[_peak_batch_size_] = $peak_batch_size;
             $this_batch->[_do_not_pad_]      = $do_not_pad;
             $this_batch->[_batch_count_]     = $batch_count;
+            $this_batch->[_rix_seqno_controlling_ci_] =
+              \@ix_seqno_controlling_ci;
 
             $self->send_lines_to_vertical_aligner();
 
@@ -15007,7 +15091,6 @@ sub total_line_length {
       $summed_lengths_to_go[$ibeg];
 }
 
-
 sub excess_line_length {
 
     # return number of characters by which a line of tokens ($ibeg..$iend)
@@ -15018,7 +15101,7 @@ sub excess_line_length {
     my ( $self, $ibeg, $iend, $ignore_right_weld ) = @_;
 
     # Original expression for line length
-    ##$length = leading_spaces_to_go($ibeg) + token_sequence_length( $ibeg, $iend ); 
+    ##$length = leading_spaces_to_go($ibeg) + token_sequence_length( $ibeg, $iend );
 
     # This is basically sub 'leading_spaces_to_go':
     my $indentation = $leading_spaces_to_go[$ibeg];
@@ -15788,14 +15871,15 @@ sub send_lines_to_vertical_aligner {
     }
     my $n_last_line = @{$rlines_K} - 1;
 
-    my $do_not_pad              = $this_batch->[_do_not_pad_];
-    my $peak_batch_size         = $this_batch->[_peak_batch_size_];
-    my $starting_in_quote       = $this_batch->[_starting_in_quote_];
-    my $ending_in_quote         = $this_batch->[_ending_in_quote_];
-    my $is_static_block_comment = $this_batch->[_is_static_block_comment_];
-    my $ibeg0                   = $this_batch->[_ibeg0_];
-    my $rK_to_go                = $this_batch->[_rK_to_go_];
-    my $batch_count             = $this_batch->[_batch_count_];
+    my $do_not_pad               = $this_batch->[_do_not_pad_];
+    my $peak_batch_size          = $this_batch->[_peak_batch_size_];
+    my $starting_in_quote        = $this_batch->[_starting_in_quote_];
+    my $ending_in_quote          = $this_batch->[_ending_in_quote_];
+    my $is_static_block_comment  = $this_batch->[_is_static_block_comment_];
+    my $ibeg0                    = $this_batch->[_ibeg0_];
+    my $rK_to_go                 = $this_batch->[_rK_to_go_];
+    my $batch_count              = $this_batch->[_batch_count_];
+    my $rix_seqno_controlling_ci = $this_batch->[_rix_seqno_controlling_ci_];
 
     my $rLL    = $self->[_rLL_];
     my $Klimit = $self->[_Klimit_];
@@ -15841,7 +15925,7 @@ sub send_lines_to_vertical_aligner {
         $self->flush_vertical_aligner();
     }
 
-    $self->undo_ci( $ri_first, $ri_last );
+    $self->undo_ci( $ri_first, $ri_last, $rix_seqno_controlling_ci );
 
     $self->set_logical_padding( $ri_first, $ri_last, $peak_batch_size,
         $starting_in_quote )
@@ -16405,105 +16489,157 @@ sub get_seqno {
     return ($seqno);
 }
 
-sub undo_ci {
-
-    # Undo continuation indentation in certain sequences
-    # For example, we can undo continuation indentation in sort/map/grep chains
-    #    my $dat1 = pack( "n*",
-    #        map { $_, $lookup->{$_} }
-    #          sort { $a <=> $b }
-    #          grep { $lookup->{$_} ne $default } keys %$lookup );
-    # To align the map/sort/grep keywords like this:
-    #    my $dat1 = pack( "n*",
-    #        map { $_, $lookup->{$_} }
-    #        sort { $a <=> $b }
-    #        grep { $lookup->{$_} ne $default } keys %$lookup );
-    my ( $self, $ri_first, $ri_last ) = @_;
-    my ( $line_1, $line_2, $lev_last );
-    my $this_line_is_semicolon_terminated;
-    my $max_line = @{$ri_first} - 1;
+{
+    my %undo_extended_ci;
 
-    # looking at each line of this batch..
-    # We are looking at leading tokens and looking for a sequence
-    # all at the same level and higher level than enclosing lines.
-    foreach my $line ( 0 .. $max_line ) {
+    sub initialize_undo_ci {
+        %undo_extended_ci = ();
+    }
 
-        my $ibeg = $ri_first->[$line];
-        my $lev  = $levels_to_go[$ibeg];
-        if ( $line > 0 ) {
+    sub undo_ci {
 
-            # if we have started a chain..
-            if ($line_1) {
+        # Undo continuation indentation in certain sequences
+        my ( $self, $ri_first, $ri_last, $rix_seqno_controlling_ci ) = @_;
+        my ( $line_1, $line_2, $lev_last );
+        my $this_line_is_semicolon_terminated;
+        my $max_line = @{$ri_first} - 1;
 
-                # see if it continues..
-                if ( $lev == $lev_last ) {
-                    if (   $types_to_go[$ibeg] eq 'k'
-                        && $is_sort_map_grep{ $tokens_to_go[$ibeg] } )
-                    {
+        my $rseqno_which_extended_ci = $self->[_rseqno_which_extended_ci_];
+
+        # Loop over all lines of the batch ...
+        foreach my $line ( 0 .. $max_line ) {
+
+            ####################################
+            # SECTION 1: Undo needless common CI
+            ####################################
+
+         # We are looking at leading tokens and looking for a sequence
+         # all at the same level and all at a higher level than enclosing lines.
+
+            # For example, we can undo continuation indentation in sort/map/grep
+            # chains
 
-                        # chain continues...
-                        # check for chain ending at end of a statement
-                        if ( $line == $max_line ) {
+            #    my $dat1 = pack( "n*",
+            #        map { $_, $lookup->{$_} }
+            #          sort { $a <=> $b }
+            #          grep { $lookup->{$_} ne $default } keys %$lookup );
 
-                            # see of this line ends a statement
-                            my $iend = $ri_last->[$line];
-                            $this_line_is_semicolon_terminated =
-                              $types_to_go[$iend] eq ';'
+            # to become
+
+            #    my $dat1 = pack( "n*",
+            #        map { $_, $lookup->{$_} }
+            #        sort { $a <=> $b }
+            #        grep { $lookup->{$_} ne $default } keys %$lookup );
+
+            my $ibeg = $ri_first->[$line];
+            my $lev  = $levels_to_go[$ibeg];
+            if ( $line > 0 ) {
+
+                # if we have started a chain..
+                if ($line_1) {
+
+                    # see if it continues..
+                    if ( $lev == $lev_last ) {
+                        if (   $types_to_go[$ibeg] eq 'k'
+                            && $is_sort_map_grep{ $tokens_to_go[$ibeg] } )
+                        {
+
+                            # chain continues...
+                            # check for chain ending at end of a statement
+                            if ( $line == $max_line ) {
+
+                                # see of this line ends a statement
+                                my $iend = $ri_last->[$line];
+                                $this_line_is_semicolon_terminated =
+                                  $types_to_go[$iend] eq ';'
+
+                                  # with possible side comment
+                                  || ( $types_to_go[$iend] eq '#'
+                                    && $iend - $ibeg >= 2
+                                    && $types_to_go[ $iend - 2 ] eq ';'
+                                    && $types_to_go[ $iend - 1 ] eq 'b' );
+                            }
+                            $line_2 = $line
+                              if ($this_line_is_semicolon_terminated);
+                        }
+                        else {
 
-                              # with possible side comment
-                              || ( $types_to_go[$iend] eq '#'
-                                && $iend - $ibeg >= 2
-                                && $types_to_go[ $iend - 2 ] eq ';'
-                                && $types_to_go[ $iend - 1 ] eq 'b' );
+                            # kill chain
+                            $line_1 = undef;
                         }
-                        $line_2 = $line if ($this_line_is_semicolon_terminated);
                     }
-                    else {
+                    elsif ( $lev < $lev_last ) {
+
+                        # chain ends with previous line
+                        $line_2 = $line - 1;
+                    }
+                    elsif ( $lev > $lev_last ) {
 
                         # kill chain
                         $line_1 = undef;
                     }
-                }
-                elsif ( $lev < $lev_last ) {
 
-                    # chain ends with previous line
-                    $line_2 = $line - 1;
+                    # undo the continuation indentation if a chain ends
+                    if ( defined($line_2) && defined($line_1) ) {
+                        my $continuation_line_count = $line_2 - $line_1 + 1;
+                        @ci_levels_to_go[ @{$ri_first}[ $line_1 .. $line_2 ] ]
+                          = (0) x ($continuation_line_count)
+                          if ( $continuation_line_count >= 0 );
+                        @leading_spaces_to_go[ @{$ri_first}
+                          [ $line_1 .. $line_2 ] ] =
+                          @reduced_spaces_to_go[ @{$ri_first}
+                          [ $line_1 .. $line_2 ] ];
+                        $line_1 = undef;
+                    }
                 }
-                elsif ( $lev > $lev_last ) {
 
-                    # kill chain
-                    $line_1 = undef;
-                }
+                # not in a chain yet..
+                else {
 
-                # undo the continuation indentation if a chain ends
-                if ( defined($line_2) && defined($line_1) ) {
-                    my $continuation_line_count = $line_2 - $line_1 + 1;
-                    @ci_levels_to_go[ @{$ri_first}[ $line_1 .. $line_2 ] ] =
-                      (0) x ($continuation_line_count)
-                      if ( $continuation_line_count >= 0 );
-                    @leading_spaces_to_go[ @{$ri_first}[ $line_1 .. $line_2 ] ]
-                      = @reduced_spaces_to_go[ @{$ri_first}
-                      [ $line_1 .. $line_2 ] ];
-                    $line_1 = undef;
+                    # look for start of a new sort/map/grep chain
+                    if ( $lev > $lev_last ) {
+                        if (   $types_to_go[$ibeg] eq 'k'
+                            && $is_sort_map_grep{ $tokens_to_go[$ibeg] } )
+                        {
+                            $line_1 = $line;
+                        }
+                    }
                 }
             }
 
-            # not in a chain yet..
-            else {
+            #########################################################
+            # SECTION 2: Undo ci set by sub extended_ci if not needed
+            #########################################################
 
-                # look for start of a new sort/map/grep chain
-                if ( $lev > $lev_last ) {
-                    if (   $types_to_go[$ibeg] eq 'k'
-                        && $is_sort_map_grep{ $tokens_to_go[$ibeg] } )
-                    {
-                        $line_1 = $line;
-                    }
+            # Undo the ci of the leading token if its controlling token
+            # went out on a previous line without ci
+            if ( $ci_levels_to_go[$ibeg] ) {
+                my $Kbeg  = $K_to_go[$ibeg];
+                my $seqno = $rseqno_which_extended_ci->{$Kbeg};
+                if ( $seqno && $undo_extended_ci{$seqno} ) {
+                    $ci_levels_to_go[$ibeg]      = 0;
+                    $leading_spaces_to_go[$ibeg] = $reduced_spaces_to_go[$ibeg];
                 }
             }
+
+            # Flag any controlling opening tokens in lines without ci.
+            # This will be used later in the above if statement to undo the
+            # ci which they added.
+            elsif ( @{$rix_seqno_controlling_ci} ) {
+                my $iend = $ri_last->[$line];
+                foreach my $i ( @{$rix_seqno_controlling_ci} ) {
+                    next if ( $i < $ibeg );
+                    last if ( $i > $iend );
+                    my $seqno = $type_sequence_to_go[$i];
+                    $undo_extended_ci{$seqno} = 1;
+                }
+            }
+
+            $lev_last = $lev;
         }
-        $lev_last = $lev;
+
+        return;
     }
-    return;
 }
 
 {    ## begin closure set_logical_padding