From 14ca445a5c8cc7dc8eb479b81b9333d87c78f567 Mon Sep 17 00:00:00 2001 From: Steve Hancock Date: Sun, 14 Jul 2024 16:35:07 -0700 Subject: [PATCH] add -dtlc -atlc --- .perlcriticrc | 3 +- lib/Perl/Tidy.pm | 3 + lib/Perl/Tidy/Formatter.pm | 152 +++++++++++++++++++++++-------- t/snippets/atlc.in | 7 ++ t/snippets/atlc1.par | 1 + t/snippets/atlc2.par | 1 + t/snippets/dtlc.in | 7 ++ t/snippets/dtlc1.par | 1 + t/snippets/dtlc2.par | 1 + t/snippets/expect/atlc.atlc1 | 7 ++ t/snippets/expect/atlc.atlc2 | 7 ++ t/snippets/expect/atlc.def | 7 ++ t/snippets/expect/dtlc.def | 7 ++ t/snippets/expect/dtlc.dtlc1 | 7 ++ t/snippets/expect/dtlc.dtlc2 | 7 ++ t/snippets/expect/git146.def | 6 ++ t/snippets/expect/git146.git146 | 6 ++ t/snippets/git146.par | 2 +- t/snippets/packing_list.txt | 12 ++- t/snippets30.t | 157 ++++++++++++++++++++++++++++++++ 20 files changed, 360 insertions(+), 41 deletions(-) create mode 100644 t/snippets/atlc.in create mode 100644 t/snippets/atlc1.par create mode 100644 t/snippets/atlc2.par create mode 100644 t/snippets/dtlc.in create mode 100644 t/snippets/dtlc1.par create mode 100644 t/snippets/dtlc2.par create mode 100644 t/snippets/expect/atlc.atlc1 create mode 100644 t/snippets/expect/atlc.atlc2 create mode 100644 t/snippets/expect/atlc.def create mode 100644 t/snippets/expect/dtlc.def create mode 100644 t/snippets/expect/dtlc.dtlc1 create mode 100644 t/snippets/expect/dtlc.dtlc2 create mode 100644 t/snippets/expect/git146.def create mode 100644 t/snippets/expect/git146.git146 diff --git a/.perlcriticrc b/.perlcriticrc index 8fc71ccb..c922d58a 100644 --- a/.perlcriticrc +++ b/.perlcriticrc @@ -84,8 +84,9 @@ max_mccabe=180 # This policy can be very helpful for locating complex code, but sometimes # deep nests are the best option, especially in error handling and debug # coding. So a large value is used here. +# sub Formatter::count_list_elements currently needs 10, several others need 9 [ControlStructures::ProhibitDeepNests] -max_nests=9 +max_nests=10 # Agree that cascading elses are best avoided, but in reality there are a lot # of cases where they cannot be avoided. diff --git a/lib/Perl/Tidy.pm b/lib/Perl/Tidy.pm index ed4f7ede..a49ebc73 100644 --- a/lib/Perl/Tidy.pm +++ b/lib/Perl/Tidy.pm @@ -3509,6 +3509,7 @@ sub generate_options { $category = 3; # Whitespace control ######################################## $add_option->( 'add-trailing-commas', 'atc', '!' ); + $add_option->( 'add-trailing-lone-commas', 'atlc', '!' ); $add_option->( 'add-semicolons', 'asc', '!' ); $add_option->( 'add-whitespace', 'aws', '!' ); $add_option->( 'block-brace-tightness', 'bbt', '=i' ); @@ -3516,6 +3517,7 @@ sub generate_options { $add_option->( 'delete-old-whitespace', 'dws', '!' ); $add_option->( 'delete-repeated-commas', 'drc', '!' ); $add_option->( 'delete-trailing-commas', 'dtc', '!' ); + $add_option->( 'delete-trailing-lone-commas', 'dtlc', '!' ); $add_option->( 'delete-weld-interfering-commas', 'dwic', '!' ); $add_option->( 'delete-semicolons', 'dsm', '!' ); $add_option->( 'function-paren-vertical-alignment', 'fpva', '!' ); @@ -3849,6 +3851,7 @@ sub generate_options { cuddled-break-option=1 delete-old-newlines delete-repeated-commas + delete-trailing-lone-commas delete-semicolons dump-block-minimum-lines=20 dump-block-types=sub diff --git a/lib/Perl/Tidy/Formatter.pm b/lib/Perl/Tidy/Formatter.pm index e3bed0b1..a6587093 100644 --- a/lib/Perl/Tidy/Formatter.pm +++ b/lib/Perl/Tidy/Formatter.pm @@ -202,6 +202,7 @@ my ( $rOpts_add_newlines, $rOpts_add_whitespace, $rOpts_add_trailing_commas, + $rOpts_add_trailing_lone_commas, $rOpts_blank_lines_after_opening_block, $rOpts_block_brace_tightness, $rOpts_block_brace_vertical_tightness, @@ -224,6 +225,7 @@ my ( $rOpts_delete_old_whitespace, $rOpts_delete_side_comments, $rOpts_delete_trailing_commas, + $rOpts_delete_trailing_lone_commas, $rOpts_delete_weld_interfering_commas, $rOpts_extended_continuation_indentation, $rOpts_format_skipping, @@ -2533,9 +2535,10 @@ sub initialize_global_option_vars { # Make global vars for frequently used options for efficiency #------------------------------------------------------------ - $rOpts_add_newlines = $rOpts->{'add-newlines'}; - $rOpts_add_trailing_commas = $rOpts->{'add-trailing-commas'}; - $rOpts_add_whitespace = $rOpts->{'add-whitespace'}; + $rOpts_add_newlines = $rOpts->{'add-newlines'}; + $rOpts_add_trailing_commas = $rOpts->{'add-trailing-commas'}; + $rOpts_add_trailing_lone_commas = $rOpts->{'add-trailing-lone-commas'}; + $rOpts_add_whitespace = $rOpts->{'add-whitespace'}; $rOpts_blank_lines_after_opening_block = $rOpts->{'blank-lines-after-opening-block'}; $rOpts_block_brace_tightness = $rOpts->{'block-brace-tightness'}; @@ -2572,6 +2575,8 @@ sub initialize_global_option_vars { $rOpts->{'extended-continuation-indentation'}; $rOpts_delete_side_comments = $rOpts->{'delete-side-comments'}; $rOpts_delete_trailing_commas = $rOpts->{'delete-trailing-commas'}; + $rOpts_delete_trailing_lone_commas = + $rOpts->{'delete-trailing-lone-commas'}; $rOpts_delete_weld_interfering_commas = $rOpts->{'delete-weld-interfering-commas'}; $rOpts_format_skipping = $rOpts->{'format-skipping'}; @@ -11030,22 +11035,36 @@ sub respace_tokens_inner_loop { #---------------------------------------------------------- else { - # if this is a list .. - # NOTE: the final determination of what is a list is in sub - # respace_post_loop_ops. This is a close approximation. + # if this looks like a list .. my $rtype_count = $rtype_count_by_seqno->{$type_sequence}; - if ( $rtype_count - && ( $rtype_count->{','} || $rtype_count->{'=>'} ) - && !$rtype_count->{';'} - && !$rtype_count->{'f'} ) + if ( !$rtype_count + || !$rtype_count->{';'} && !$rtype_count->{'f'} ) { # if NOT preceded by a comma.. if ( $last_nonblank_code_type ne ',' ) { # insert a comma if requested - if ( $rOpts_add_trailing_commas - && %trailing_comma_rules ) + if ( + $rOpts_add_trailing_commas + && %trailing_comma_rules + + # and... + && ( + + # ... there is a comma or fat_comma + $rtype_count + && ( $rtype_count->{','} + || $rtype_count->{'=>'} ) + + # ... or exception for nested container + || ( + $rOpts_add_trailing_lone_commas + && $is_closing_type{ + $last_nonblank_code_type} + ) + ) + ) { $self->add_trailing_comma( $KK, $Kfirst, $trailing_comma_rules{$token} ); @@ -11057,8 +11076,15 @@ sub respace_tokens_inner_loop { # delete a trailing comma if requested my $deleted; - if ( $rOpts_delete_trailing_commas - && %trailing_comma_rules ) + if ( + $rOpts_delete_trailing_commas + && %trailing_comma_rules + && $rtype_count + && $rtype_count->{','} + && ( $rOpts_delete_trailing_lone_commas + || $rtype_count->{','} > 1 + || $rtype_count->{'=>'} ) + ) { $deleted = $self->delete_trailing_comma( $KK, $Kfirst, @@ -12626,38 +12652,90 @@ sub match_trailing_comma_rule { my $type_sequence = $rLL->[$KK]->[_TYPE_SEQUENCE_]; return unless ($type_sequence); my $closing_token = $rLL->[$KK]->[_TOKEN_]; - my $rtype_count = $self->[_rtype_count_by_seqno_]->{$type_sequence}; - return unless defined($rtype_count); - my $comma_count = $rtype_count->{','}; - my $fat_comma_count = $rtype_count->{'=>'}; - return unless ( $comma_count || $fat_comma_count ); my $is_permanently_broken = $self->[_ris_permanently_broken_]->{$type_sequence}; - # Note that _ris_broken_container_ also stores the line diff - # but it is not available at this early stage. my $K_opening = $self->[_K_opening_container_]->{$type_sequence}; return if ( !defined($K_opening) ); + my $iline_first = $self->[_rfirst_comma_line_index_]->{$type_sequence}; + my $iline_last = $rLL_new->[$Kp]->[_LINE_INDEX_]; + my $rtype_count = $self->[_rtype_count_by_seqno_]->{$type_sequence}; + my $comma_count = 0; + my $fat_comma_count = 0; + my $comma_count_inner = 0; - # Do not add a comma which will be deleted by - # --delete-weld-interfering commas (b1471) + if ($rtype_count) { + $comma_count = $rtype_count->{','}; + $fat_comma_count = $rtype_count->{'=>'}; + } + + # Check for cases where adding a lone comma may interfere with welding. if ( $if_add - && $rOpts_delete_weld_interfering_commas && !$comma_count && $is_closing_type{$last_nonblank_code_type} ) { - # Back up to the previous token + + # check for nesting closing containers my $Kpp = $self->K_previous_nonblank( undef, $rLL_new ); - if ( defined($Kpp) ) { - my $seqno_pp = $rLL_new->[$Kpp]->[_TYPE_SEQUENCE_]; - my $type_pp = $rLL_new->[$Kpp]->[_TYPE_]; + return if ( !defined($Kpp) ); + my $seqno_pp = $rLL_new->[$Kpp]->[_TYPE_SEQUENCE_]; + my $type_pp = $rLL_new->[$Kpp]->[_TYPE_]; + + # nesting containers have sequence numbers which differ by 1 + my $is_nesting_right = + $seqno_pp + && $is_closing_type{$type_pp} + && ( $seqno_pp == $type_sequence + 1 ); + + # Do not add a comma which will be deleted by + # --delete-weld-interfering commas (b1471) + if ( $is_nesting_right + && $rOpts_delete_weld_interfering_commas ) + { + return; + } - # The containers would have to be nesting, so - # sequence numbers must differ by 1 - return - if ( $seqno_pp - && $is_closing_type{$type_pp} - && ( $seqno_pp == $type_sequence + 1 ) ); + # Must return if no fat comma and not fully nesting + if ( !$fat_comma_count ) { + + # containers must be nesting on the right + return unless ($is_nesting_right); + + # inner container must have commas + my $rtype_count_pp = $self->[_rtype_count_by_seqno_]->{$seqno_pp}; + return unless ($rtype_count_pp); + $comma_count_inner = $rtype_count_pp->{','}; + my $fat_comma_count_inner = $rtype_count_pp->{'=>'}; + return if ( !$comma_count_inner ); + return if ( $comma_count_inner < 2 ); + + # and inner container must be multiline + $iline_first = $self->[_rfirst_comma_line_index_]->{$seqno_pp}; + my $iline_c = $rLL_new->[$Kpp]->[_LINE_INDEX_]; + return if ( !defined($iline_first) ); + return if ( $iline_c <= $iline_first ); + + # the containers must be nesting on the left + my $Ktest = $self->K_next_nonblank( $K_opening, $rLL_new ); + return unless ($Ktest); + my $seqno_test = $rLL_new->[$Ktest]->[_TYPE_SEQUENCE_]; + if ( !$seqno_test || $seqno_test != $seqno_pp ) { + return; + } + + # if outer container type is paren, must be sub call + my $token = $rLL_new->[$K_opening]->[_TOKEN_]; + if ( $token eq '(' ) { + my $Km = $self->K_previous_nonblank( $K_opening, $rLL_new ); + my $type_p = $Km ? $rLL_new->[$Km]->[_TYPE_] : 'b'; + ## see also sub count_return_values_wanted + my $is_function_call = + $type_p eq 'U' + || $type_p eq 'i' + || $type_p eq 'w' + || $type_p eq '->'; + return unless ($is_function_call); + } } } @@ -12668,8 +12746,8 @@ sub match_trailing_comma_rule { my $has_multiline_containers = $line_diff_containers > 0; # multiline definition 2: first and last commas on different lines - my $iline_first = $self->[_rfirst_comma_line_index_]->{$type_sequence}; - my $iline_last = $rLL_new->[$Kp]->[_LINE_INDEX_]; + # Note that _ris_broken_container_ also stores the line diff + # but it is not available at this early stage. my $has_multiline_commas; my $line_diff_commas = 0; if ( !defined($iline_first) ) { @@ -12713,7 +12791,7 @@ sub match_trailing_comma_rule { # 'm' matches a Multiline list #----------------------------- elsif ( $trailing_comma_style eq 'm' ) { - $match = $is_multiline && $comma_count; + $match = $is_multiline && ( $comma_count || $comma_count_inner ); } #---------------------------------- diff --git a/t/snippets/atlc.in b/t/snippets/atlc.in new file mode 100644 index 00000000..54255407 --- /dev/null +++ b/t/snippets/atlc.in @@ -0,0 +1,7 @@ +$self->make_grammar( + { + iterator => $self->_iterator, + parser => $self, + version => $self->version + } +); diff --git a/t/snippets/atlc1.par b/t/snippets/atlc1.par new file mode 100644 index 00000000..e8ee09e2 --- /dev/null +++ b/t/snippets/atlc1.par @@ -0,0 +1 @@ +-atc -wtc=m diff --git a/t/snippets/atlc2.par b/t/snippets/atlc2.par new file mode 100644 index 00000000..54274fe5 --- /dev/null +++ b/t/snippets/atlc2.par @@ -0,0 +1 @@ +-atlc -atc -wtc=m diff --git a/t/snippets/dtlc.in b/t/snippets/dtlc.in new file mode 100644 index 00000000..e2f77e2d --- /dev/null +++ b/t/snippets/dtlc.in @@ -0,0 +1,7 @@ +$self->make_grammar( + { + iterator => $self->_iterator, + parser => $self, + version => $self->version, + }, +); diff --git a/t/snippets/dtlc1.par b/t/snippets/dtlc1.par new file mode 100644 index 00000000..247a5daf --- /dev/null +++ b/t/snippets/dtlc1.par @@ -0,0 +1 @@ +-dtc -wtc=0 diff --git a/t/snippets/dtlc2.par b/t/snippets/dtlc2.par new file mode 100644 index 00000000..d6328f57 --- /dev/null +++ b/t/snippets/dtlc2.par @@ -0,0 +1 @@ +-dtc -wtc=0 -ndtlc diff --git a/t/snippets/expect/atlc.atlc1 b/t/snippets/expect/atlc.atlc1 new file mode 100644 index 00000000..c808a4b1 --- /dev/null +++ b/t/snippets/expect/atlc.atlc1 @@ -0,0 +1,7 @@ +$self->make_grammar( + { + iterator => $self->_iterator, + parser => $self, + version => $self->version, + } +); diff --git a/t/snippets/expect/atlc.atlc2 b/t/snippets/expect/atlc.atlc2 new file mode 100644 index 00000000..e2f77e2d --- /dev/null +++ b/t/snippets/expect/atlc.atlc2 @@ -0,0 +1,7 @@ +$self->make_grammar( + { + iterator => $self->_iterator, + parser => $self, + version => $self->version, + }, +); diff --git a/t/snippets/expect/atlc.def b/t/snippets/expect/atlc.def new file mode 100644 index 00000000..54255407 --- /dev/null +++ b/t/snippets/expect/atlc.def @@ -0,0 +1,7 @@ +$self->make_grammar( + { + iterator => $self->_iterator, + parser => $self, + version => $self->version + } +); diff --git a/t/snippets/expect/dtlc.def b/t/snippets/expect/dtlc.def new file mode 100644 index 00000000..e2f77e2d --- /dev/null +++ b/t/snippets/expect/dtlc.def @@ -0,0 +1,7 @@ +$self->make_grammar( + { + iterator => $self->_iterator, + parser => $self, + version => $self->version, + }, +); diff --git a/t/snippets/expect/dtlc.dtlc1 b/t/snippets/expect/dtlc.dtlc1 new file mode 100644 index 00000000..54255407 --- /dev/null +++ b/t/snippets/expect/dtlc.dtlc1 @@ -0,0 +1,7 @@ +$self->make_grammar( + { + iterator => $self->_iterator, + parser => $self, + version => $self->version + } +); diff --git a/t/snippets/expect/dtlc.dtlc2 b/t/snippets/expect/dtlc.dtlc2 new file mode 100644 index 00000000..3fb66569 --- /dev/null +++ b/t/snippets/expect/dtlc.dtlc2 @@ -0,0 +1,7 @@ +$self->make_grammar( + { + iterator => $self->_iterator, + parser => $self, + version => $self->version + }, +); diff --git a/t/snippets/expect/git146.def b/t/snippets/expect/git146.def new file mode 100644 index 00000000..8d766e41 --- /dev/null +++ b/t/snippets/expect/git146.def @@ -0,0 +1,6 @@ + my %strips = ( + 1 => [ + [ [ 1750, 150, ], [ 1850, 150, ], ], + [ [ 1950, 150, ], [ 2050, 150, ], ], + ] + ); diff --git a/t/snippets/expect/git146.git146 b/t/snippets/expect/git146.git146 new file mode 100644 index 00000000..14d767e4 --- /dev/null +++ b/t/snippets/expect/git146.git146 @@ -0,0 +1,6 @@ + my %strips = ( + 1 => [ + [ [ 1750, 150, ], [ 1850, 150, ], ], + [ [ 1950, 150, ], [ 2050, 150, ], ], + ], + ); diff --git a/t/snippets/git146.par b/t/snippets/git146.par index 117ba07c..77925116 100644 --- a/t/snippets/git146.par +++ b/t/snippets/git146.par @@ -1,4 +1,4 @@ # testing three dash parameters ----add-trailing-commas +---add-trailing-commas ---unknown-future-option ---wtc=h diff --git a/t/snippets/packing_list.txt b/t/snippets/packing_list.txt index 6e2ce47b..a16c48ec 100644 --- a/t/snippets/packing_list.txt +++ b/t/snippets/packing_list.txt @@ -442,6 +442,8 @@ ../snippets3.t format1.def ../snippets3.t given1.def ../snippets3.t gnu1.def +../snippets30.t git143.def +../snippets30.t git143.git143 ../snippets4.t gnu1.gnu ../snippets4.t gnu2.def ../snippets4.t gnu2.gnu @@ -562,5 +564,11 @@ ../snippets9.t rt98902.def ../snippets9.t rt98902.rt98902 ../snippets9.t rt99961.def -../snippets30.t git143.def -../snippets30.t git143.git143 +../snippets30.t atlc.atlc1 +../snippets30.t atlc.atlc2 +../snippets30.t atlc.def +../snippets30.t dtlc.def +../snippets30.t dtlc.dtlc1 +../snippets30.t dtlc.dtlc2 +../snippets30.t git146.def +../snippets30.t git146.git146 diff --git a/t/snippets30.t b/t/snippets30.t index fee06e9b..92a7128a 100644 --- a/t/snippets30.t +++ b/t/snippets30.t @@ -3,6 +3,14 @@ # Contents: #1 git143.def #2 git143.git143 +#3 atlc.atlc1 +#4 atlc.atlc2 +#5 atlc.def +#6 dtlc.def +#7 dtlc.dtlc1 +#8 dtlc.dtlc2 +#9 git146.def +#10 git146.git146 # To locate test #13 you can search for its name or the string '#13' @@ -20,8 +28,18 @@ BEGIN { # BEGIN SECTION 1: Parameter combinations # ########################################### $rparams = { + 'atlc1' => "-atc -wtc=m", + 'atlc2' => "-atlc -atc -wtc=m", 'def' => "", + 'dtlc1' => "-dtc -wtc=0", + 'dtlc2' => "-dtc -wtc=0 -ndtlc", 'git143' => "-atc -wtc=h", + 'git146' => <<'----------', +# testing three dash parameters +---add-trailing-commas +---unknown-future-option +---wtc=h +---------- }; ############################ @@ -29,6 +47,26 @@ BEGIN { ############################ $rsources = { + 'atlc' => <<'----------', +$self->make_grammar( + { + iterator => $self->_iterator, + parser => $self, + version => $self->version + } +); +---------- + + 'dtlc' => <<'----------', +$self->make_grammar( + { + iterator => $self->_iterator, + parser => $self, + version => $self->version, + }, +); +---------- + 'git143' => <<'----------', # include '=>' in comma count to allow adding trailing comma here my %strips = ( @@ -38,6 +76,15 @@ BEGIN { ] ); ---------- + + 'git146' => <<'----------', + my %strips = ( + 1 => [ + [ [ 1750, 150, ], [ 1850, 150, ], ], + [ [ 1950, 150, ], [ 2050, 150, ], ], + ] + ); +---------- }; #################################### @@ -72,6 +119,116 @@ BEGIN { ); #2........... }, + + 'atlc.atlc1' => { + source => "atlc", + params => "atlc1", + expect => <<'#3...........', +$self->make_grammar( + { + iterator => $self->_iterator, + parser => $self, + version => $self->version, + } +); +#3........... + }, + + 'atlc.atlc2' => { + source => "atlc", + params => "atlc2", + expect => <<'#4...........', +$self->make_grammar( + { + iterator => $self->_iterator, + parser => $self, + version => $self->version, + }, +); +#4........... + }, + + 'atlc.def' => { + source => "atlc", + params => "def", + expect => <<'#5...........', +$self->make_grammar( + { + iterator => $self->_iterator, + parser => $self, + version => $self->version + } +); +#5........... + }, + + 'dtlc.def' => { + source => "dtlc", + params => "def", + expect => <<'#6...........', +$self->make_grammar( + { + iterator => $self->_iterator, + parser => $self, + version => $self->version, + }, +); +#6........... + }, + + 'dtlc.dtlc1' => { + source => "dtlc", + params => "dtlc1", + expect => <<'#7...........', +$self->make_grammar( + { + iterator => $self->_iterator, + parser => $self, + version => $self->version + } +); +#7........... + }, + + 'dtlc.dtlc2' => { + source => "dtlc", + params => "dtlc2", + expect => <<'#8...........', +$self->make_grammar( + { + iterator => $self->_iterator, + parser => $self, + version => $self->version + }, +); +#8........... + }, + + 'git146.def' => { + source => "git146", + params => "def", + expect => <<'#9...........', + my %strips = ( + 1 => [ + [ [ 1750, 150, ], [ 1850, 150, ], ], + [ [ 1950, 150, ], [ 2050, 150, ], ], + ] + ); +#9........... + }, + + 'git146.git146' => { + source => "git146", + params => "git146", + expect => <<'#10...........', + my %strips = ( + 1 => [ + [ [ 1750, 150, ], [ 1850, 150, ], ], + [ [ 1950, 150, ], [ 2050, 150, ], ], + ], + ); +#10........... + }, }; my $ntests = 0 + keys %{$rtests}; -- 2.39.5