## 2020 01 10.01
+ - Added a parameter -kpit=n to control spaces inside of parens following
+ certain keywords, requested in git#26. This flag is off by default.
+
- Added fix for git#25, improve vertical alignment for long lists with
varying numbers of items per line.
sub usage(); # n=1 [default; follows input]
sub usage (); # n=2 [space]
+=item B<-kpit=n> or B<--keyword-paren-inner-tightness=n>
+
+The space inside of an opening paren, which itself follows a certain keyword,
+can be controlled by this parameter. The space on the inside of the
+corresponding closing paren will be treated in the same (balanced) manner.
+This parameter has precedence over any other paren spacing rules. The values
+of B<n> are as follows:
+
+ -kpit=0 means always put a space (not tight)
+ -kpit=1 means ignore this parameter [default]
+ -kpit=2 means never put a space (tight)
+
+To illustrate, the following snippet is shown formatted in three ways:
+
+ if ( seek( DATA, 0, 0 ) ) { ... } # perltidy (default)
+ if (seek(DATA, 0, 0)) { ... } # perltidy -pt=2
+ if ( seek(DATA, 0, 0) ) { ... } # perltidy -pt=2 -kpit=0
+
+In the second case the -pt=2 parameter makes all of the parens tight. In the
+third case the -kpit=0 flag causes the space within the 'if' parens to have a
+space, since 'if' is one of the keywords to which the -kpit flag applies by
+default. The remaining parens are still tight because of the -pt=2 parameter.
+
+The set of keywords to which this parameter applies are by default are:
+
+ if elsif unless while until for foreach
+
+These can be changed with the parameter B<-kpitl=s> described in the next section.
+
+
+=item B<-kpitl=string> or B<--keyword-paren-inner-tightness=string>
+
+This command can be used to change the keywords to which the the B<-kpit=n>
+command applies. The parameter B<string> is a required list either keywords or
+functions, which should be placed in quotes if there are more than one. By
+itself, this parameter does not cause any change in spacing, so the B<-kpit=n>
+command is still required.
+
+For example, the commands C<-kpitl="if else while" -kpit=2> will cause the just
+the spaces inside parens following 'if', 'else', and 'while' keywords to
+follow the tightness value indicated by the B<-kpit=2> flag.
+
=item Trimming whitespace around C<qw> quotes
B<-tqw> or B<--trim-qw> provide the default behavior of trimming
<h2>2020 01 10.01</h2>
-<pre><code>- add option --break-at-old-semicolon-breakpoints', -bos, requested
+<pre><code>- Added fix for git#25, improve vertical alignment for long lists with
+ varying numbers of items per line.
+
+- calls to the module Perl::Tidy can now capture any output produced
+ by a debug flag or one of the 'tee' flags through the new 'debugfile' and
+ 'teefile' call parameters. These output streams are rarely used but
+ they are now treated the same as any 'logfile' stream.
+
+- add option --break-at-old-semicolon-breakpoints', -bos, requested
in RT#131644. This flag will keep lines beginning with a semicolon.
- Added --use-unicode-gcstring to control use of Unicode::GCString for
perltidyrc => $perltidyrc,
logfile => $logfile,
errorfile => $errorfile,
+ teefile => $teefile,
+ debugfile => $debugfile,
formatter => $formatter, # callback object (see below)
dump_options => $dump_options,
dump_options_type => $dump_options_type,
<p>The <b>logfile</b> parameter allows the calling program to capture the log stream. This stream is only created if requested with a <b>-g</b> parameter. It contains detailed diagnostic information about a script which may be useful for debugging.</p>
+</dd>
+<dt id="teefile">teefile</dt>
+<dd>
+
+<p>The <b>teefile</b> parameter allows the calling program to capture the tee stream. This stream is only created if requested with one of the 'tee' parameters, a <b>--tee-pod</b> , <b>--tee-block-comments</b>, <b>--tee-side-commnts</b>, or <b>--tee-all-comments</b>.</p>
+
+</dd>
+<dt id="debugfile">debugfile</dt>
+<dd>
+
+<p>The <b>debugfile</b> parameter allows the calling program to capture the stream produced by the <b>--DEBUG</b> parameter. This parameter is mainly used for debugging perltidy itself.</p>
+
</dd>
<dt id="argv">argv</dt>
<dd>
sub usage(); # n=1 [default; follows input]
sub usage (); # n=2 [space]</code></pre>
+</dd>
+<dt id="kpit-n-or---keyword-paren-inner-tightness-n"><b>-kpit=n</b> or <b>--keyword-paren-inner-tightness=n</b></dt>
+<dd>
+
+<p>The space inside of an opening paren, which itself follows a certain keyword, can be controlled by this parameter. The space on the inside of the corresponding closing paren will be treated in the same (balanced) manner. This parameter has precedence over any other paren spacing rules. The values of <b>n</b> are as follows:</p>
+
+<pre><code> -kpit=0 means always put a space (not tight)
+ -kpit=1 means ignore this parameter [default]
+ -kpit=2 means never put a space (tight)</code></pre>
+
+<p>To illustrate, the following snippet is shown formatted in three ways:</p>
+
+<pre><code> if ( seek( DATA, 0, 0 ) ) { ... } # perltidy (default)
+ if (seek(DATA, 0, 0)) { ... } # perltidy -pt=2
+ if ( seek(DATA, 0, 0) ) { ... } # perltidy -pt=2 -kpit=0</code></pre>
+
+<p>In the second case the -pt=2 parameter makes all of the parens tight. In the third case the -kpit=0 flag causes the space within the 'if' parens to have a space, since 'if' is one of the keywords to which the -kpit flag applies by default. The remaining parens are still tight because of the -pt=2 parameter.</p>
+
+<p>The set of keywords to which this parameter applies are by default are:</p>
+
+<pre><code> if elsif unless while until for foreach</code></pre>
+
+<p>These can be changed with the parameter <b>-kpitl=s</b> described in the next section.</p>
+
+</dd>
+<dt id="kpitl-string-or---keyword-paren-inner-tightness-string"><b>-kpitl=string</b> or <b>--keyword-paren-inner-tightness=string</b></dt>
+<dd>
+
+<p>This command can be used to change the keywords to which the the <b>-kpit=n</b> command applies. The parameter <b>string</b> is a required list either keywords or functions, which should be placed in quotes if there are more than one. By itself, this parameter does not cause any change in spacing, so the <b>-kpit=n</b> command is still required.</p>
+
+<p>For example, the commands <code>-kpitl="if else while" -kpit=2</code> will cause the just the spaces inside parens following 'if', 'else', and 'while' keywords to follow the tightness value indicated by the <b>-kpit=2</b> flag.</p>
+
</dd>
<dt id="Trimming-whitespace-around-qw-quotes">Trimming whitespace around <code>qw</code> quotes</dt>
<dd>
$add_option->( 'brace-tightness', 'bt', '=i' );
$add_option->( 'delete-old-whitespace', 'dws', '!' );
$add_option->( 'delete-semicolons', 'dsm', '!' );
+ $add_option->( 'keyword-paren-inner-tightness', 'kpit', '=i' );
+ $add_option->( 'keyword-paren-inner-tightness-list', 'kpitl', '=s' );
$add_option->( 'nospace-after-keyword', 'nsak', '=s' );
$add_option->( 'nowant-left-space', 'nwls', '=s' );
$add_option->( 'nowant-right-space', 'nwrs', '=s' );
%option_range = (
'format' => [ 'tidy', 'html', 'user' ],
'output-line-ending' => [ 'dos', 'win', 'mac', 'unix' ],
- 'space-backslash-quote' => [ 0, 2 ],
- 'block-brace-tightness' => [ 0, 2 ],
- 'brace-tightness' => [ 0, 2 ],
- 'paren-tightness' => [ 0, 2 ],
- 'square-bracket-tightness' => [ 0, 2 ],
+ 'space-backslash-quote' => [ 0, 2 ],
+ 'block-brace-tightness' => [ 0, 2 ],
+ 'keyword-paren-inner-tightness' => [ 0, 2 ],
+ 'brace-tightness' => [ 0, 2 ],
+ 'paren-tightness' => [ 0, 2 ],
+ 'square-bracket-tightness' => [ 0, 2 ],
'block-brace-vertical-tightness' => [ 0, 2 ],
'brace-vertical-tightness' => [ 0, 2 ],
indent-columns=4
iterations=1
keep-old-blank-lines=1
+ keyword-paren-inner-tightness=1
long-block-line-count=8
look-for-autoloader
look-for-selfloader
%closing_vertical_tightness
%closing_token_indentation
$some_closing_token_indentation
+ %keyword_paren_inner_tightness
%opening_token_right
%stack_opening_token
my $rwhitespace_flags = [];
- my ( $last_token, $last_type, $last_block_type, $last_input_line_no,
- $token, $type, $block_type, $input_line_no );
+ my ( $token, $type, $block_type, $seqno, $input_line_no );
+ my (
+ $last_token, $last_type, $last_block_type,
+ $last_seqno, $last_input_line_no
+ );
+
my $j_tight_closing_paren = -1;
$token = ' ';
$type = 'b';
$block_type = '';
+ $seqno = '';
$input_line_no = 0;
$last_token = ' ';
$last_type = 'b';
$last_block_type = '';
+ $last_seqno = '';
$last_input_line_no = 0;
my $jmax = @{$rLL} - 1;
return (WS_YES);
};
+ # Local hashes to set spaces around container tokens according to their
+ # sequence numbers. These are set as keywords are examined.
+ # They are controlled by the -kpit and -kpitl flags.
+ my %opening_container_inside_ws;
+ my %closing_container_inside_ws;
+ my $set_container_ws_by_keyword = sub {
+ my ( $word, $sequence_number ) = @_;
+
+ # We just saw a keyword (or other function name) followed by an opening
+ # paren. Now check to see if the following paren should have special
+ # treatment for its inside space. If so we set a hash value using the
+ # sequence number as key.
+ if ($word) {
+ my $tightness = $keyword_paren_inner_tightness{$word};
+ if ( defined($tightness) && $tightness != 1 ) {
+ my $ws_flag = $tightness == 0 ? WS_YES : WS_NO;
+ $opening_container_inside_ws{$sequence_number} = $ws_flag;
+ $closing_container_inside_ws{$sequence_number} = $ws_flag;
+ }
+ }
+ };
+
+ my $ws_opening_container_override = sub {
+ my ( $ws, $sequence_number ) = @_;
+ if ($sequence_number) {
+ my $ws_override = $opening_container_inside_ws{$sequence_number};
+ if ($ws_override) { $ws = $ws_override }
+ }
+ return $ws;
+ };
+
+ my $ws_closing_container_override = sub {
+ my ( $ws, $sequence_number ) = @_;
+ if ($sequence_number) {
+ my $ws_override = $closing_container_inside_ws{$sequence_number};
+ if ($ws_override) { $ws = $ws_override }
+ }
+ return $ws;
+ };
+
# main loop over all tokens to define the whitespace flags
for ( my $j = 0 ; $j <= $jmax ; $j++ ) {
$last_token = $token;
$last_type = $type;
$last_block_type = $block_type;
+ $last_seqno = $seqno;
$last_input_line_no = $input_line_no;
$token = $rtokh->[_TOKEN_];
$type = $rtokh->[_TYPE_];
$block_type = $rtokh->[_BLOCK_TYPE_];
+ $seqno = $rtokh->[_TYPE_SEQUENCE_];
$input_line_no = $rtokh->[_LINE_INDEX_];
#---------------------------------------------------------------
$ws = $ws_in_container->($j);
}
}
+
+ # check for special cases which override the above rules
+ $ws = $ws_opening_container_override->( $ws, $last_seqno );
+
} # end setting space flag inside opening tokens
my $ws_1;
$ws_1 = $ws
$ws = ( $tightness > 1 ) ? WS_NO : WS_YES;
}
}
+
+ # check for special cases which override the above rules
+ $ws = $ws_closing_container_override->( $ws, $seqno );
+
} # end setting space flag inside closing tokens
my $ws_2;
$ws = WS_NO
unless ( $rOpts_space_keyword_paren
|| $space_after_keyword{$last_token} );
+
+ # Set inside space flag if requested
+ $set_container_ws_by_keyword->( $last_token, $seqno );
}
# Space between function and '('
|| ( $last_type =~ /^[wi]$/ && $last_token =~ /^(\&|->)/ ) )
{
$ws = WS_NO unless ($rOpts_space_function_paren);
+ $set_container_ws_by_keyword->( $last_token, $seqno );
}
# space between something like $i and ( in <<snippets/space2.in>>
}
}
+ # setup hash for -kpit option
+ %keyword_paren_inner_tightness = ();
+ my @kpit = split_words( $rOpts->{'keyword-paren-inner-tightness-list'} );
+ unless (@kpit) {
+ @kpit = qw(if elsif unless while until for foreach); # defaults
+ }
+
+ # we will allow keywords and user-defined identifiers
+ foreach (@kpit) {
+ $keyword_paren_inner_tightness{$_} =
+ $rOpts->{'keyword-paren-inner-tightness'};
+ }
+
# implement user whitespace preferences
if ( my @q = split_words( $rOpts->{'want-left-space'} ) ) {
@want_left_space{@q} = (1) x scalar(@q);
$K_last_nonblank_code = undef;
$K_last_last_nonblank_code = undef;
$looking_for_else = 0;
+ return;
}
# batch variables
$rbrace_follower = undef;
$comma_count_in_batch = 0;
destroy_one_line_block();
+ return;
}
sub create_one_line_block {
--- /dev/null
+if ( seek( DATA, 0, 0 ) ) { ... }
--- /dev/null
+if ( seek(DATA, 0, 0) ) { ... }
--- /dev/null
+return ( $r**$n ) *
+ ( pi**( $n / 2 ) ) /
+ (
+ sqrt(pi) *
+ factorial( 2 * ( int( $n / 2 ) ) + 2 ) /
+ factorial( int( $n / 2 ) + 1 ) /
+ ( 4**( int( $n / 2 ) + 1 ) ) );
--- /dev/null
+return ( $r**$n ) *
+ (pi**($n / 2)) /
+ (
+ sqrt(pi) *
+ factorial( 2 * (int($n / 2)) + 2 ) /
+ factorial( int($n / 2) + 1 ) /
+ (4**(int($n / 2) + 1)));
--- /dev/null
+if ( seek( DATA, 0, 0 ) ) { ... }
--- /dev/null
+-pt=2 -kpit=0
--- /dev/null
+return ( $r**$n ) * ( pi**( $n / 2 ) ) / ( sqrt(pi) * factorial( 2 * ( int( $n
+/ 2 ) ) + 2 ) / factorial( int( $n / 2 ) + 1 ) / ( 4**( int( $n / 2 ) + 1 ) )
+);
--- /dev/null
+-kpit=0 -kpitl='return factorial' -pt=2
../snippets20.t gnu6.gnu
../snippets20.t git25.def
../snippets20.t git25.git25
+../snippets20.t outdent.outdent2
../snippets3.t ce_wn1.ce_wn
../snippets3.t ce_wn1.def
../snippets3.t colin.colin
../snippets9.t rt98902.def
../snippets9.t rt98902.rt98902
../snippets9.t rt99961.def
-../snippets20.t outdent.outdent2
+../snippets20.t kpit.def
+../snippets20.t kpit.kpit
+../snippets20.t kpitl.def
+../snippets20.t kpitl.kpitl
#11 git25.def
#12 git25.git25
#13 outdent.outdent2
+#14 kpit.def
+#15 kpit.kpit
+#16 kpitl.def
+#17 kpitl.kpitl
# To locate test #13 you can search for its name or the string '#13'
# BEGIN SECTION 1: Parameter combinations #
###########################################
$rparams = {
- 'ce' => "-cuddled-blocks",
- 'def' => "",
- 'git25' => "-l=0",
- 'gnu' => "-gnu",
+ 'ce' => "-cuddled-blocks",
+ 'def' => "",
+ 'git25' => "-l=0",
+ 'gnu' => "-gnu",
+ 'kpit' => "-pt=2 -kpit=0",
+ 'kpitl' => <<'----------',
+-kpit=0 -kpitl='return factorial' -pt=2
+----------
'outdent2' => <<'----------',
# test -okw and -okwl
-okw -okwl='next'
'foo10' => undef,
};
+----------
+
+ 'kpit' => <<'----------',
+if ( seek( DATA, 0, 0 ) ) { ... }
+----------
+
+ 'kpitl' => <<'----------',
+return ( $r**$n ) * ( pi**( $n / 2 ) ) / ( sqrt(pi) * factorial( 2 * ( int( $n
+/ 2 ) ) + 2 ) / factorial( int( $n / 2 ) + 1 ) / ( 4**( int( $n / 2 ) + 1 ) )
+);
----------
'outdent' => <<'----------',
#13...........
},
+
+ 'kpit.def' => {
+ source => "kpit",
+ params => "def",
+ expect => <<'#14...........',
+if ( seek( DATA, 0, 0 ) ) { ... }
+#14...........
+ },
+
+ 'kpit.kpit' => {
+ source => "kpit",
+ params => "kpit",
+ expect => <<'#15...........',
+if ( seek(DATA, 0, 0) ) { ... }
+#15...........
+ },
+
+ 'kpitl.def' => {
+ source => "kpitl",
+ params => "def",
+ expect => <<'#16...........',
+return ( $r**$n ) *
+ ( pi**( $n / 2 ) ) /
+ (
+ sqrt(pi) *
+ factorial( 2 * ( int( $n / 2 ) ) + 2 ) /
+ factorial( int( $n / 2 ) + 1 ) /
+ ( 4**( int( $n / 2 ) + 1 ) ) );
+#16...........
+ },
+
+ 'kpitl.kpitl' => {
+ source => "kpitl",
+ params => "kpitl",
+ expect => <<'#17...........',
+return ( $r**$n ) *
+ (pi**($n / 2)) /
+ (
+ sqrt(pi) *
+ factorial( 2 * (int($n / 2)) + 2 ) /
+ factorial( int($n / 2) + 1 ) /
+ (4**(int($n / 2) + 1)));
+#17...........
+ },
};
my $ntests = 0 + keys %{$rtests};