2012/02/01

Recent entries from same category

  1. VimConf 2023 Tiny に参加しました
  2. Vim で Go 言語を書くために行った引越し作業 2020年度版
  3. Vim をモダンな IDE に変える LSP の設定
  4. ぼくがかんがえたさいきょうの Vim のこうせい 2019年 年末版
  5. VimConf 2019 を終えて

こんにちわ。昨今、ウェブ開発の進化はすざましいですね。PythonやPerlやJava、色んな言語で書かれていると思います。
もちろん編集にはVimを使っているかと思います。
でも編集だけ?

違うよね!
Vim scriptはウェブアプリケーション記述言語なんだよ!

Plack::App::Vim
package Plack::App::Vim;
use strict;
use warnings;
use parent qw/Plack::Component/;
use Plack::Request;
use Encode;
use JSON::PP;

sub prepare_app {
    my $self = shift;
    $self->{vim} ||= 'vim';
    if (!$self->{server}) {
        open(my $f"vim --serverlist|");
        my $server = <$f>;
        close($f);
        chomp $server;
        $self->{server} = $server;
    }
    if (!$self->{encoding}) {
        open(my $fsprintf("%s --servername %s --remote-expr \"&encoding\"|",
            $self->{vim}$self->{server}));
        my $encoding = <$f>;
        close($f);
        chomp $encoding;
        $self->{encoding} = $encoding;
    }
    $self;
}

sub call {
    my ($self$env) = @_;
    my $req = Plack::Request->new($env);
    my $json = JSON::PP->new->ascii
        ->allow_singlequote->allow_blessed->allow_nonref;
    my $str = $json->encode({
        uri => $env->{PATH_INFO}||'',
        method => $req->method,
        headers => [split/\n/$req->headers->as_string)],
        content => $req->content,
    });
    $str =~ s!"!\\x22!g;

    my $command;
    if ($^O eq 'MSWin32') {
        $command = sprintf(
            '%s --servername %s --remote-expr "vimplack#handle("""%s""")"',
            $self->{vim}$self->{server},
            encode($self->{encoding} || 'utf8'$str));
    } else {
        $command = sprintf(
            "%s --servername %s --remote-expr 'vimplack#handle(\"%s\")'",
            $self->{vim}$self->{server},
            encode($self->{encoding} || 'utf8'$str));
    }
    open(my $f"$command|");
    binmode $f':utf8';
    my $out = <$f>;
    close $f;
    my $res = $json->decode($out);
    $res->[2][0] = encode_utf8 $res->[2][0] if $res;
    $res || [500, ['Content-Type' => 'text/plain'], ['Internal Server Error']];
}

1;

__END__

=head1 NAME

Plack::App::Vim - The Vim App in Plack

=head1 SYNOPSIS

  use Plack::Builder;
  use Plack::App::Vim;

  builder {
    mount "/" => Plack::App::Vim->new(server => 'VIM');
  };

=head1 DESCRIPTION

Plack::App::Vim allows you to write web application with Vim script.

=head1 AUTHOR

Yasuhiro Matsumoto

=head1 SEE ALSO

L<Plack>

=cut
Plack::Appのアプリケーションハンドラを書いたよ。これを起動するpsgiファイルを用意するよ!

app.psgi
#!perl
use lib qw/lib/;
use Plack::Builder;
use Plack::App::Vim;

builder {
    mount "/" => Plack::App::Vim->new(server => 'VIM');
};
引数のserverにはclientserver機能が使えるVimを立ち上げ、そのサーバIDを指定しておく必要があるよ!
そしてVim側にハンドラを書くよ!

autoload/vimplack.vim
scriptencoding utf-8

function! vimplack#handle(req)
  let req = json#decode(a:req)
  let res = [200, {}, ["hello world"]]
  return json#encode(res)
endfunction
PSGIプロトコルそのままですね!便利!

起動しよう!
# plackup app.psgi
HTTP::Server::PSGI: Accepting connections at http://0:5000/
ブラウザでhttp://localhost:5000を開こう!
Vim on PSGI
やたー!
あとはアプリケーション書き放題ですね!
試しに掲示板書いてみるよ!

autoload/vimplack.vim
scriptencoding utf-8

let s:comments = get(s:, 'comments', [])

function! vimplack#handle(req)
  let req = json#decode(a:req)
  if req.uri == "/"
    let res = [200{"Content-Type""text/html; charset=utf-8"}, [""
\."<html>"
\."<link rel='shortcut icon' href='/static/favicon.ico'>"
\."<title>comment board</title>"
\."<body>"
\."<form action='/regist' method='post'>"
\."コメント:<input type='text' name='comment' value='' /><br />"
\."<input type='submit' value='登録' />"
\."</form>"
\.join(map(copy(s:comments)'html#encodeEntityReference(v:val)')'<br />')
\."</body>"
\."</html>"
\]]
  elseif req.uri == '/regist' && req.method == 'POST'
    let params = {}
    for _ in map(split(req.content, '&')'split(v:val,"=")')
      let params[_[0]] = iconv(http#decodeURI(_[1])'utf-8', &encoding)
    endfor
    if has_key(params, 'comment')
      call add(s:comments, params['comment'])
    endif
    let res = [302{"Location""/"}, [""]]
  else
    let res = [404{}, ["404 Dan Not Found"]]
  endif
  return json#encode(res)
endfunction
アプリケーションの更新はVimを再起動するかautoload/vimplack.vimを開いている常態なら :so %
で行けるよ!
Vim on PSGI

知らんかったー
Vim scriptはウェブアプリケーション記述言語やったんやー
mattn/p5-Plack-App-Vim - GitHub

Vim Application Handler for PSGI

https://github.com/mattn/p5-Plack-App-Vim
Posted at by