]> git.donarmstrong.com Git - perltidy.git/commitdiff
added option --non-indenting-braces
authorSteve Hancock <perltidy@users.sourceforge.net>
Tue, 1 Sep 2020 00:52:45 +0000 (17:52 -0700)
committerSteve Hancock <perltidy@users.sourceforge.net>
Tue, 1 Sep 2020 00:52:45 +0000 (17:52 -0700)
13 files changed:
CHANGES.md
bin/perltidy
lib/Perl/Tidy.pm
lib/Perl/Tidy/Formatter.pm
lib/Perl/Tidy/VerticalAligner.pm
t/snippets/expect/nib.def [new file with mode: 0644]
t/snippets/expect/nib.nib1 [new file with mode: 0644]
t/snippets/expect/nib.nib2 [new file with mode: 0644]
t/snippets/nib.in [new file with mode: 0644]
t/snippets/nib1.par [new file with mode: 0644]
t/snippets/nib2.par [new file with mode: 0644]
t/snippets/packing_list.txt
t/snippets21.t

index d7c49749a6ac76b85d31be56b6cdf7c8f418b7e3..2d49007ce7b183343902ad3e014819b14d8b7da3 100644 (file)
@@ -1,5 +1,11 @@
 # Perltidy Change Log
 
+    - Added parameter --non-indenting-braces, or -nib, which prevents
+      code following an opening brace marked with a special side comment 
+      from indenting one level.  This is off by default and turned on 
+      with -nib.  It might be useful for preventing code from shifting 
+      when adding or testing closures, for example.
+
     - Side comment locations reset at a line ending in a level 0 open
       block, such as when a new multi-line sub begins.  This is intended to 
       help keep side comments from drifting to far to the right.
index 8d345f49b959e13e08065f1c6bde4f364fdb7fa8..33383d8b3743a14ff98e2432f6e54ee918f1dcf7 100755 (executable)
@@ -847,6 +847,45 @@ terminates a code block .  For example,
 
 The default is not to do this, indicated by B<-nicb>.
 
+
+=item B<-nib>, B<--non-indenting-braces>
+
+If this flag is set, perltidy will look for opening block braces which are
+followed by a special side comment, which is B<#<<<> by default.  If found, the
+code between this opening brace and its corresponding closing brace will not be
+given the normal extra indentation level.  As a simple example, 
+
+  perltidy -nib:
+
+    { #<<<
+    print "hello world\n";
+    }
+
+This might be useful, for example, to keep large sections of code from
+moving to the right when placed in a closure.
+
+Only the opening brace needs to be marked, and nested braces can be marked.
+The special side comment can be changed with the next parameter.
+
+
+=item B<-nibp=s>, B<--non-indenting-brace-prefix=s>
+
+The B<-nibp=string> parameter may be used to change the marker for
+non-indenting braces.  The default is equivalent to -nibp='#<<<'.  The string
+that you enter must begin with a # and should be in quotes as necessary to get
+past the command shell of your system.  This string is the leading text of a
+regex pattern that is constructed by appending pre-pending a '^', so you must
+also include backslashes for characters to be taken literally rather than as
+patterns.
+
+For example, to match the side comment '#++', the parameter would be
+  
+  -nibp='#\+\+'
+
+Note that the default string is the same as the string for starting a
+B<format-skipping> section, but it is for a side-comment rather than a block
+comment. 
+
 =item B<-olq>, B<--outdent-long-quotes>
 
 When B<-olq> is set, lines which is a quoted string longer than the
index f090b69ee8cb146833debf0eba2dc73244e24a72..2f52af0ac200e21a75f338804d95fc7f51220b29 100644 (file)
@@ -2189,6 +2189,8 @@ sub generate_options {
     $add_option->( 'indent-spaced-block-comments',      'isbc', '!' );
     $add_option->( 'fixed-position-side-comment',       'fpsc', '=i' );
     $add_option->( 'minimum-space-to-comment',          'msc',  '=i' );
+    $add_option->( 'non-indenting-braces',              'nib',  '!' );
+    $add_option->( 'non-indenting-brace-prefix',        'nibp', '=s' );
     $add_option->( 'outdent-long-comments',             'olc',  '!' );
     $add_option->( 'outdent-static-block-comments',     'osbc', '!' );
     $add_option->( 'static-block-comment-prefix',       'sbcp', '=s' );
@@ -2463,6 +2465,7 @@ sub generate_options {
       noquiet
       noshow-options
       nostatic-side-comments
+      nonon-indenting-braces
       notabs
       nowarning-output
       one-line-block-semicolons=1
index 268b39b444c397926a2bededc3af6801ab59782e..01dd46164ff56f9de1d0b9e90a0a596f789ed44a 100644 (file)
@@ -190,6 +190,8 @@ use vars qw{
   $format_skipping_pattern_begin
   $format_skipping_pattern_end
 
+  $non_indenting_brace_pattern
+
   $bli_pattern
 
   $block_brace_vertical_tightness_pattern
@@ -205,10 +207,9 @@ use vars qw{
 
 };
 
-###################################################################
-# Section 2: Global variables which relate to an individual script.
-# These are work arrays for the current batch of tokens.
-###################################################################
+#########################################################
+# Section 2: Work arrays for the current batch of tokens.
+#########################################################
 
 use vars qw{
   $max_index_to_go
@@ -4574,21 +4575,96 @@ sub weld_len_right_to_go {
     return $weld_len;
 }
 
+sub adjust_indentation_levels {
+
+    my ($self) = @_;
+
+    # Set adjusted levels for any non-indenting braces
+    $self->non_indenting_braces();
+
+    # Set adjusted levels for the whitespace cycle option
+    $self->whitespace_cycle_adjustment();
+
+}
+
+sub non_indenting_braces {
+
+    # remove indentation within marked braces if requested
+    my ($self) = @_;
+    return unless ( $rOpts->{'non-indenting-braces'} );
+
+    my $rLL  = $self->[_rLL_];
+    return unless ( defined($rLL) && @{$rLL} );
+
+    my $radjusted_levels;
+    my $Kmax = @{$rLL} - 1;
+    my @seqno_stack;
+
+    my $is_non_indenting_brace = sub {
+        my ($KK)       = @_;
+        my $token      = $rLL->[$KK]->[_TOKEN_];
+        my $block_type = $rLL->[$KK]->[_BLOCK_TYPE_];
+        return unless ( $token eq '{' && $block_type );
+        my $line_index = $rLL->[$KK]->[_LINE_INDEX_];
+        my $K_sc       = $self->K_next_nonblank($KK);
+        return unless defined($K_sc);
+        my $line_index_sc = $rLL->[$K_sc]->[_LINE_INDEX_];
+        return unless ( $line_index_sc == $line_index );
+        my $type_sc = $rLL->[$K_sc]->[_TYPE_];
+        return unless ( $type_sc eq '#' );
+        my $token_sc = $rLL->[$K_sc]->[_TOKEN_];
+        return ( $token_sc =~ /$non_indenting_brace_pattern/ );
+    };
+
+    foreach my $KK ( 0 .. $Kmax ) {
+        my $seqno     = $rLL->[$KK]->[_TYPE_SEQUENCE_];
+        my $level_abs = $rLL->[$KK]->[_LEVEL_];
+        my $level     = $level_abs;
+        my $num       = @seqno_stack;
+        if ($seqno) {
+            my $token = $rLL->[$KK]->[_TOKEN_];
+            if ( $token eq '{' && $is_non_indenting_brace->($KK) ) {
+                push @seqno_stack, $seqno;
+            }
+            if ( $token eq '}' && @seqno_stack && $seqno_stack[-1] == $seqno ) {
+                pop @seqno_stack;
+                $num -= 1;
+            }
+        }
+        if ($num) { $level -= $num }
+        $radjusted_levels->[$KK] = $level;
+    }
+    $self->[_radjusted_levels_] = $radjusted_levels;
+    return;
+}
+
 sub whitespace_cycle_adjustment {
 
     my $self = shift;
     my $rLL  = $self->[_rLL_];
     return unless ( defined($rLL) && @{$rLL} );
-    my $radjusted_levels;
+    my $radjusted_levels = $self->[_radjusted_levels_];
+
     my $rOpts_whitespace_cycle = $rOpts->{'whitespace-cycle'};
     if ( $rOpts_whitespace_cycle && $rOpts_whitespace_cycle > 0 ) {
+
+        my $Kmax = @{$rLL} - 1;
+
+        # We have to start with any existing adjustments
+        my $adjusted_levels_defined =
+          defined($radjusted_levels) && @{$radjusted_levels} == @{$rLL};
+        if ( !$adjusted_levels_defined ) {
+            foreach my $KK ( 0 .. $Kmax ) {
+                $radjusted_levels->[$KK] = $rLL->[$KK]->[_LEVEL_];
+            }
+        }
+
         my $whitespace_last_level  = -1;
         my @whitespace_level_stack = ();
         my $last_nonblank_type     = 'b';
         my $last_nonblank_token    = '';
-        my $Kmax                   = @{$rLL} - 1;
         foreach my $KK ( 0 .. $Kmax ) {
-            my $level_abs = $rLL->[$KK]->[_LEVEL_];
+            my $level_abs = $radjusted_levels->[$KK];  ##$rLL->[$KK]->[_LEVEL_];
             my $level     = $level_abs;
             if ( $level_abs < $whitespace_last_level ) {
                 pop(@whitespace_level_stack);
@@ -4890,8 +4966,7 @@ sub finish_formatting {
     # Locate small nested blocks which should not be broken
     $self->mark_short_nested_blocks();
 
-    # Set adjusted levels for the whitespace cycle option
-    $self->whitespace_cycle_adjustment();
+    $self->adjust_indentation_levels();
 
     # Adjust continuation indentation if -bli is set
     $self->bli_adjustment();
@@ -5078,8 +5153,13 @@ sub get_available_spaces_to_go {
         # Adjust levels if necessary to recycle whitespace:
         my $level            = $level_abs;
         my $radjusted_levels = $self->[_radjusted_levels_];
+        my $nK               = @{$rLL};
+        my $nws              = @{$radjusted_levels};
         if ( defined($radjusted_levels) && @{$radjusted_levels} == @{$rLL} ) {
             $level = $radjusted_levels->[$Kj];
+
+            # negative levels can occure in bad files
+            if ( $level < 0 ) { $level = 0 }
         }
 
         # The continued_quote flag means that this is the first token of a
@@ -5810,6 +5890,7 @@ sub check_options {
       make_format_skipping_pattern( 'format-skipping-begin', '#<<<' );
     $format_skipping_pattern_end =
       make_format_skipping_pattern( 'format-skipping-end', '#>>>' );
+    make_non_indenting_brace_pattern();
 
     # If closing side comments ARE selected, then we can safely
     # delete old closing side comments unless closing side comment
@@ -6455,6 +6536,29 @@ sub make_format_skipping_pattern {
     return $pattern;
 }
 
+sub make_non_indenting_brace_pattern {
+
+    # create the pattern used to identify static side comments
+    $non_indenting_brace_pattern = '^#<<<';
+
+    # allow the user to change it
+    if ( $rOpts->{'non-indenting-brace-prefix'} ) {
+        my $prefix = $rOpts->{'non-indenting-brace-prefix'};
+        $prefix =~ s/^\s*//;
+        if ( $prefix !~ /^#/ ) {
+            Die("ERROR: the -nibp parameter '$prefix' must begin with '#'\n");
+        }
+        my $pattern = '^' . $prefix;
+        if ( bad_pattern($pattern) ) {
+            Die(
+"ERROR: the -nibp prefix '$prefix' causes the invalid regex '$pattern'\n"
+            );
+        }
+        $non_indenting_brace_pattern = $pattern;
+    }
+    return;
+}
+
 sub make_closing_side_comment_list_pattern {
 
     # turn any input list into a regex for recognizing selected block types
@@ -7403,6 +7507,9 @@ sub copy_token_as_type {
         my $radjusted_levels = $self->[_radjusted_levels_];
         if ( defined($radjusted_levels) && @{$radjusted_levels} == @{$rLL} ) {
             $level_wc = $radjusted_levels->[$Ktoken_vars];
+
+            # negative levels can occure in bad files
+            if ( $level_wc < 0 ) { $level_wc = 0 }
         }
         my $space_count =
           $ci_level * $rOpts_continuation_indentation +
@@ -10728,6 +10835,13 @@ sub send_lines_to_vertical_aligner {
             }
         }
 
+        my $level_adj        = $lev;
+        my $radjusted_levels = $self->[_radjusted_levels_];
+        if ( defined($radjusted_levels) && @{$radjusted_levels} == @{$rLL} ) {
+            $level_adj = $radjusted_levels->[$Kbeg];
+            if ( $level_adj < 0 ) { $level_adj = 0 }
+        }
+
         # add any new closing side comment to the last line
         if ( $closing_side_comment && $n == $n_last_line && @{$rfields} ) {
             $rfields->[-1] .= " $closing_side_comment";
@@ -10741,6 +10855,7 @@ sub send_lines_to_vertical_aligner {
         my $rvalign_hash = {};
         $rvalign_hash->{level}           = $lev;
         $rvalign_hash->{level_end}       = $level_end;
+        $rvalign_hash->{level_adj}       = $level_adj;
         $rvalign_hash->{indentation}     = $indentation;
         $rvalign_hash->{is_forced_break} = $forced_breakpoint || $in_comma_list;
         $rvalign_hash->{outdent_long_lines}        = $outdent_long_lines;
index 1073eff6d5d496100273fa7b53e0ce273a84e320..7a87109f89062c2bf9d8f7c3fdfbda3be929fabe 100644 (file)
@@ -342,6 +342,7 @@ sub valign_input {
 
     my $level                     = $rline_hash->{level};
     my $level_end                 = $rline_hash->{level_end};
+    my $level_adj                 = $rline_hash->{level_adj};
     my $indentation               = $rline_hash->{indentation};
     my $is_forced_break           = $rline_hash->{is_forced_break};
     my $outdent_long_lines        = $rline_hash->{outdent_long_lines};
@@ -397,7 +398,7 @@ sub valign_input {
 
     # Reset side comment location if we are entering a new block from level 0.
     # This is intended to keep them from drifting too far to the right.
-    if ( $terminal_block_type && $level == 0 && $level_end > $level ) {
+    if ( $terminal_block_type && $level_adj == 0 && $level_end > $level ) {
         $self->forget_side_comment();
     }
 
diff --git a/t/snippets/expect/nib.def b/t/snippets/expect/nib.def
new file mode 100644 (file)
index 0000000..dd67a28
--- /dev/null
@@ -0,0 +1,16 @@
+{    #<<<
+    {    #<<<
+        {    #++
+            print "hello world\n";
+        }
+    }
+}
+
+{    #++
+    {    #++
+        {    #<<<
+            print "hello world\n";
+        }
+    }
+}
+
diff --git a/t/snippets/expect/nib.nib1 b/t/snippets/expect/nib.nib1
new file mode 100644 (file)
index 0000000..4499f50
--- /dev/null
@@ -0,0 +1,16 @@
+{    #<<<
+{    #<<<
+{    #++
+    print "hello world\n";
+}
+}
+}
+
+{    #++
+    {    #++
+        {    #<<<
+        print "hello world\n";
+        }
+    }
+}
+
diff --git a/t/snippets/expect/nib.nib2 b/t/snippets/expect/nib.nib2
new file mode 100644 (file)
index 0000000..4b36c95
--- /dev/null
@@ -0,0 +1,16 @@
+{    #<<<
+    {    #<<<
+        {    #++
+        print "hello world\n";
+        }
+    }
+}
+
+{    #++
+{    #++
+{    #<<<
+    print "hello world\n";
+}
+}
+}
+
diff --git a/t/snippets/nib.in b/t/snippets/nib.in
new file mode 100644 (file)
index 0000000..4499f50
--- /dev/null
@@ -0,0 +1,16 @@
+{    #<<<
+{    #<<<
+{    #++
+    print "hello world\n";
+}
+}
+}
+
+{    #++
+    {    #++
+        {    #<<<
+        print "hello world\n";
+        }
+    }
+}
+
diff --git a/t/snippets/nib1.par b/t/snippets/nib1.par
new file mode 100644 (file)
index 0000000..b79e8ce
--- /dev/null
@@ -0,0 +1 @@
+-nib
diff --git a/t/snippets/nib2.par b/t/snippets/nib2.par
new file mode 100644 (file)
index 0000000..9845232
--- /dev/null
@@ -0,0 +1 @@
+-nib -nibp='#\+\+'
index 42cf2869a8dee3a4d034eb1b28b2084084eaaf94..3899237149cb1b9c51a6f5161b83c688293592a3 100644 (file)
 ../snippets9.t rt98902.def
 ../snippets9.t rt98902.rt98902
 ../snippets9.t rt99961.def
+../snippets21.t        nib.def
+../snippets21.t        nib.nib1
+../snippets21.t        nib.nib2
index a41b696776492f8cd9d601a84a64ec9d4c671db3..b9436b9a16daeee1b270003054d6ce618e9a4885 100644 (file)
@@ -14,6 +14,9 @@
 #11 git33.git33
 #12 rt133130.def
 #13 rt133130.rt133130
+#14 nib.def
+#15 nib.nib1
+#16 nib.nib2
 
 # To locate test #13 you can search for its name or the string '#13'
 
@@ -36,8 +39,12 @@ BEGIN {
 -wls='->' -wrs='->'
 
 ----------
-        'gnu'      => "-gnu",
-        'lop'      => "-nlop",
+        'gnu'  => "-gnu",
+        'lop'  => "-nlop",
+        'nib1' => "-nib",
+        'nib2' => <<'----------',
+-nib -nibp='#\+\+'
+----------
         'rt133130' => <<'----------',
 # only the method should get a csc:
 -csc -cscl=sub -sal=method
@@ -105,6 +112,25 @@ $bits =
 lc( $self->mime_attr('content-type')
         || $self->{MIH_DefaultType}
         || 'text/plain' );
+----------
+
+        'nib' => <<'----------',
+{    #<<<
+{    #<<<
+{    #++
+    print "hello world\n";
+}
+}
+}
+
+{    #++
+    {    #++
+        {    #<<<
+        print "hello world\n";
+        }
+    }
+}
+
 ----------
 
         'prune' => <<'----------',
@@ -559,6 +585,75 @@ method sum_radlinks {
 } ## end sub sum_radlinks
 #13...........
         },
+
+        'nib.def' => {
+            source => "nib",
+            params => "def",
+            expect => <<'#14...........',
+{    #<<<
+    {    #<<<
+        {    #++
+            print "hello world\n";
+        }
+    }
+}
+
+{    #++
+    {    #++
+        {    #<<<
+            print "hello world\n";
+        }
+    }
+}
+
+#14...........
+        },
+
+        'nib.nib1' => {
+            source => "nib",
+            params => "nib1",
+            expect => <<'#15...........',
+{    #<<<
+{    #<<<
+{    #++
+    print "hello world\n";
+}
+}
+}
+
+{    #++
+    {    #++
+        {    #<<<
+        print "hello world\n";
+        }
+    }
+}
+
+#15...........
+        },
+
+        'nib.nib2' => {
+            source => "nib",
+            params => "nib2",
+            expect => <<'#16...........',
+{    #<<<
+    {    #<<<
+        {    #++
+        print "hello world\n";
+        }
+    }
+}
+
+{    #++
+{    #++
+{    #<<<
+    print "hello world\n";
+}
+}
+}
+
+#16...........
+        },
     };
 
     my $ntests = 0 + keys %{$rtests};