7
8
use Padre::Role::Task ();
8
9
use Padre::Wx::Role::View ();
9
10
use Padre::Wx::Role::Main ();
11
12
use Padre::Wx::Icon ();
12
13
use Padre::Wx::TreeCtrl ();
14
use Padre::Wx::HtmlWindow ();
15
our $VERSION = '0.76';
17
our $VERSION = '0.90';
18
20
Padre::Wx::Role::View
19
21
Padre::Wx::Role::Main
23
25
# perldiag error message classification
73
74
my $panel = shift || $main->bottom;
75
my $self = $class->SUPER::new($panel);
75
77
# Create the underlying object
76
my $self = $class->SUPER::new(
78
$self->{tree} = Padre::Wx::TreeCtrl->new(
79
81
Wx::wxDefaultPosition,
81
83
Wx::wxTR_SINGLE | Wx::wxTR_FULL_ROW_HIGHLIGHT | Wx::wxTR_HAS_BUTTONS
86
$self->{help} = Padre::Wx::HtmlWindow->new(
89
Wx::wxDefaultPosition,
95
my $sizer = Wx::BoxSizer->new(Wx::wxHORIZONTAL);
96
$sizer->Add( $self->{tree}, 3, Wx::wxALL | Wx::wxEXPAND, 2 );
97
$sizer->Add( $self->{help}, 2, Wx::wxALL | Wx::wxEXPAND, 2 );
98
$self->SetSizer($sizer);
84
100
# Additional properties
86
$self->{document} = '';
102
$self->{length} = -1;
89
104
# Prepare the available images
90
105
my $images = Wx::ImageList->new( 16, 16 );
110
$self->AssignImageList($images);
125
$self->{tree}->AssignImageList($images);
112
127
Wx::Event::EVT_TREE_ITEM_ACTIVATED(
115
131
$_[0]->on_tree_item_activated( $_[1] );
135
Wx::Event::EVT_TREE_SEL_CHANGED(
139
$_[0]->on_tree_item_selection_changed( $_[1] );
145
if (Padre::Feature::STYLE_GUI) {
124
156
######################################################################
125
157
# Padre::Wx::Role::View Methods
136
shift->main->show_syntax(0);
168
$_[0]->main->show_syntaxcheck(0);
143
#####################################################################
147
172
my $self = shift;
148
$self->running and return;
149
TRACE('Starting the syntax checker') if DEBUG;
151
174
# Add the margins for the syntax markers
152
175
foreach my $editor ( $self->main->editors ) {
157
180
# Set margin 1 16 px wide
158
181
$editor->SetMarginWidth( 1, 16 );
161
if ( Params::Util::_INSTANCE( $self->{timer}, 'Wx::Timer' ) ) {
162
$self->on_timer( undef, 1 );
164
TRACE('Creating new timer') if DEBUG;
165
$self->{timer} = Wx::Timer->new(
167
Padre::Wx::ID_TIMER_SYNTAX
169
Wx::Event::EVT_TIMER(
171
Padre::Wx::ID_TIMER_SYNTAX,
173
$self->on_timer( $_[1], $_[2] );
177
$self->{timer}->Start( 1000, 0 );
183
186
my $self = shift;
184
$self->running or return;
185
TRACE('Stopping the syntax checker') if DEBUG;
188
if ( Params::Util::_INSTANCE( $self->{timer}, 'Wx::Timer' ) ) {
189
$self->{timer}->Stop;
192
# Remove the editor margin
193
foreach my $editor ( $self->main->editors ) {
187
my $main = $self->main;
188
my $lock = $main->lock('UPDATE');
190
# Clear out any state and tasks
194
# Remove the editor margins
195
foreach my $editor ( $main->editors ) {
194
196
$editor->SetMarginWidth( 1, 0 );
197
# Clear out the existing data
204
!!( $_[0]->{timer} and $_[0]->{timer}->IsRunning );
211
206
#####################################################################
209
sub on_tree_item_selection_changed {
212
my $item = $event->GetItem or return;
213
my $issue = $self->{tree}->GetPlData($item);
215
if ( $issue and $issue->{diagnostics} ) {
216
my $diag = $issue->{diagnostics};
217
$self->_update_help_page($diag);
219
$self->_update_help_page;
214
223
sub on_tree_item_activated {
215
my ( $self, $event ) = @_;
216
my $item = $event->GetItem or return;
217
my $error = $self->GetPlData($item) or return;
218
my $editor = $self->current->editor or return;
219
my $line = $error->{line};
226
my $item = $event->GetItem or return;
227
my $issue = $self->{tree}->GetPlData($item) or return;
228
my $editor = $self->current->editor or return;
229
my $line = $issue->{line};
222
if not defined($line)
224
or $editor->GetLineCount < $line;
231
# Does it point to somewhere valid?
232
return unless defined $line;
233
return if $line !~ /^\d+$/o;
234
return if $editor->GetLineCount < $line;
226
236
# Select the problem after the event has finished
227
237
Wx::Event::EVT_IDLE(
270
273
# Remove all items from the tool
271
$self->DeleteAllItems;
274
$self->{tree}->DeleteAllItems;
276
# Clear the help page
277
$self->_update_help_page;
282
# Pick up colouring from the current editor style
285
my $config = $self->config;
287
# Load the editor style
288
require Padre::Wx::Editor;
289
my $data = Padre::Wx::Editor::data( $config->editor_style ) or return;
291
# Find the colours we need
292
my $foreground = $data->{padre}->{colors}->{PADRE_BLACK}->{foreground};
293
my $background = $data->{padre}->{background};
295
# Apply them to the widgets
296
if ( defined $foreground and defined $background ) {
297
$foreground = Padre::Wx::color($foreground);
298
$background = Padre::Wx::color($background);
300
$self->{tree}->SetForegroundColour($foreground);
301
$self->{tree}->SetBackgroundColour($background);
303
# $self->{search}->SetForegroundColour($foreground);
304
# $self->{search}->SetBackgroundColour($background);
310
# Nothing to implement here
278
# Nothing to implement here
283
316
my $self = shift;
284
my $document = $self->current->document or return;
286
# allows us to check when an empty or unsaved document is open
287
my $filename = defined( $document->filename ) ? $document->filename : '';
289
my $length = $document->text_length;
291
if ( $filename eq $self->{document} ) {
293
# Shortcut if nothing has changed.
294
# NOTE: Given the speed at which the timer fires a cheap
295
# length check is better than an expensive MD5 check.
296
return if ( $length eq $self->{length} );
299
$self->{document} = $filename;
300
$self->{length} = $length;
318
# Abort any in-flight checks
321
# Do we have a document with something in it?
322
my $document = $self->current->document;
323
unless ( $document and not $document->is_unused ) {
328
# Is there a syntax check task for this document type
329
my $task = $document->task_syntax;
302
335
# Fire the background task discarding old results
304
336
$self->task_request(
305
task => $document->task_syntax,
306
338
document => $document,
341
# Clear out the syntax check window, leaving the margin as is
342
$self->{tree}->DeleteAllItems;
343
$self->_update_help_page;
310
348
sub task_finish {
323
361
my $filename = $current->filename;
324
362
my $lock = $self->main->lock('UPDATE');
364
# Clear all indicators
365
$editor->StartStyling( 0, Wx::wxSTC_INDICS_MASK );
366
$editor->SetStyling( $editor->GetTextLength - 1, 0 );
368
# NOTE: Recolor the document to make sure we do not accidentally
369
# remove syntax highlighting while syntax checking
370
$document->colourize;
326
372
# Flush old results
329
my $root = $self->AddRoot('Root');
375
my $root = $self->{tree}->AddRoot('Root');
331
377
# If there are no errors clear the synax checker pane
332
378
unless ( Params::Util::_ARRAY($model) ) {
339
385
$project_dir = quotemeta $project_dir;
340
386
$filename =~ s/^$project_dir[\\\/]?//;
388
$self->{tree}->SetItemText(
344
390
sprintf( Wx::gettext('No errors or warnings found in %s.'), $filename )
347
$self->SetItemText( $root, Wx::gettext('No errors or warnings found.') );
393
$self->{tree}->SetItemText( $root, Wx::gettext('No errors or warnings found.') );
349
$self->SetItemImage( $root, $self->{images}->{ok} );
395
$self->{tree}->SetItemImage( $root, $self->{images}->{ok} );
399
$self->{tree}->SetItemText(
355
401
defined $filename
356
402
? sprintf( Wx::gettext('Found %d issue(s) in %s'), scalar @$model, $filename )
357
403
: sprintf( Wx::gettext('Found %d issue(s)'), scalar @$model )
359
$self->SetItemImage( $root, $self->{images}->{root} );
405
$self->{tree}->SetItemImage( $root, $self->{images}->{root} );
363
409
foreach my $issue ( sort { $a->{line} <=> $b->{line} } @$model ) {
365
if ( not exists $issue->{type} ) {
366
require Data::Dumper;
367
TRACE( "Cannot handle issue:\n" . Data::Dumper::Dumper($issue) ) if DEBUG;
371
my $line = $issue->{line} - 1;
372
my $type = $issue->{type};
373
$editor->MarkerAdd( $line, $MESSAGE{$type}{marker} );
375
my $item = $self->AppendItem(
411
my $line = $issue->{line} - 1;
412
my $type = exists $issue->{type} ? $issue->{type} : 'F';
413
my $marker = $MESSAGE{$type}{marker};
414
my $is_warning = $marker == Padre::Wx::MarkWarn();
415
$editor->MarkerAdd( $line, $marker );
417
# Underline the syntax warning/error line with an orange or red squiggle indicator
418
my $start = $editor->PositionFromLine($line);
419
my $indent = $editor->GetLineIndentPosition($line);
420
my $end = $editor->GetLineEndPosition($line);
422
# Change only the indicators
423
$editor->StartStyling( $indent, Wx::wxSTC_INDICS_MASK );
424
$editor->SetStyling( $end - $indent, $is_warning ? Wx::wxSTC_INDIC1_MASK : Wx::wxSTC_INDIC2_MASK );
426
my $item = $self->{tree}->AppendItem(
378
429
Wx::gettext('Line %d: (%s) %s'),
380
431
$MESSAGE{$type}{label},
381
432
$issue->{message}
383
$MESSAGE{$type}{marker} == Padre::Wx::MarkWarn() ? $self->{images}{warning} : $self->{images}{error}
434
$is_warning ? $self->{images}{warning} : $self->{images}{error}
385
$self->SetPlData( $item, $issue );
387
if ( defined $issue->{diagnostics} ) {
388
my @diags = split /\n/, $issue->{diagnostics};
389
for my $diag (@diags) {
390
$self->AppendItem( $item, $diag, $self->{images}{diagnostics} );
436
$self->{tree}->SetPlData( $item, $issue );
439
$self->{tree}->Expand($root);
440
$self->{tree}->EnsureVisible($root);
445
# Updates the help page. It shows the text if it is defined otherwise clears and hides it
446
sub _update_help_page {
450
# load the escaped HTML string into the shown page otherwise hide
451
# if the text is undefined
452
my $help = $self->{help};
453
if ( defined $text ) {
455
$text = CGI::escapeHTML($text);
456
$text =~ s/\n/<br>/g;
457
my $WARN_TEXT = $MESSAGE{'W'}{label};
458
if ( $text =~ /^\((W\s+(\w+)|D|S|F|P|X|A)\)/ ) {
459
my ( $category, $warning_category ) = ( $1, $2 );
460
my $category_label = ( $category =~ /^W/ ) ? $MESSAGE{'W'}{label} : $MESSAGE{$1}{label};
462
defined($warning_category)
463
? "<code>no warnings '$warning_category'; # disable</code><br>"
464
. "<code>use warnings '$warning_category'; # enable</code><br><br>"
466
$text =~ s{^\((W\s+(\w+)|D|S|F|P|X|A)\)}{<h3>$category_label</h3>$notes};
468
$help->SetPage($text);
395
$self->Expand($root);
396
$self->EnsureVisible($root);
475
# Sticky note light-yellow background
476
$self->{help}->SetBackgroundColour( Wx::Colour->new( 0xFD, 0xFC, 0xBB ) );
478
# Relayout to actually hide/show the help page
401
482
# Selects the problemistic line :)
416
497
my $current_line = $editor->LineFromPosition( $editor->GetCurrentPos );
418
499
# Start with the first child
419
my $root = $self->GetRootItem;
420
my ( $child, $cookie ) = $self->GetFirstChild($root);
500
my $root = $self->{tree}->GetRootItem;
501
my ( $child, $cookie ) = $self->{tree}->GetFirstChild($root);
421
502
my $first_line = undef;
422
503
while ($cookie) {
424
505
# Get the line and check that it is a valid line number
425
my $issue = $self->GetPlData($child) or return;
506
my $issue = $self->{tree}->GetPlData($child) or return;
426
507
my $line = $issue->{line};
428
509
if ( not defined($line)
429
510
or ( $line !~ /^\d+$/o )
430
511
or ( $line > $editor->GetLineCount ) )
432
( $child, $cookie ) = $self->GetNextChild( $root, $cookie );
513
( $child, $cookie ) = $self->{tree}->GetNextChild( $root, $cookie );
455
536
# Get the next child if there is one
456
( $child, $cookie ) = $self->GetNextChild( $root, $cookie );
537
( $child, $cookie ) = $self->{tree}->GetNextChild( $root, $cookie );
459
540
# The next problem is simply the first (wrap around)