Index: lib/Padre.pm
===================================================================
--- lib/Padre.pm	(Revision 165)
+++ lib/Padre.pm	(Arbeitskopie)
@@ -165,6 +165,7 @@
 	$Class::Autouse::LOADED{'Wx::Object'} = 1;
 }
 use Class::Autouse qw{
+   Padre::PluginManager
    Padre::Project
    Padre::Pod::Frame
    Padre::Pod::Indexer
@@ -210,6 +211,8 @@
             files => [],
             pod   => [],
         },
+
+        plugin_manager => undef,
     }, $class;
 
     # Locate the configuration directory
@@ -218,9 +221,11 @@
     $self->{config_db}   = Padre::Config->default_db;
 
     $self->load_config;
+
     $self->_process_command_line;
-    $self->_locate_plugins;
 
+    $self->{plugin_manager} = Padre::PluginManager->new($self),
+
     $SINGLETON = $self;
     return $self;
 }
@@ -247,11 +252,23 @@
     $_[0]->{config_db};
 }
 
+sub plugin_dir {
+    $_[0]->{plugin_dir};
+}
+
+sub plugin_manager {
+    $_[0]->{plugin_manager};
+}
+
 sub run {
     my ($self) = @_;
     if ( $self->get_index ) {
         $self->run_indexer;
     } else {
+        # FIXME: This call should be delayed until after the
+        # window was opened but my Wx skills do not exist. --Steffen
+        # (RT #1)
+        $self->plugin_manager->load_plugins();
         $self->run_editor;
     }
     return;
@@ -282,32 +299,6 @@
 
     return;
 }
-
-sub _locate_plugins {
-    my ($self) = @_;
-    my %plugins;
-    foreach my $path (@INC) {
-        my $dir = File::Spec->catdir($path, 'Padre', 'Plugin');
-        opendir my $dh, $dir or next;
-        while (my $file = readdir $dh) {
-            if ($file =~ /^\w+\.pm$/) {
-                $file =~ s/\.pm$//;
-                $plugins{$file} = 0;
-                my $module = "Padre::Plugin::$file";
-		eval "use $module"; ## no critic
-                if ($@) {
-                    warn "ERROR while trying to load plugin '$file': $@";
-                    next;
-                }
-                
-                $plugins{$file} = $module;
-            }
-        }
-    }
-    $self->{plugins} = \%plugins;
-    return;
-}
-
 sub usage {
     die <<"END_USAGE";
 Usage: $0 [FILENAMEs]
Index: lib/Padre/Config.pm
===================================================================
--- lib/Padre/Config.pm	(Revision 165)
+++ lib/Padre/Config.pm	(Arbeitskopie)
@@ -3,6 +3,7 @@
 use 5.008;
 use strict;
 use warnings;
+use File::Path    ();
 use File::Spec    ();
 use File::HomeDir ();
 use YAML::Tiny    ();
@@ -43,10 +44,26 @@
     );
 }
 
+sub default_plugin_dir {
+    my $pluginsdir = File::Spec->catdir(
+        $_[0]->default_dir,
+        'plugins',
+    );
+    my $plugins_full_path = File::Spec->catdir(
+        $pluginsdir, 'Padre', 'Plugin'
+    );
+    unless ( -e $plugins_full_path) {
+        File::Path::mkpath($plugins_full_path) or
+        die "Cannot create plugins dir '$plugins_full_path' $!";
+    }
 
+    return $pluginsdir;
+}
 
 
 
+
+
 #####################################################################
 # Constructor and Serialization
 
Index: lib/Padre/PluginManager.pm
===================================================================
--- lib/Padre/PluginManager.pm	(Revision 0)
+++ lib/Padre/PluginManager.pm	(Revision 0)
@@ -0,0 +1,128 @@
+package Padre::PluginManager;
+
+# Miscellaneous plugin functionality for Padre
+
+use strict;
+use warnings;
+use File::Path ();
+use File::Spec ();
+use Carp       qw(croak);
+
+our $VERSION = '0.06';
+
+
+sub new {
+    my $class = shift;
+    my $padre = shift || Padre->new();
+
+    if (not $padre or not $padre->isa("Padre")) {
+      croak("Creation of a Padre::PluginManager without a Padre not possible");
+    }
+
+    my $self  = bless {
+      plugins => {},
+      plugin_dir => Padre::Config->default_plugin_dir,
+      
+      par_loaded => 0,
+      @_
+    }, $class;
+
+    return $self;
+}
+
+#############
+# ACCESSORS
+#
+sub plugin_dir { $_[0]->{plugin_dir} }
+
+sub plugins { $_[0]->{plugins} }
+
+##############
+
+sub load_plugins {
+    my ($self) = @_;
+    $self->_load_plugins_from_inc();
+    $self->_load_plugins_from_par();
+    return;
+}
+
+sub _load_plugins_from_inc {
+    my ($self) = @_;
+
+    # Try the plugin directory first:
+    my $plugin_dir = $self->plugin_dir;
+    unshift @INC, $plugin_dir unless grep {$_ eq $plugin_dir} @INC;
+
+    foreach my $path (@INC) {
+        my $dir = File::Spec->catdir($path, 'Padre', 'Plugin');
+        opendir my $dh, $dir or next;
+        while (my $file = readdir $dh) {
+            if ($file =~ /^\w+\.pm$/) {
+                $file =~ s/\.pm$//;
+                $self->_load_plugin($file);
+            }
+        }
+    }
+
+    return;
+}
+
+sub _load_plugins_from_par {
+    my ($self) = @_;
+    $self->_setup_par();
+
+    my $plugin_dir = $self->plugin_dir();
+    opendir my $dh, $plugin_dir or return;
+    while (my $file = readdir $dh) {
+        if ($file =~ /^\w+\.par$/i) {
+            my $parfile = File::Spec->catfile($plugin_dir, $file);
+            $file =~ s/\.par$//i;
+            PAR->import($parfile);
+            $self->_load_plugin($file);
+        }
+    }
+    closedir($dh);
+    return;
+}
+
+sub _setup_par {
+    my ($self) = @_;
+
+    return if $self->{par_loaded};
+
+    require PAR;
+    # setup the PAR environment:
+    my $plugin_dir = $self->plugin_dir;
+    my $cache_dir = File::Spec->catdir($plugin_dir, 'cache');
+    $ENV{PAR_GLOBAL_TEMP} = $cache_dir;
+    File::Path::mkpath($cache_dir) if not -e $cache_dir;
+    $ENV{PAR_TEMP} = $cache_dir;
+
+    $self->{par_loaded} = 1;
+    return();
+}
+
+# given a file name (Foo.pm), load the corresponding module
+sub _load_plugin {
+    my ($self, $file) = @_;
+    my $plugins = $self->plugins;
+    $plugins->{$file} = 0;
+    
+    my $module = "Padre::Plugin::$file";
+
+    # skip if that plugin was already loaded
+    my $inc_file = $module.".pm";
+    $inc_file =~ s/::/\//g;
+    return if exists $INC{$inc_file};
+
+    eval "use $module"; ## no critic
+    if ($@) {
+        warn "ERROR while trying to load plugin '$file': $@";
+        return();
+    }
+    $plugins->{$file} = $module;
+    return 1;
+}
+
+
+1;
Index: lib/Padre/Wx/Menu.pm
===================================================================
--- lib/Padre/Wx/Menu.pm	(Revision 165)
+++ lib/Padre/Wx/Menu.pm	(Arbeitskopie)
@@ -50,7 +50,8 @@
     EVT_MENU( $win, $menu->{edit}->Append( wxID_FIND, '' ),           \&Padre::Wx::MainWindow::on_find             );
     EVT_MENU( $win, $menu->{edit}->Append( -1, "&Find Again\tF3" ),   \&Padre::Wx::MainWindow::on_find_again       );
     EVT_MENU( $win, $menu->{edit}->Append( -1, "&Goto\tCtrl-G" ),     \&Padre::Wx::MainWindow::on_goto             );
-    EVT_MENU( $win, $menu->{edit}->Append( -1, "&AutoComp\tCtrl-P" ), \&Padre::Wx::MainWindow::on_autocompletition );
+    EVT_MENU( $win, $menu->{edit}->Append( -1, "&AutoComp->\tCtrl-N" ), \&Padre::Wx::MainWindow::on_forward_autocompletition );
+    EVT_MENU( $win, $menu->{edit}->Append( -1, "<-&AutoComp\tCtrl-P" ), \&Padre::Wx::MainWindow::on_backward_autocompletition );
     EVT_MENU( $win, $menu->{edit}->Append( -1, "Subs\tAlt-S"     ),   sub { $_[0]->{rightbar}->SetFocus()} ); 
     EVT_MENU( $win, $menu->{edit}->Append( -1, "&Comment out block\tCtrl-M" ),   \&Padre::Wx::MainWindow::on_comment_out_block       );
     EVT_MENU( $win, $menu->{edit}->Append( -1, "&UnComment block\tCtrl-Shift-M" ),   \&Padre::Wx::MainWindow::on_uncomment_block       );
@@ -140,7 +141,7 @@
     
     # Create the Plugins menu
     $menu->{plugin} = Wx::Menu->new;
-    my %plugins = %{ $ide->{plugins} };
+    my %plugins = %{ $ide->plugin_manager->plugins };
     foreach my $name ( sort keys %plugins ) {
         next if not $plugins{$name};
         my @menu    = eval { $plugins{$name}->menu };
Index: lib/Padre/Wx/MainWindow.pm
===================================================================
--- lib/Padre/Wx/MainWindow.pm	(Revision 165)
+++ lib/Padre/Wx/MainWindow.pm	(Arbeitskopie)
@@ -400,28 +400,58 @@
 }
 
 
-sub on_autocompletition {
-   my $self   = shift;
+sub on_forward_autocompletition {
+   my $self = shift;
+   
+   $self->_autocompletition("forward");
+   return;
+}
 
-   my $id     = $self->{notebook}->GetSelection;
-   my $page   = $self->{notebook}->GetPage($id);
-   my $pos    = $page->GetCurrentPos;
-   my $line   = $page->LineFromPosition($pos);
-   my $first  = $page->PositionFromLine($line);
-   my $prefix = $page->GetTextRange($first, $pos); # line from beginning to current position
-      $prefix =~ s{^.*?((\w+::)*\w+)$}{$1};
-   my $last   = $page->GetLength();
-   my $text   = $page->GetTextRange(0, $last);
+
+sub on_backward_autocompletition {
+   my $self = shift;
+   
+   $self->_autocompletition("backward");
+   return;
+}
+
+
+sub _autocompletition {
+   my $self      = shift;
+   my $direction = shift;
+
+   my $id        = $self->{notebook}->GetSelection;
+   my $page      = $self->{notebook}->GetPage($id);
+   my $pos       = $page->GetCurrentPos;
+   my $line      = $page->LineFromPosition($pos);
+   my $first     = $page->PositionFromLine($line);
+   my $prefix    = $page->GetTextRange($first, $pos); # line from beginning to current position
+   $prefix =~ s{^.*?((\w+::)*\w+)$}{$1};
+   my $last      = $page->GetLength();
+   my $pre_text  = $page->GetTextRange(0, $first+length($prefix));
+   my $post_text = $page->GetTextRange($first, $last);
+
    my %seen;
-   my @words = grep { ! $seen{$_}++ } sort ($text =~ m{\b($prefix\w*(?:::\w+)*)\b}g);
-   if (@words > 20) {
-      @words = @words[0..19];
+   my @words;
+   my $completion_regexp = qr{\b($prefix\w*(?:::\w+)*)\b};
+   if ($direction eq 'forward') {
+     push @words, grep { ! $seen{$_}++ } ($post_text =~ /$completion_regexp/g);
+     push @words, grep { ! $seen{$_}++ } ($pre_text  =~ /$completion_regexp/g);
+   } else {
+     push @words, grep { ! $seen{$_}++ } reverse ($pre_text  =~ /$completion_regexp/g);
+     push @words, grep { ! $seen{$_}++ } reverse ($post_text =~ /$completion_regexp/g);
    }
+
+   my $max_words = 20;
+   if (@words > $max_words) {
+      @words = @words[0..$max_words-1];
+   }
    $page->AutoCompShow(length($prefix), join " ", @words);
 
    return;
 }
 
+
 sub on_right_click {
     my ($self, $event) = @_;
 #print "right\n";
Index: Build.PL
===================================================================
--- Build.PL	(Revision 165)
+++ Build.PL	(Arbeitskopie)
@@ -26,6 +26,7 @@
         'File::Slurp'             => 0,
 	'Module::Inspector'       => '0.04',
         'ORLite'                  => '0.10',
+        'PAR'                     => '0.970',
         'Pod::POM'                => 0,
         'Pod::Simple'             => 0,
 	'Probe::Perl'             => '0.01',
