1 #####################################################################
3 # the Perl::Tidy::FileWriter class writes the output file
5 #####################################################################
7 package Perl::Tidy::FileWriter;
10 our $VERSION = '20220613';
12 use constant DEVEL_MODE => 0;
13 use constant EMPTY_STRING => q{};
17 # Catch any undefined sub calls so that we are sure to get
18 # some diagnostic information. This sub should never be called
19 # except for a programming error.
21 return if ( $AUTOLOAD =~ /\bDESTROY$/ );
22 my ( $pkg, $fname, $lno ) = caller();
23 my $my_package = __PACKAGE__;
25 ======================================================================
26 Error detected in package '$my_package', version $VERSION
27 Received unexpected AUTOLOAD call for sub '$AUTOLOAD'
28 Called from package: '$pkg'
29 Called from File '$fname' at line '$lno'
30 This error is probably due to a recent programming change
31 ======================================================================
38 # required to avoid call to AUTOLOAD in some versions of perl
41 my $input_stream_name = EMPTY_STRING;
43 # Maximum number of little messages; probably need not be changed.
44 use constant MAX_NAG_MESSAGES => 6;
48 # Array index names for variables.
49 # Do not combine with other BEGIN blocks (c101).
52 _line_sink_object_ => $i++,
53 _logger_object_ => $i++,
55 _output_line_number_ => $i++,
56 _consecutive_blank_lines_ => $i++,
57 _consecutive_nonblank_lines_ => $i++,
58 _consecutive_new_blank_lines_ => $i++,
59 _first_line_length_error_ => $i++,
60 _max_line_length_error_ => $i++,
61 _last_line_length_error_ => $i++,
62 _first_line_length_error_at_ => $i++,
63 _max_line_length_error_at_ => $i++,
64 _last_line_length_error_at_ => $i++,
65 _line_length_error_count_ => $i++,
66 _max_output_line_length_ => $i++,
67 _max_output_line_length_at_ => $i++,
68 _rK_checklist_ => $i++,
69 _K_arrival_order_matches_ => $i++,
70 _K_sequence_error_msg_ => $i++,
71 _K_last_arrival_ => $i++,
77 Perl::Tidy::Die($msg);
84 # This routine is called for errors that really should not occur
85 # except if there has been a bug introduced by a recent program change.
86 # Please add comments at calls to Fault to explain why the call
87 # should not occur, and where to look to fix it.
88 my ( $package0, $filename0, $line0, $subroutine0 ) = caller(0);
89 my ( $package1, $filename1, $line1, $subroutine1 ) = caller(1);
90 my ( $package2, $filename2, $line2, $subroutine2 ) = caller(2);
93 ==============================================================================
94 While operating on input stream with name: '$input_stream_name'
95 A fault was detected at line $line0 of sub '$subroutine1'
97 which was called from line $line1 of sub '$subroutine2'
99 This is probably an error introduced by a recent programming change.
100 Perl::Tidy::FileWriter.pm reports VERSION='$VERSION'.
101 ==============================================================================
104 # This return is to keep Perl-Critic from complaining.
109 my ( $self, $msg ) = @_;
110 my $logger_object = $self->[_logger_object_];
111 if ($logger_object) { $logger_object->warning($msg); }
115 sub write_logfile_entry {
116 my ( $self, $msg ) = @_;
117 my $logger_object = $self->[_logger_object_];
118 if ($logger_object) {
119 $logger_object->write_logfile_entry($msg);
125 my ( $class, $line_sink_object, $rOpts, $logger_object ) = @_;
128 $self->[_line_sink_object_] = $line_sink_object;
129 $self->[_logger_object_] = $logger_object;
130 $self->[_rOpts_] = $rOpts;
131 $self->[_output_line_number_] = 1;
132 $self->[_consecutive_blank_lines_] = 0;
133 $self->[_consecutive_nonblank_lines_] = 0;
134 $self->[_consecutive_new_blank_lines_] = 0;
135 $self->[_first_line_length_error_] = 0;
136 $self->[_max_line_length_error_] = 0;
137 $self->[_last_line_length_error_] = 0;
138 $self->[_first_line_length_error_at_] = 0;
139 $self->[_max_line_length_error_at_] = 0;
140 $self->[_last_line_length_error_at_] = 0;
141 $self->[_line_length_error_count_] = 0;
142 $self->[_max_output_line_length_] = 0;
143 $self->[_max_output_line_length_at_] = 0;
144 $self->[_rK_checklist_] = [];
145 $self->[_K_arrival_order_matches_] = 0;
146 $self->[_K_sequence_error_msg_] = EMPTY_STRING;
147 $self->[_K_last_arrival_] = -1;
149 # save input stream name for local error messages
150 $input_stream_name = EMPTY_STRING;
151 if ($logger_object) {
152 $input_stream_name = $logger_object->get_input_stream_name();
159 sub setup_convergence_test {
160 my ( $self, $rlist ) = @_;
163 # We are going to destroy the list, so make a copy
164 # and put in reverse order so we can pop values
165 my @list = @{$rlist};
166 if ( $list[0] < $list[-1] ) {
167 @list = reverse @list;
169 $self->[_rK_checklist_] = \@list;
171 $self->[_K_arrival_order_matches_] = 1;
172 $self->[_K_sequence_error_msg_] = EMPTY_STRING;
173 $self->[_K_last_arrival_] = -1;
177 sub get_convergence_check {
179 my $rlist = $self->[_rK_checklist_];
181 # converged if all K arrived and in correct order
182 return $self->[_K_arrival_order_matches_] && !@{$rlist};
185 sub get_K_sequence_error_msg {
187 return $self->[_K_sequence_error_msg_];
190 sub get_output_line_number {
191 return $_[0]->[_output_line_number_];
194 sub decrement_output_line_number {
195 $_[0]->[_output_line_number_]--;
199 sub get_consecutive_nonblank_lines {
200 return $_[0]->[_consecutive_nonblank_lines_];
203 sub get_consecutive_blank_lines {
204 return $_[0]->[_consecutive_blank_lines_];
207 sub reset_consecutive_blank_lines {
208 $_[0]->[_consecutive_blank_lines_] = 0;
212 sub want_blank_line {
214 unless ( $self->[_consecutive_blank_lines_] ) {
215 $self->write_blank_code_line();
220 sub require_blank_code_lines {
222 # write out the requested number of blanks regardless of the value of -mbl
223 # unless -mbl=0. This allows extra blank lines to be written for subs and
224 # packages even with the default -mbl=1
225 my ( $self, $count ) = @_;
226 my $need = $count - $self->[_consecutive_blank_lines_];
227 my $rOpts = $self->[_rOpts_];
228 my $forced = $rOpts->{'maximum-consecutive-blank-lines'} > 0;
229 foreach my $i ( 0 .. $need - 1 ) {
230 $self->write_blank_code_line($forced);
235 sub write_blank_code_line {
238 my $rOpts = $self->[_rOpts_];
241 && $self->[_consecutive_blank_lines_] >=
242 $rOpts->{'maximum-consecutive-blank-lines'} );
244 $self->[_consecutive_nonblank_lines_] = 0;
246 # Balance old blanks against new (forced) blanks instead of writing them.
247 # This fixes case b1073.
248 if ( !$forced && $self->[_consecutive_new_blank_lines_] > 0 ) {
249 $self->[_consecutive_new_blank_lines_]--;
253 $self->write_line("\n");
254 $self->[_consecutive_blank_lines_]++;
255 $self->[_consecutive_new_blank_lines_]++ if ($forced);
260 use constant MAX_PRINTED_CHARS => 80;
262 sub write_code_line {
263 my ( $self, $str, $K ) = @_;
265 $self->[_consecutive_blank_lines_] = 0;
266 $self->[_consecutive_new_blank_lines_] = 0;
267 $self->[_consecutive_nonblank_lines_]++;
268 $self->write_line($str);
270 #----------------------------
271 # Convergence and error check
272 #----------------------------
275 # Convergence check: we are checking if all defined K values arrive in
276 # the order which was defined by the caller. Quit checking if any
277 # unexpected K value arrives.
278 if ( $self->[_K_arrival_order_matches_] ) {
279 my $Kt = pop @{ $self->[_rK_checklist_] };
280 if ( !defined($Kt) || $Kt != $K ) {
281 $self->[_K_arrival_order_matches_] = 0;
285 # Check for out-of-order arrivals of index K. The K values are the
286 # token indexes of the last token of code lines, and they should come
287 # out in increasing order. Otherwise something is seriously wrong.
288 # Most likely a recent programming change to VerticalAligner.pm has
289 # caused lines to go out in the wrong order. This could happen if
290 # either the cache or buffer that it uses are emptied in the wrong
292 if ( !$self->[_K_sequence_error_msg_] ) {
293 my $K_prev = $self->[_K_last_arrival_];
294 if ( $K < $K_prev ) {
296 if ( length($str) > MAX_PRINTED_CHARS ) {
297 $str = substr( $str, 0, MAX_PRINTED_CHARS ) . "...";
301 While operating on input stream with name: '$input_stream_name'
302 Lines have arrived out of order in sub 'write_code_line'
303 as detected by token index K=$K arriving after index K=$K_prev in the following line:
305 This is probably due to a recent programming change and needs to be fixed.
308 if (DEVEL_MODE) { Fault($msg) }
310 $self->warning($msg);
312 # Only issue this warning once
313 $self->[_K_sequence_error_msg_] = $msg;
317 $self->[_K_last_arrival_] = $K;
323 my ( $self, $str ) = @_;
325 $self->[_line_sink_object_]->write_line($str);
327 if ( chomp $str ) { $self->[_output_line_number_]++; }
329 # This calculation of excess line length ignores any internal tabs
330 my $rOpts = $self->[_rOpts_];
331 my $len_str = length($str);
332 my $exceed = $len_str - $rOpts->{'maximum-line-length'};
333 if ( $str && substr( $str, 0, 1 ) eq "\t" && $str =~ /^\t+/g ) {
334 $exceed += pos($str) * $rOpts->{'indent-columns'};
337 # Note that we just incremented output line number to future value
338 # so we must subtract 1 for current line number
339 if ( $len_str > $self->[_max_output_line_length_] ) {
340 $self->[_max_output_line_length_] = $len_str;
341 $self->[_max_output_line_length_at_] =
342 $self->[_output_line_number_] - 1;
346 my $output_line_number = $self->[_output_line_number_];
347 $self->[_last_line_length_error_] = $exceed;
348 $self->[_last_line_length_error_at_] = $output_line_number - 1;
349 if ( $self->[_line_length_error_count_] == 0 ) {
350 $self->[_first_line_length_error_] = $exceed;
351 $self->[_first_line_length_error_at_] = $output_line_number - 1;
354 if ( $self->[_last_line_length_error_] >
355 $self->[_max_line_length_error_] )
357 $self->[_max_line_length_error_] = $exceed;
358 $self->[_max_line_length_error_at_] = $output_line_number - 1;
361 if ( $self->[_line_length_error_count_] < MAX_NAG_MESSAGES ) {
362 $self->write_logfile_entry(
363 "Line length exceeded by $exceed characters\n");
365 $self->[_line_length_error_count_]++;
370 sub report_line_length_errors {
372 my $rOpts = $self->[_rOpts_];
373 my $line_length_error_count = $self->[_line_length_error_count_];
374 if ( $line_length_error_count == 0 ) {
375 $self->write_logfile_entry(
376 "No lines exceeded $rOpts->{'maximum-line-length'} characters\n");
377 my $max_output_line_length = $self->[_max_output_line_length_];
378 my $max_output_line_length_at = $self->[_max_output_line_length_at_];
379 $self->write_logfile_entry(
380 " Maximum output line length was $max_output_line_length at line $max_output_line_length_at\n"
386 my $word = ( $line_length_error_count > 1 ) ? "s" : EMPTY_STRING;
387 $self->write_logfile_entry(
388 "$line_length_error_count output line$word exceeded $rOpts->{'maximum-line-length'} characters:\n"
391 $word = ( $line_length_error_count > 1 ) ? "First" : EMPTY_STRING;
392 my $first_line_length_error = $self->[_first_line_length_error_];
393 my $first_line_length_error_at = $self->[_first_line_length_error_at_];
394 $self->write_logfile_entry(
395 " $word at line $first_line_length_error_at by $first_line_length_error characters\n"
398 if ( $line_length_error_count > 1 ) {
399 my $max_line_length_error = $self->[_max_line_length_error_];
400 my $max_line_length_error_at = $self->[_max_line_length_error_at_];
401 my $last_line_length_error = $self->[_last_line_length_error_];
402 my $last_line_length_error_at =
403 $self->[_last_line_length_error_at_];
404 $self->write_logfile_entry(
405 " Maximum at line $max_line_length_error_at by $max_line_length_error characters\n"
407 $self->write_logfile_entry(
408 " Last at line $last_line_length_error_at by $last_line_length_error characters\n"