| | 1 | package Padre::Wx::Dialog::FindInFiles; |
| | 2 | |
| | 3 | use 5.008; |
| | 4 | use strict; |
| | 5 | use warnings; |
| | 6 | use threads; |
| | 7 | use threads::shared; |
| | 8 | use Padre::DB (); |
| | 9 | use Padre::Wx (); |
| | 10 | use Padre::Wx::History::ComboBox (); |
| | 11 | |
| | 12 | our $VERSION = '0.40'; |
| | 13 | our @ISA = qw{ |
| | 14 | Padre::Wx::Role::MainChild |
| | 15 | Wx::Dialog |
| | 16 | }; |
| | 17 | |
| | 18 | my $_ack_loaded = 0; |
| | 19 | |
| | 20 | =pod |
| | 21 | |
| | 22 | =head2 new |
| | 23 | |
| | 24 | my $find_in_files = Padre::Wx::Dialog::FindInFiles->new($main); |
| | 25 | |
| | 26 | Create and return a C<Padre::Wx::Dialog::FindInFiles> search widget. |
| | 27 | |
| | 28 | =cut |
| | 29 | |
| | 30 | sub new { |
| | 31 | my $class = shift; |
| | 32 | my $main = shift or die("Did not pass parent to dialog constructor"); |
| | 33 | |
| | 34 | my $self = $class->SUPER::new( |
| | 35 | $main, |
| | 36 | -1, |
| | 37 | Wx::gettext('Find in Files'), |
| | 38 | Wx::wxDefaultPosition, |
| | 39 | Wx::wxDefaultSize, |
| | 40 | Wx::wxCAPTION | Wx::wxCLOSE_BOX | Wx::wxSYSTEM_MENU | Wx::wxRESIZE_BORDER |
| | 41 | ); |
| | 42 | |
| | 43 | $self->{ack_opts} = {}; |
| | 44 | $self->{ack_iter} = undef; |
| | 45 | $self->{ack_stats} = {}; |
| | 46 | $self->{ack_done_event} = Wx::NewEventType; |
| | 47 | $self->{_panel_index} = 9999999; |
| | 48 | share($self->{ack_done_event}); |
| | 49 | |
| | 50 | $self->{_ack_term} = Padre::Wx::History::ComboBox->new( |
| | 51 | $self, |
| | 52 | -1, |
| | 53 | '', |
| | 54 | Wx::wxDefaultPosition, |
| | 55 | Wx::wxDefaultSize, |
| | 56 | 'search' |
| | 57 | ); |
| | 58 | |
| | 59 | $self->{_ack_dir} = Padre::Wx::History::ComboBox->new( |
| | 60 | $self, |
| | 61 | -1, |
| | 62 | '', |
| | 63 | Wx::wxDefaultPosition, |
| | 64 | Wx::wxDefaultSize, |
| | 65 | 'find in' |
| | 66 | ); |
| | 67 | |
| | 68 | $self->{_file_types} = Padre::Wx::History::ComboBox->new( |
| | 69 | $self, |
| | 70 | -1, |
| | 71 | '', |
| | 72 | Wx::wxDefaultPosition, |
| | 73 | Wx::wxDefaultSize, |
| | 74 | 'find type' |
| | 75 | ); |
| | 76 | |
| | 77 | $self->{_find} = Wx::Button->new( |
| | 78 | $self, |
| | 79 | Wx::wxID_FIND, |
| | 80 | Wx::gettext("&Find") |
| | 81 | ); |
| | 82 | Wx::Event::EVT_BUTTON( |
| | 83 | $self, |
| | 84 | $self->{_find}, |
| | 85 | sub { |
| | 86 | $_[0]->find_clicked; |
| | 87 | } |
| | 88 | ); |
| | 89 | $self->{_find}->SetDefault; |
| | 90 | |
| | 91 | $self->{_pick_dir} = Wx::Button->new( |
| | 92 | $self, |
| | 93 | Wx::wxID_ANY, |
| | 94 | Wx::gettext('...'), |
| | 95 | Wx::wxDefaultPosition, |
| | 96 | Wx::wxDefaultSize, |
| | 97 | Wx::wxBU_EXACTFIT |
| | 98 | ); |
| | 99 | Wx::Event::EVT_BUTTON( |
| | 100 | $self, |
| | 101 | $self->{_pick_dir}, |
| | 102 | sub { |
| | 103 | $_[0]->on_pick_dir; |
| | 104 | } |
| | 105 | ); |
| | 106 | |
| | 107 | $self->{_cancel} = Wx::Button->new( |
| | 108 | $self, |
| | 109 | Wx::wxID_CANCEL, |
| | 110 | Wx::gettext("&Cancel"), |
| | 111 | ); |
| | 112 | Wx::Event::EVT_BUTTON( |
| | 113 | $self, |
| | 114 | $self->{_cancel}, |
| | 115 | sub { |
| | 116 | $_[0]->cancel; |
| | 117 | } |
| | 118 | ); |
| | 119 | |
| | 120 | $self->{_case_insensitive} = Wx::CheckBox->new( |
| | 121 | $self, |
| | 122 | -1, |
| | 123 | Wx::gettext('Case &Insensitive'), |
| | 124 | ); |
| | 125 | Wx::Event::EVT_CHECKBOX( |
| | 126 | $self, |
| | 127 | $self->{_case_insensitive}, |
| | 128 | sub { |
| | 129 | $_[0]->{_case_insensitive}->SetFocus; |
| | 130 | } |
| | 131 | ); |
| | 132 | |
| | 133 | $self->{_ignore_hidden_subdirs} = Wx::CheckBox->new( |
| | 134 | $self, |
| | 135 | -1, |
| | 136 | Wx::gettext('I&gnore hidden Subdirectories'), |
| | 137 | ); |
| | 138 | Wx::Event::EVT_CHECKBOX( |
| | 139 | $self, |
| | 140 | $self->{_ignore_hidden_subdirs}, |
| | 141 | sub { |
| | 142 | $_[0]->{_ignore_hidden_subdirs}->SetFocus; |
| | 143 | } |
| | 144 | ); |
| | 145 | |
| | 146 | # Setting up the grid containing the search criteria |
| | 147 | my $find_grid = Wx::FlexGridSizer->new(3, 2, 5, 5); |
| | 148 | $find_grid->AddGrowableCol(1); |
| | 149 | $find_grid->Add( |
| | 150 | Wx::StaticText->new( |
| | 151 | $self, |
| | 152 | Wx::wxID_STATIC, |
| | 153 | Wx::gettext('Term:') |
| | 154 | ), |
| | 155 | 0, |
| | 156 | Wx::wxALIGN_LEFT | Wx::wxALIGN_CENTER_VERTICAL, |
| | 157 | 0 |
| | 158 | ); |
| | 159 | $find_grid->Add( |
| | 160 | $self->{_ack_term}, |
| | 161 | 1, |
| | 162 | Wx::wxEXPAND, |
| | 163 | 0 |
| | 164 | ); |
| | 165 | $find_grid->Add( |
| | 166 | Wx::StaticText->new( |
| | 167 | $self, |
| | 168 | Wx::wxID_STATIC, |
| | 169 | Wx::gettext('Dir:') |
| | 170 | ), |
| | 171 | 0, |
| | 172 | Wx::wxALIGN_LEFT | Wx::wxALIGN_CENTER_VERTICAL, |
| | 173 | 0 |
| | 174 | ); |
| | 175 | # Setting up a sizer containing the directory picker... |
| | 176 | my $dir_sizer = Wx::BoxSizer->new( |
| | 177 | Wx::wxHORIZONTAL |
| | 178 | ); |
| | 179 | $dir_sizer->Add( |
| | 180 | $self->{_ack_dir}, |
| | 181 | 1, |
| | 182 | Wx::wxEXPAND, |
| | 183 | 0 |
| | 184 | ); |
| | 185 | $dir_sizer->Add( |
| | 186 | $self->{_pick_dir}, |
| | 187 | 0, |
| | 188 | Wx::wxLEFT, |
| | 189 | 1 |
| | 190 | ); |
| | 191 | # ... and adding it to the grid |
| | 192 | $find_grid->Add( |
| | 193 | $dir_sizer, |
| | 194 | 1, |
| | 195 | Wx::wxEXPAND | Wx::wxALIGN_LEFT | Wx::wxALIGN_CENTER_VERTICAL, |
| | 196 | 0 |
| | 197 | ); |
| | 198 | $find_grid->Add( |
| | 199 | Wx::StaticText->new( |
| | 200 | $self, |
| | 201 | Wx::wxID_STATIC, |
| | 202 | Wx::gettext('In Files/Types:') |
| | 203 | ), |
| | 204 | 0, |
| | 205 | Wx::wxALIGN_LEFT | Wx::wxALIGN_CENTER_VERTICAL, |
| | 206 | 0 |
| | 207 | ); |
| | 208 | $find_grid->Add( |
| | 209 | $self->{_file_types}, |
| | 210 | 1, |
| | 211 | Wx::wxEXPAND, |
| | 212 | 0 |
| | 213 | ); |
| | 214 | |
| | 215 | # Setting up the box containing the search criteria |
| | 216 | my $find_box = Wx::StaticBoxSizer->new( |
| | 217 | Wx::StaticBox->new( |
| | 218 | $self, |
| | 219 | -1, |
| | 220 | Wx::gettext('Find in Files') |
| | 221 | ), |
| | 222 | Wx::wxVERTICAL |
| | 223 | ); |
| | 224 | $find_box->Add( |
| | 225 | $find_grid, |
| | 226 | 1, |
| | 227 | Wx::wxEXPAND | Wx::wxALL, |
| | 228 | 5 |
| | 229 | ); |
| | 230 | |
| | 231 | # Setting up the box containing the search options |
| | 232 | my $option_box = Wx::StaticBoxSizer->new( |
| | 233 | Wx::StaticBox->new( |
| | 234 | $self, |
| | 235 | -1, |
| | 236 | Wx::gettext('Options') |
| | 237 | ), |
| | 238 | Wx::wxVERTICAL |
| | 239 | ); |
| | 240 | $option_box->Add( |
| | 241 | $self->{_case_insensitive}, |
| | 242 | 0, |
| | 243 | Wx::wxALIGN_LEFT | Wx::wxALIGN_CENTER_VERTICAL | Wx::wxALL, |
| | 244 | 5 |
| | 245 | ); |
| | 246 | $option_box->Add( |
| | 247 | $self->{_ignore_hidden_subdirs}, |
| | 248 | 0, |
| | 249 | Wx::wxALIGN_LEFT | Wx::wxALIGN_CENTER_VERTICAL | Wx::wxALL, |
| | 250 | 5 |
| | 251 | ); |
| | 252 | |
| | 253 | # Setting up the box containing the buttons |
| | 254 | my $button_box = Wx::BoxSizer->new( |
| | 255 | Wx::wxHORIZONTAL |
| | 256 | ); |
| | 257 | $button_box->Add( |
| | 258 | $self->{_find}, |
| | 259 | 0, |
| | 260 | Wx::wxALL, |
| | 261 | 5 |
| | 262 | ); |
| | 263 | $button_box->Add( |
| | 264 | $self->{_cancel}, |
| | 265 | 0, |
| | 266 | Wx::wxALL, |
| | 267 | 5 |
| | 268 | ); |
| | 269 | |
| | 270 | # Setting up the dialog's sizer |
| | 271 | my $sizer = Wx::BoxSizer->new( |
| | 272 | Wx::wxVERTICAL |
| | 273 | ); |
| | 274 | $sizer->Add( |
| | 275 | $find_box, |
| | 276 | 0, |
| | 277 | Wx::wxEXPAND | Wx::wxALL, |
| | 278 | 5 |
| | 279 | ); |
| | 280 | $sizer->Add( |
| | 281 | $option_box, |
| | 282 | 0, |
| | 283 | Wx::wxEXPAND | Wx::wxALL, |
| | 284 | 5 |
| | 285 | ); |
| | 286 | $sizer->Add( |
| | 287 | $button_box, |
| | 288 | 0, |
| | 289 | Wx::wxALIGN_RIGHT | Wx::wxALL, |
| | 290 | 5 |
| | 291 | ); |
| | 292 | |
| | 293 | # Applying the sizer(s) to the dialog |
| | 294 | $self->SetSizer($sizer); |
| | 295 | $sizer->SetSizeHints($self); |
| | 296 | |
| | 297 | # Update the dialog from configuration |
| | 298 | my $config = $self->current->config; |
| | 299 | $self->{_case_insensitive}->SetValue(!($config->find_case)); |
| | 300 | $self->{_ignore_hidden_subdirs}->SetValue($config->find_nohidden); |
| | 301 | |
| | 302 | return $self; |
| | 303 | } |
| | 304 | |
| | 305 | =pod |
| | 306 | |
| | 307 | =head2 cancel |
| | 308 | |
| | 309 | $self->cancel |
| | 310 | |
| | 311 | Hide dialog when pressed cancel button. |
| | 312 | |
| | 313 | =cut |
| | 314 | |
| | 315 | sub cancel { |
| | 316 | my $self = shift; |
| | 317 | $self->Hide; |
| | 318 | |
| | 319 | # As we leave the Find dialog, return the user to the current editor |
| | 320 | # window so they don't need to click it. |
| | 321 | my $editor = $self->current->editor; |
| | 322 | if ($editor) { |
| | 323 | $editor->SetFocus; |
| | 324 | } |
| | 325 | |
| | 326 | return; |
| | 327 | } |
| | 328 | |
| | 329 | =pod |
| | 330 | |
| | 331 | =head2 find |
| | 332 | |
| | 333 | $self->find |
| | 334 | |
| | 335 | Loading up App::Ack if neccessary, Grabbing currently selected text, placing it |
| | 336 | in the find combobox and showing the dialog. |
| | 337 | |
| | 338 | =cut |
| | 339 | |
| | 340 | sub find { |
| | 341 | my $self = shift; |
| | 342 | |
| | 343 | # Delay App::Ack loading till first use, this reduces memory usage |
| | 344 | # and init time |
| | 345 | unless($_ack_loaded) { |
| | 346 | my $minver = 1.86; |
| | 347 | my $error = "App::Ack $minver required for this feature"; |
| | 348 | |
| | 349 | # try to load app::ack - we don't require $minver in the eval to |
| | 350 | # provide a meaningful error message if needed. |
| | 351 | eval 'use App::Ack'; ## no critic |
| | 352 | if ($@) { |
| | 353 | $self->main->error("$error (module not installed)"); |
| | 354 | return; |
| | 355 | } elsif( $App::Ack::VERSION < $minver ) { |
| | 356 | $self->main->error("$error (you have $App::Ack::VERSION installed)"); |
| | 357 | return; |
| | 358 | } |
| | 359 | # redefine some app::ack subs to display results in padre's output |
| | 360 | SCOPE: { |
| | 361 | no warnings 'redefine', 'once'; |
| | 362 | *{App::Ack::print_first_filename} = sub { $self->_print_results("$_[0]\n"); }; |
| | 363 | *{App::Ack::print_separator} = sub { $self->_print_results("--\n"); }; |
| | 364 | *{App::Ack::print} = sub { $self->_print_results( $_[0] ); }; |
| | 365 | *{App::Ack::print_filename} = sub { $self->_print_results("$_[0]$_[1]"); }; |
| | 366 | *{App::Ack::print_line_no} = sub { $self->_print_results("$_[0]$_[1]"); }; |
| | 367 | } |
| | 368 | $_ack_loaded = 1; |
| | 369 | } |
| | 370 | |
| | 371 | $self->{_ack_term}->refresh; |
| | 372 | $self->{_ack_term}->SetValue($self->current->text || ''); |
| | 373 | $self->{_ack_term}->SetFocus; |
| | 374 | $self->{_ack_dir}->refresh; |
| | 375 | $self->{_ack_dir}->SetValue($self->current->project->root) if $self->current->project; |
| | 376 | |
| | 377 | $self->Show(1) unless $self->IsShown; |
| | 378 | |
| | 379 | return; |
| | 380 | } |
| | 381 | |
| | 382 | sub on_pick_dir { |
| | 383 | my $self = shift; |
| | 384 | my $event = shift; |
| | 385 | |
| | 386 | my $default_dir = $self->{_ack_dir}->GetValue; |
| | 387 | unless($default_dir) { |
| | 388 | my $filename = $self->current->filename; |
| | 389 | $default_dir = File::Basename::dirname($filename) if $filename; |
| | 390 | } |
| | 391 | |
| | 392 | my $dir_dialog = Wx::DirDialog->new( |
| | 393 | $self->main, |
| | 394 | Wx::gettext("Select directory"), |
| | 395 | $default_dir |
| | 396 | ); |
| | 397 | return if $dir_dialog->ShowModal == Wx::wxID_CANCEL |
| | 398 | $self->{_ack_dir}->SetValue($dir_dialog->GetPath); |
| | 399 | |
| | 400 | return; |
| | 401 | } |
| | 402 | |
| | 403 | sub find_clicked { |
| | 404 | my $self = shift; |
| | 405 | my $event = shift; |
| | 406 | my $main = $self->current->main; |
| | 407 | my $config = $self->_sync_config; |
| | 408 | |
| | 409 | return unless $self->{_ack_term}->GetValue; |
| | 410 | |
| | 411 | # TODO kill the thread before closing the application |
| | 412 | @_ = (); # cargo cult or bug? see Wx::Thread / Creating new threads |
| | 413 | |
| | 414 | $self->{ack_opts} = {}; |
| | 415 | |
| | 416 | $self->{ack_opts}->{regex} = $self->{_ack_term}->GetValue; |
| | 417 | if($config->find_nohidden) { |
| | 418 | $self->{ack_opts}->{all} = 1; |
| | 419 | } else { |
| | 420 | $self->{ack_opts}->{u} = 1; # unrestricted |
| | 421 | } |
| | 422 | |
| | 423 | for my $i ( App::Ack::filetypes_supported() ) { |
| | 424 | $App::Ack::type_wanted{$i} = undef; |
| | 425 | } |
| | 426 | if(my $file_types = $self->{_file_types}) { |
| | 427 | my $is_regex = 1; |
| | 428 | my $wanted = ($file_types =~ s/^no//)? 0 : 1; |
| | 429 | for my $i ( App::Ack::filetypes_supported() ) { |
| | 430 | if ( $i eq $file_types ) { |
| | 431 | $App::Ack::type_wanted{$i} = $wanted; |
| | 432 | $is_regex = 0; |
| | 433 | last; |
| | 434 | } |
| | 435 | } |
| | 436 | $self->{ack_opts}->{G} = quotemeta $file_types if $is_regex; |
| | 437 | } |
| | 438 | |
| | 439 | # case_insensitive |
| | 440 | $self->{ack_opts}->{i} = $config->find_case if $config->find_case; |
| | 441 | |
| | 442 | my $what = App::Ack::get_starting_points( [ $self->{_ack_dir}->GetValue ], $self->{ack_opts} ); |
| | 443 | $self->{ack_iter} = App::Ack::get_iterator( $what, $self->{ack_opts} ); |
| | 444 | App::Ack::filetype_setup(); |
| | 445 | |
| | 446 | unless ( $main->{ack} ) { |
| | 447 | $self->_ack_create_pane; |
| | 448 | } |
| | 449 | $main->show_output(1); |
| | 450 | $self->_ack_show_output(1); |
| | 451 | $main->{ack}->DeleteAllItems; |
| | 452 | |
| | 453 | Wx::Event::EVT_COMMAND( $main, -1, $self->{ack_done_event}, sub { $self->_ack_done(@_); } ); |
| | 454 | |
| | 455 | my $worker = threads->create( sub { $self->_ack_on_thread(@_); } ); |
| | 456 | |
| | 457 | return; |
| | 458 | } |
| | 459 | |
| | 460 | sub _ack_create_pane { |
| | 461 | my $self = shift; |
| | 462 | my $main = $self->current->main; |
| | 463 | |
| | 464 | $main->{ack} = Wx::ListCtrl->new( |
| | 465 | $main->bottom, |
| | 466 | -1, |
| | 467 | Wx::wxDefaultPosition, |
| | 468 | Wx::wxDefaultSize, |
| | 469 | Wx::wxLC_SINGLE_SEL | Wx::wxLC_NO_HEADER | Wx::wxLC_REPORT |
| | 470 | ); |
| | 471 | |
| | 472 | $main->{ack}->InsertColumn( 0, Wx::gettext('Ack') ); |
| | 473 | $main->{ack}->SetColumnWidth( 0, Wx::wxLIST_AUTOSIZE ); |
| | 474 | |
| | 475 | Wx::Event::EVT_LIST_ITEM_ACTIVATED( |
| | 476 | $main, |
| | 477 | $main->{ack}, |
| | 478 | sub { $self->_ack_on_result_selected(@_); }, |
| | 479 | ); |
| | 480 | } |
| | 481 | |
| | 482 | sub _ack_show_output { |
| | 483 | my $self = shift; |
| | 484 | my $main = $self->current->main; |
| | 485 | my $on = @_ ? $_[0] ? 1 : 0 : 1; |
| | 486 | my $bp = \$main->{bottom}; |
| | 487 | my $op = \$main->{ack}; |
| | 488 | my $idx = ${$bp}->GetPageIndex( ${$op} ); |
| | 489 | |
| | 490 | if ( $idx >= 0 ) { |
| | 491 | ${$bp}->SetSelection($idx); |
| | 492 | } else { |
| | 493 | ${$bp}->InsertPage( |
| | 494 | 0, |
| | 495 | ${$op}, |
| | 496 | Wx::gettext("Ack"), |
| | 497 | 1, |
| | 498 | ); |
| | 499 | ${$op}->Show; |
| | 500 | } |
| | 501 | $main->aui->GetPane('bottom')->Show; |
| | 502 | $main->aui->Update; |
| | 503 | |
| | 504 | return; |
| | 505 | } |
| | 506 | |
| | 507 | sub _ack_on_result_selected { |
| | 508 | my ( $self, $event ) = @_; |
| | 509 | |
| | 510 | my $text = $event->GetItem->GetText; |
| | 511 | return if not defined $text; |
| | 512 | |
| | 513 | my ( $file, $line ) = ( $text =~ /^(.*?)\((\d+)\)\:/ ); |
| | 514 | return unless $line; |
| | 515 | |
| | 516 | my $main = $self->current->main; |
| | 517 | my $id = $main->setup_editor($file); |
| | 518 | $main->on_nth_pane($id) if $id; |
| | 519 | |
| | 520 | my $page = $main->current->editor; |
| | 521 | $line--; |
| | 522 | $page->goto_line_centerize($line); |
| | 523 | } |
| | 524 | |
| | 525 | sub _ack_done { |
| | 526 | my ( $self, $main, $event ) = @_; |
| | 527 | |
| | 528 | my $data = $event->GetData; |
| | 529 | |
| | 530 | $main = $self->current->main; |
| | 531 | $main->{ack}->InsertStringItem( $self->{_panel_index}--, $data ); |
| | 532 | $main->{ack}->SetColumnWidth( 0, Wx::wxLIST_AUTOSIZE ); |
| | 533 | |
| | 534 | return; |
| | 535 | } |
| | 536 | |
| | 537 | sub _ack_on_thread { |
| | 538 | my $self = shift; |
| | 539 | # clear $self->{ack_stats}; for every request |
| | 540 | $self->{ack_stats} = { |
| | 541 | cnt_files => 0, |
| | 542 | cnt_matches => 0, |
| | 543 | }; |
| | 544 | |
| | 545 | App::Ack::print_matches( $self->{ack_iter}, $self->{ack_opts} ); |
| | 546 | |
| | 547 | # summary |
| | 548 | $self->_send_text( '-' x 39 . "\n" ) if ( $self->{ack_stats}->{cnt_files} ); |
| | 549 | $self->_send_text("Found $self->{ack_stats}->{cnt_files} files and $self->{ack_stats}->{cnt_matches} matches\n"); |
| | 550 | } |
| | 551 | |
| | 552 | sub _print_results { |
| | 553 | my ( $self, $text ) = @_; |
| | 554 | |
| | 555 | # the first is filename, the second is line number, the third is matched line text |
| | 556 | # while 'Binary file', there is ONLY filename |
| | 557 | $self->{ack_stats}->{printed_lines}++; |
| | 558 | |
| | 559 | # don't print filename again if it's just printed |
| | 560 | return |
| | 561 | if ($self->{ack_stats}->{printed_lines} % 3 == 1 |
| | 562 | and $self->{ack_stats}->{last_matched_filename} |
| | 563 | and $self->{ack_stats}->{last_matched_filename} eq $text ); |
| | 564 | if ( $self->{ack_stats}->{printed_lines} % 3 == 1 ) { |
| | 565 | if ( $text =~ /^Binary file/ ) { |
| | 566 | $self->{ack_stats}->{printed_lines} = $self->{ack_stats}->{printed_lines} + 2; |
| | 567 | } |
| | 568 | |
| | 569 | $self->{ack_stats}->{last_matched_filename} = $text; |
| | 570 | $self->{ack_stats}->{cnt_files}++; |
| | 571 | |
| | 572 | # chop last ':', add \n after $filename |
| | 573 | chop($text); |
| | 574 | $text = "Found '$self->{ack_opts}->{regex}' in '$text':\n"; |
| | 575 | |
| | 576 | # new line between different files |
| | 577 | $self->_send_text( '-' x 39 . "\n" ); |
| | 578 | } elsif ( $self->{ack_stats}->{printed_lines} % 3 == 2 ) { |
| | 579 | $self->{ack_stats}->{cnt_matches}++; |
| | 580 | |
| | 581 | # use () to wrap the number, an extra space for line number |
| | 582 | $text =~ s/(\d+)/\($1\)/; |
| | 583 | $text .= ' '; |
| | 584 | } |
| | 585 | |
| | 586 | #my $end = $result->get_end_iter; |
| | 587 | #$result->insert($end, $text); |
| | 588 | |
| | 589 | # just print it when we have \n |
| | 590 | if ( $text =~ /[\r\n]/ ) { |
| | 591 | my $filename = $self->{ack_stats}->{last_matched_filename}; |
| | 592 | chop($filename); |
| | 593 | $text = $filename . $self->{ack_stats}->{last_text} . $text if $self->{ack_stats}->{last_text}; |
| | 594 | delete $self->{ack_stats}->{last_text}; |
| | 595 | } else { |
| | 596 | $self->{ack_stats}->{last_text} .= $text; |
| | 597 | return; |
| | 598 | } |
| | 599 | |
| | 600 | $self->_send_text($text); |
| | 601 | |
| | 602 | return; |
| | 603 | } |
| | 604 | |
| | 605 | sub _send_text { |
| | 606 | my ( $self, $text) = shift; |
| | 607 | |
| | 608 | # Wx documentation states that the value passed must be shared. |
| | 609 | share($text); |
| | 610 | |
| | 611 | my $threvent = Wx::PlThreadEvent->new( -1, $self->{ack_done_event}, $text ); |
| | 612 | Wx::PostEvent( $self->current->main, $threvent ); |
| | 613 | } |
| | 614 | |
| | 615 | sub _sync_config { |
| | 616 | my $self = shift; |
| | 617 | my $config = $self->current->config; |
| | 618 | $config->set(find_case => !$self->{_case_insensitive}->GetValue); |
| | 619 | $config->set(find_nohidden => $self->{_ignore_hidden_subdirs}->GetValue); |
| | 620 | $config->write; |
| | 621 | |
| | 622 | return $config; |
| | 623 | } |
| | 624 | |
| | 625 | 1; |
| | 626 | |
| | 627 | =pod |
| | 628 | |
| | 629 | =head1 COPYRIGHT & LICENSE |
| | 630 | |
| | 631 | Copyright 2008-2009 The Padre development team as listed in Padre.pm. |
| | 632 | |
| | 633 | This program is free software; you can redistribute |
| | 634 | it and/or modify it under the same terms as Perl itself. |
| | 635 | |
| | 636 | The full text of the license can be found in the |
| | 637 | LICENSE file included with this module. |
| | 638 | |
| | 639 | =cut |
| | 640 | |
| | 641 | # Copyright 2008-2009 The Padre development team as listed in Padre.pm. |
| | 642 | # LICENSE |
| | 643 | # This program is free software; you can redistribute it and/or |
| | 644 | # modify it under the same terms as Perl 5 itself. |