I've been looking a bit at Padre lately and thought that I'd try my hand at creating a plugin for it. While the documentation for creating plugins is rather thin, it didn't take very long or require too much poking around the source to create a useful (for me) plugin.
One of the features of Padre is the ability to create new documents from templates-- however, the templates list is hard-coded in the app which doesn't lend itself well towards creating/maintaining lots of different templates. Toward that end I decided to create a "My Templates" plugin that would allow me to maintain my own list of document creation templates.
package Padre::Plugin::MyTemplates;
use 5.008;
use strict;
use warnings;
use Padre::Constant ();
use Padre::Current ();
use Padre::Locale ();
use Padre::Plugin ();
use Padre::Wx ();
use File::Path qw(make_path);
our $VERSION = '0.11';
our @ISA = 'Padre::Plugin';
#####################################################################
# Padre::Plugin Methods
sub plugin_name {
'My Templates';
}
sub padre_interfaces {
'Padre::Plugin' => 0.43;
}
sub menu_plugins_simple {
my ($self) = @_;
my $template_dir = $self->template_dir();
my $template_idx = $self->index_file();
my @menu;
if ( -f $template_idx ) {
# Parse the index and dynamically create the menu items for th
+e various
# templates listed in the index.
my $IN;
if ( open( $IN, '<', $template_idx ) ) {
push @menu, Wx::gettext("Edit Index") => sub { $self->edit
+_index() };
# TODO: Provide a spiffy graphical way to add templates
# push @menu, Wx::gettext("Add Template") => sub { $self->
+add_template() };
my @entries = grep {m/^\s*[^#]/} (<$IN>);
chomp @entries;
close $IN;
foreach my $i (@entries) {
my ( $label, $file ) = split /\s+\|\s+/, $i;
next unless ( $label && $file );
$file =~ s/\s+$//;
# Determine if the file is fully specified or if it is
+ located
# in the CONFIG_DIR templates directory.
unless ( -f $file ) {
my $test = File::Spec->catfile( $template_dir, $fi
+le );
$file = $test if ( -f $test );
}
next unless ( -f $file );
push @menu, sprintf( Wx::gettext("New %s"), $label ) =
+> sub { $self->new_from_template($file) };
}
}
else {
$self->show_error( "Error reading template index:", $templ
+ate_idx, $! );
}
}
else {
@menu = ( Wx::gettext("Initialize") => sub { $self->create_ind
+ex() }, );
}
MyTemplates => [@menu];
}
#####################################################################
# Custom Methods
sub template_dir {
my ($self) = @_;
return File::Spec->catfile( Padre::Constant::CONFIG_DIR, 'template
+s' );
}
sub index_file {
my ($self) = @_;
return File::Spec->catfile( $self->template_dir(), 'template.index
+' );
}
sub create_index {
my ($self) = @_;
# Ensure that the template directory exists
my $template_dir = $self->template_dir();
make_path($template_dir) unless ( -d $template_dir );
unless ( -d $template_dir ) {
$self->show_error( "Template directory does not exist:", $temp
+late_dir );
return;
}
# Create a skeleton index file
my $template_idx = $self->index_file();
my $OUT;
if ( open( $OUT, '>', $template_idx ) ) {
print $OUT <<"EOT";
# MyTemplate template index
#
# This file should contain one line for each template in this director
+y.
#
# Entries are a pipe separated list of the form:
# template label | file name
#
# Comment lines start with a '#'
#
POD | template.pod
EOT
close $OUT;
# Create a sample template
my $template = File::Spec->catfile( $template_dir, 'template.p
+od' );
if ( open( $OUT, '>', $template ) ) {
# We don't want this showing up in the plugin POD
my @text = (
'=pod',
'=head1 Heading Text',
'=head2 Heading Text',
'=head3 Heading Text',
'=head4 Heading Text',
'=over indentlevel',
'=item stuff',
'=back',
'=begin format',
'=end format',
'=for format text...',
'=encoding type',
'=cut',
);
print $OUT +( join "\n\n", @text ), "\n";
close $OUT;
# Reload the plugin in order to update the menu
$self->current->ide->plugin_manager->reload_plugin('Padre:
+:Plugin::MyTemplates');
}
else {
$self->show_error( "Error creating sample template:", $tem
+plate, $! );
}
}
else {
$self->show_error( "Error creating template index:", $template
+_idx, $! );
}
}
sub show_error {
my ( $self, $text, $item, $bang ) = @_;
$bang ||= '';
$self->current->main->message(
sprintf( Wx::gettext("$text '%s'\n\n"), $item ) . $bang );
}
sub add_template {
my ($self) = @_;
# TODO:
# We need to prompt the user for:
# 1. the file to add
# 2. a label for the file
# 3. whether to leave the file where it is or copy it to their tem
+plate directory
# Update the index
# Reload the plugin in order to update the menu
# $self->current->ide->plugin_manager->reload_plugin('Padre::Plugi
+n::MyTemplates');
# Until we figure that all out...
$self->current->main->message(
Wx::gettext('This feature has not been implemented yet...'),
Wx::gettext('Notice') );
}
sub edit_index {
my ($self) = @_;
my $template_idx = $self->index_file();
$self->current->main->setup_editors($template_idx);
}
sub new_from_template {
my ( $self, $file ) = @_;
# Load up a new editor tab...
$self->current->main->on_new;
# ...and insert the template text into the tab.
# (Rather shamelessly copied from Padre::Wx::Main b.t.w.)
my $editor = $self->current->editor or return;
if ( $editor->insert_from_file($file) ) {
my $document = $editor->{Document};
$document->{original_content} = $document->text_get;
$document->set_mimetype( $document->guess_mimetype );
$document->editor->padre_setup;
$document->rebless;
$document->colourize;
}
else {
$self->show_error( "Error loading template file '%s'", $file )
+;
}
return;
}
1;
__END__
=head1 NAME
Padre::Plugin::MyTemplates - A personal templates plugin
=head1 DESCRIPTION
Allows users to have maintain their own set of templates for use in cr
+eating
new files.
Template information is stored in a template.index file in the user's
~/.padre/templates directory.
Template entries are listed in the index file, one template per line,
+as a pipe
separated list of the form:
template label | file name
Template files are assumed to exist in the user's ~/.padre/templates d
+irectory.
Template file information that is stored with the full path/name of th
+e file may
be located anywhere that the user has read access to.
Comment lines start with a '#' and are ignored. Blank lines are also i
+gnored.
=head1 AUTHOR
Gregory Siems E<lt>gsiems@gmail.comE<gt>
=head1 COPYRIGHT AND LICENSE
Copyright (C) 2009 by Gregory Siems
This library is free software; you can redistribute it and/or modify
it under the same terms as Perl itself, either Perl version 5.8.8 or,
at your option, any later version of Perl 5 you may have available.
=cut