Ticket #68: ticket_66_67_68.diff

File ticket_66_67_68.diff, 10.5 KB (added by tsee, 6 years ago)

Patch implementing this ticket, as well as 66/67

  • lib/Padre.pm

     
    165165    $Class::Autouse::LOADED{'Wx::Object'} = 1; 
    166166} 
    167167use Class::Autouse qw{ 
     168   Padre::PluginManager 
    168169   Padre::Project 
    169170   Padre::Pod::Frame 
    170171   Padre::Pod::Indexer 
     
    210211            files => [], 
    211212            pod   => [], 
    212213        }, 
     214 
     215        plugin_manager => undef, 
    213216    }, $class; 
    214217 
    215218    # Locate the configuration directory 
     
    218221    $self->{config_db}   = Padre::Config->default_db; 
    219222 
    220223    $self->load_config; 
     224 
    221225    $self->_process_command_line; 
    222     $self->_locate_plugins; 
    223226 
     227    $self->{plugin_manager} = Padre::PluginManager->new($self), 
     228 
    224229    $SINGLETON = $self; 
    225230    return $self; 
    226231} 
     
    247252    $_[0]->{config_db}; 
    248253} 
    249254 
     255sub plugin_dir { 
     256    $_[0]->{plugin_dir}; 
     257} 
     258 
     259sub plugin_manager { 
     260    $_[0]->{plugin_manager}; 
     261} 
     262 
    250263sub run { 
    251264    my ($self) = @_; 
    252265    if ( $self->get_index ) { 
    253266        $self->run_indexer; 
    254267    } else { 
     268        # FIXME: This call should be delayed until after the 
     269        # window was opened but my Wx skills do not exist. --Steffen 
     270        # (RT #1) 
     271        $self->plugin_manager->load_plugins(); 
    255272        $self->run_editor; 
    256273    } 
    257274    return; 
     
    282299 
    283300    return; 
    284301} 
    285  
    286 sub _locate_plugins { 
    287     my ($self) = @_; 
    288     my %plugins; 
    289     foreach my $path (@INC) { 
    290         my $dir = File::Spec->catdir($path, 'Padre', 'Plugin'); 
    291         opendir my $dh, $dir or next; 
    292         while (my $file = readdir $dh) { 
    293             if ($file =~ /^\w+\.pm$/) { 
    294                 $file =~ s/\.pm$//; 
    295                 $plugins{$file} = 0; 
    296                 my $module = "Padre::Plugin::$file"; 
    297         eval "use $module"; ## no critic 
    298                 if ($@) { 
    299                     warn "ERROR while trying to load plugin '$file': $@"; 
    300                     next; 
    301                 } 
    302                  
    303                 $plugins{$file} = $module; 
    304             } 
    305         } 
    306     } 
    307     $self->{plugins} = \%plugins; 
    308     return; 
    309 } 
    310  
    311302sub usage { 
    312303    die <<"END_USAGE"; 
    313304Usage: $0 [FILENAMEs] 
  • lib/Padre/Config.pm

     
    33use 5.008; 
    44use strict; 
    55use warnings; 
     6use File::Path    (); 
    67use File::Spec    (); 
    78use File::HomeDir (); 
    89use YAML::Tiny    (); 
     
    4344    ); 
    4445} 
    4546 
     47sub default_plugin_dir { 
     48    my $pluginsdir = File::Spec->catdir( 
     49        $_[0]->default_dir, 
     50        'plugins', 
     51    ); 
     52    my $plugins_full_path = File::Spec->catdir( 
     53        $pluginsdir, 'Padre', 'Plugin' 
     54    ); 
     55    unless ( -e $plugins_full_path) { 
     56        File::Path::mkpath($plugins_full_path) or 
     57        die "Cannot create plugins dir '$plugins_full_path' $!"; 
     58    } 
    4659 
     60    return $pluginsdir; 
     61} 
    4762 
    4863 
    4964 
     65 
     66 
    5067##################################################################### 
    5168# Constructor and Serialization 
    5269 
  • lib/Padre/PluginManager.pm

     
     1package Padre::PluginManager; 
     2 
     3# Miscellaneous plugin functionality for Padre 
     4 
     5use strict; 
     6use warnings; 
     7use File::Path (); 
     8use File::Spec (); 
     9use Carp       qw(croak); 
     10 
     11our $VERSION = '0.06'; 
     12 
     13 
     14sub new { 
     15    my $class = shift; 
     16    my $padre = shift || Padre->new(); 
     17 
     18    if (not $padre or not $padre->isa("Padre")) { 
     19      croak("Creation of a Padre::PluginManager without a Padre not possible"); 
     20    } 
     21 
     22    my $self  = bless { 
     23      plugins => {}, 
     24      plugin_dir => Padre::Config->default_plugin_dir, 
     25       
     26      par_loaded => 0, 
     27      @_ 
     28    }, $class; 
     29 
     30    return $self; 
     31} 
     32 
     33############# 
     34# ACCESSORS 
     35# 
     36sub plugin_dir { $_[0]->{plugin_dir} } 
     37 
     38sub plugins { $_[0]->{plugins} } 
     39 
     40############## 
     41 
     42sub load_plugins { 
     43    my ($self) = @_; 
     44    $self->_load_plugins_from_inc(); 
     45    $self->_load_plugins_from_par(); 
     46    return; 
     47} 
     48 
     49sub _load_plugins_from_inc { 
     50    my ($self) = @_; 
     51 
     52    # Try the plugin directory first: 
     53    my $plugin_dir = $self->plugin_dir; 
     54    unshift @INC, $plugin_dir unless grep {$_ eq $plugin_dir} @INC; 
     55 
     56    foreach my $path (@INC) { 
     57        my $dir = File::Spec->catdir($path, 'Padre', 'Plugin'); 
     58        opendir my $dh, $dir or next; 
     59        while (my $file = readdir $dh) { 
     60            if ($file =~ /^\w+\.pm$/) { 
     61                $file =~ s/\.pm$//; 
     62                $self->_load_plugin($file); 
     63            } 
     64        } 
     65    } 
     66 
     67    return; 
     68} 
     69 
     70sub _load_plugins_from_par { 
     71    my ($self) = @_; 
     72    $self->_setup_par(); 
     73 
     74    my $plugin_dir = $self->plugin_dir(); 
     75    opendir my $dh, $plugin_dir or return; 
     76    while (my $file = readdir $dh) { 
     77        if ($file =~ /^\w+\.par$/i) { 
     78            my $parfile = File::Spec->catfile($plugin_dir, $file); 
     79            $file =~ s/\.par$//i; 
     80            PAR->import($parfile); 
     81            $self->_load_plugin($file); 
     82        } 
     83    } 
     84    closedir($dh); 
     85    return; 
     86} 
     87 
     88sub _setup_par { 
     89    my ($self) = @_; 
     90 
     91    return if $self->{par_loaded}; 
     92 
     93    require PAR; 
     94    # setup the PAR environment: 
     95    my $plugin_dir = $self->plugin_dir; 
     96    my $cache_dir = File::Spec->catdir($plugin_dir, 'cache'); 
     97    $ENV{PAR_GLOBAL_TEMP} = $cache_dir; 
     98    File::Path::mkpath($cache_dir) if not -e $cache_dir; 
     99    $ENV{PAR_TEMP} = $cache_dir; 
     100 
     101    $self->{par_loaded} = 1; 
     102    return(); 
     103} 
     104 
     105# given a file name (Foo.pm), load the corresponding module 
     106sub _load_plugin { 
     107    my ($self, $file) = @_; 
     108    my $plugins = $self->plugins; 
     109    $plugins->{$file} = 0; 
     110     
     111    my $module = "Padre::Plugin::$file"; 
     112 
     113    # skip if that plugin was already loaded 
     114    my $inc_file = $module.".pm"; 
     115    $inc_file =~ s/::/\//g; 
     116    return if exists $INC{$inc_file}; 
     117 
     118    eval "use $module"; ## no critic 
     119    if ($@) { 
     120        warn "ERROR while trying to load plugin '$file': $@"; 
     121        return(); 
     122    } 
     123    $plugins->{$file} = $module; 
     124    return 1; 
     125} 
     126 
     127 
     1281; 
  • lib/Padre/Wx/Menu.pm

     
    5050    EVT_MENU( $win, $menu->{edit}->Append( wxID_FIND, '' ),           \&Padre::Wx::MainWindow::on_find             ); 
    5151    EVT_MENU( $win, $menu->{edit}->Append( -1, "&Find Again\tF3" ),   \&Padre::Wx::MainWindow::on_find_again       ); 
    5252    EVT_MENU( $win, $menu->{edit}->Append( -1, "&Goto\tCtrl-G" ),     \&Padre::Wx::MainWindow::on_goto             ); 
    53     EVT_MENU( $win, $menu->{edit}->Append( -1, "&AutoComp\tCtrl-P" ), \&Padre::Wx::MainWindow::on_autocompletition ); 
     53    EVT_MENU( $win, $menu->{edit}->Append( -1, "&AutoComp->\tCtrl-N" ), \&Padre::Wx::MainWindow::on_forward_autocompletition ); 
     54    EVT_MENU( $win, $menu->{edit}->Append( -1, "<-&AutoComp\tCtrl-P" ), \&Padre::Wx::MainWindow::on_backward_autocompletition ); 
    5455    EVT_MENU( $win, $menu->{edit}->Append( -1, "Subs\tAlt-S"     ),   sub { $_[0]->{rightbar}->SetFocus()} );  
    5556    EVT_MENU( $win, $menu->{edit}->Append( -1, "&Comment out block\tCtrl-M" ),   \&Padre::Wx::MainWindow::on_comment_out_block       ); 
    5657    EVT_MENU( $win, $menu->{edit}->Append( -1, "&UnComment block\tCtrl-Shift-M" ),   \&Padre::Wx::MainWindow::on_uncomment_block       ); 
     
    140141     
    141142    # Create the Plugins menu 
    142143    $menu->{plugin} = Wx::Menu->new; 
    143     my %plugins = %{ $ide->{plugins} }; 
     144    my %plugins = %{ $ide->plugin_manager->plugins }; 
    144145    foreach my $name ( sort keys %plugins ) { 
    145146        next if not $plugins{$name}; 
    146147        my @menu    = eval { $plugins{$name}->menu }; 
  • lib/Padre/Wx/MainWindow.pm

     
    400400} 
    401401 
    402402 
    403 sub on_autocompletition { 
    404    my $self   = shift; 
     403sub on_forward_autocompletition { 
     404   my $self = shift; 
     405    
     406   $self->_autocompletition("forward"); 
     407   return; 
     408} 
    405409 
    406    my $id     = $self->{notebook}->GetSelection; 
    407    my $page   = $self->{notebook}->GetPage($id); 
    408    my $pos    = $page->GetCurrentPos; 
    409    my $line   = $page->LineFromPosition($pos); 
    410    my $first  = $page->PositionFromLine($line); 
    411    my $prefix = $page->GetTextRange($first, $pos); # line from beginning to current position 
    412       $prefix =~ s{^.*?((\w+::)*\w+)$}{$1}; 
    413    my $last   = $page->GetLength(); 
    414    my $text   = $page->GetTextRange(0, $last); 
     410 
     411sub on_backward_autocompletition { 
     412   my $self = shift; 
     413    
     414   $self->_autocompletition("backward"); 
     415   return; 
     416} 
     417 
     418 
     419sub _autocompletition { 
     420   my $self      = shift; 
     421   my $direction = shift; 
     422 
     423   my $id        = $self->{notebook}->GetSelection; 
     424   my $page      = $self->{notebook}->GetPage($id); 
     425   my $pos       = $page->GetCurrentPos; 
     426   my $line      = $page->LineFromPosition($pos); 
     427   my $first     = $page->PositionFromLine($line); 
     428   my $prefix    = $page->GetTextRange($first, $pos); # line from beginning to current position 
     429   $prefix =~ s{^.*?((\w+::)*\w+)$}{$1}; 
     430   my $last      = $page->GetLength(); 
     431   my $pre_text  = $page->GetTextRange(0, $first+length($prefix)); 
     432   my $post_text = $page->GetTextRange($first, $last); 
     433 
    415434   my %seen; 
    416    my @words = grep { ! $seen{$_}++ } sort ($text =~ m{\b($prefix\w*(?:::\w+)*)\b}g); 
    417    if (@words > 20) { 
    418       @words = @words[0..19]; 
     435   my @words; 
     436   my $completion_regexp = qr{\b($prefix\w*(?:::\w+)*)\b}; 
     437   if ($direction eq 'forward') { 
     438     push @words, grep { ! $seen{$_}++ } ($post_text =~ /$completion_regexp/g); 
     439     push @words, grep { ! $seen{$_}++ } ($pre_text  =~ /$completion_regexp/g); 
     440   } else { 
     441     push @words, grep { ! $seen{$_}++ } reverse ($pre_text  =~ /$completion_regexp/g); 
     442     push @words, grep { ! $seen{$_}++ } reverse ($post_text =~ /$completion_regexp/g); 
    419443   } 
     444 
     445   my $max_words = 20; 
     446   if (@words > $max_words) { 
     447      @words = @words[0..$max_words-1]; 
     448   } 
    420449   $page->AutoCompShow(length($prefix), join " ", @words); 
    421450 
    422451   return; 
    423452} 
    424453 
     454 
    425455sub on_right_click { 
    426456    my ($self, $event) = @_; 
    427457#print "right\n"; 
  • Build.PL

     
    2626        'File::Slurp'             => 0, 
    2727    'Module::Inspector'       => '0.04', 
    2828        'ORLite'                  => '0.10', 
     29        'PAR'                     => '0.970', 
    2930        'Pod::POM'                => 0, 
    3031        'Pod::Simple'             => 0, 
    3132    'Probe::Perl'             => '0.01',