Плагин к vi для написания в WordPress

Эта запись будет обновляться по мере улучшения плагина. Плагин добавляет в vi семейство команд WP*. На данный момент это команды WPBlogs и WPPostSend. WPBlogs выводит на экран список блогов, известных плагину. WPPostSend отсылает в блог написанное на экране сообщение.
command! -nargs=0 WPBlogs exec("perl wordpress_blogs()")
command! -nargs=0 WPPostSend exec("perl wordpress_send_post()")
"command! -nargs=0 BlogNew exec("py blog_new_post()")
"command! -nargs=0 BlogSend exec("py blog_send_post()")
"command! -nargs=1 BlogOpen exec('py blog_open_post(<f-args>)')

perl <<EOF

use strict;
use warnings;
use FindBin;
use lib "$FindBin::Bin/.";
use encoding 'utf8', STDOUT => 'cp1251';


use Carp;
use XMLRPC::Lite;

my %blogs= (
            'kergma' => {
	                 'name' => 'КергмологияЏ',
	                 'url' =>  'http://kergma.net/xmlrpc.php',
                         'login' => 'admin',
                         'password' => 'unknown'
	                }
);

my $current_blog;

sub omni
{
 my $blog = shift;
 my $first_param=shift;
 my $remote_name_function=shift;
 my $our_name_function=shift;
 my @args=@_;

 my $call = XMLRPC::Lite->proxy( $blogs{$blog}{'url'} )->call(
        'metaWeblog.' . $remote_name_function,
        $first_param,                              # blogid, ignored
        $blogs{$blog}{'login'},
        $blogs{$blog}{'password'},
	@args
    );
 $call->fault and croak "$our_name_function: " , $call->faultstring;
 return $call;
}

sub wordpress_blogs
{
 my $curbuf=$main::curbuf;
 VIM::SetOption("enc=utf-8");
 VIM::DoCommand('%d');

 my @list;
 foreach my $blog (keys %blogs)
  {
   push @list,"[$blog]\t$blogs{$blog}{name}";
  }
 $curbuf->Append(1, @list);     # appends a line
 VIM::SetOption("nomodified");
 VIM::DoCommand('map <buffer> <enter> :perl wordpress_recent_posts()<cr>');
}


sub get_categories {

   my $blog = shift;
   my $call=omni($blog,1,"getCategories","getCategories");
   my @categories;
   push @categories, $_->{ categoryName } for @{ $call->result };
   return \@categories;
}


sub wordpress_recent_posts
{
 my ($row,$col)=$main::curwin->Cursor();
 my $curbuf=$main::curwin->Buffer();
 my $current_line=$curbuf->Get($row);
 $current_line =~ m/\[(\w+)\]/;
 my $blog=$1;
 if(!defined $blogs{$blog})
  {
   wordpress_blogs();
  }
 else
  {
   $current_blog=$blog;
   show_recent_posts();
  }
}

sub show_recent_posts
{
 my $curbuf=$main::curwin->Buffer();
 $curbuf->Delete(1 .. $curbuf->Count());
 VIM::DoCommand('%d');
 my $call=omni($current_blog,1,"getRecentPosts","get_recent_posts",15);
 my @list;
 push @list,"[$current_blog]\t$blogs{$current_blog}{name}";
 push @list,("");
 push @list,("[0]\tДобавить записьЊ");
 push @list,("");
 push @list,"[$_->{postid}]\t$_->{'title'}" foreach @{$call->result};

 $curbuf->Append(1, @list);     # appends a line
 $main::curwin->Cursor(4,10);
 VIM::SetOption("nomodified");
 VIM::DoCommand('map <buffer> <enter> :perl wordpress_edit_post()<cr>');
}


sub wordpress_edit_post
{
 my ($row,$col)=$main::curwin->Cursor();
 my $curbuf=$main::curwin->Buffer();
 my $current_line=$curbuf->Get($row);
 $current_line =~ m/\[(\d+)\]/;
 my $postid=$1;
 $curbuf->Delete(1 .. $curbuf->Count());
 if($postid==0)
  {
   wordpress_new_post();
  }
 else
  {
   wordpress_open_post($postid);
  }
}


sub wordpress_new_post
{
 my ($row,$col)=$main::curwin->Cursor();
 my $curbuf=$main::curwin->Buffer();
 $curbuf->Delete(1 .. 10);
 my @list;
 push @list, "=========== Meta ============";
 push @list,"Categs : " . join (",",@{get_categories($current_blog)});
 push @list,"Title  :  ";
 push @list,"========== Content ==========";
 push @list,"";


 VIM::DoCommand('%d');
 $curbuf->Append(0, @list);     # appends a line
 $main::curwin->Cursor(4,10);
 VIM::SetOption("nomodified");
 VIM::DoCommand('map <buffer> <enter> :perl wordpress_edit_post()<cr>');
}


sub wordpress_open_post
{
 my $postid=shift;

 my $call=omni($current_blog,$postid,"getPost","get_recent_posts",15);
 $call=$call->result;
 my @list;
 push @list, "=========== Meta ============";
 push @list,"StrID  : " . $call->{'postid'} ;
 push @list,"Categs : " . join (", ",@{$call->{'categories'}}) ;
 push @list,"         (" . join (",",@{get_categories($current_blog)}) . ")";
 push @list,"Title  : " . $call->{'title'};
 push @list,"========== Content ==========";
 push @list,"";

 push @list,split("\n",$call->{'description'});

 my $curbuf=$main::curwin->Buffer();
 VIM::DoCommand('%d');
  $curbuf->Append(0, @list);     # appends a line
  $main::curwin->Cursor(4,10);
 VIM::SetOption("nomodified");
 VIM::DoCommand('map <buffer> <enter> :perl wordpress_edit_post()<cr>');
}

sub wordpress_send_post
{
 my $pos=1;
 my $curbuf=$main::curwin->Buffer();
 my %post;
 while(my $str=$curbuf->Get($pos))
  {
   $pos++;
   last if $str =~ m/== Content ==/;
   if($str=~ m/^StrID\s*:\s*(\d*)/)
    {
     $post{postid}=$1;
     next;
    }
   if($str=~ m/^Title\s*:\s*(.*)/)
    {
     $post{title}=$1;
     next;
    }
   if($str=~ m/^Categs\s*:\s*(.*)/)
    {

     my @categories=split /\s*?,\s*?/,$1;
     $post{categories}=[@categories];
     next;
    }
  }

  use bytes;
  $post{description}=join ("\n",$curbuf->Get($pos .. $curbuf->Count()));
  no bytes;

  if(!exists $post{postid} || $post{postid} !~ /^\d+$/)
   {
    my $call=omni($current_blog,1,"newPost","get_recent_posts",
                                      {
				       'title'=>$post{'title'},
				       'description'=>$post{'description'},
				       'categories'=>$post{'categories'},
				      },
				      1);
   }
  elsif($post{postid} =~ /^\d+$/)
   {
    my $call=omni($current_blog,$post{postid},"editPost","get_recent_posts",
                                      {
				       'title'=>$post{'title'},
				       'description'=>$post{'description'},
				       'categories'=>$post{'categories'},
				      },
				      1);
   }

 show_recent_posts();

}