Fork me on GitHub

2012/01/27


このエントリーをはてなブックマークに追加
こんにちわ。昨今、ウェブ開発の進化はすざましいですね。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 21:00 in ソフトウェア::vim
Tagged as: plack, vim
Bookmarks: add to hatena add to hatena | add to delicious.com | add to livedoor.clip add to livedoor.clip

2012/01/04


このエントリーをはてなブックマークに追加
まず中平さんの vim-paint をインストール。
ynkdir/vim-paint - GitHub
https://github.com/ynkdir/vim-paint
このままだと日本語出せないのでパッチを当てる。
diff --git a/autoload/paint/bdf.vim b/autoload/paint/bdf.vim
index 8485995..e8323b8 100644
--- a/autoload/paint/bdf.vim
+++ b/autoload/paint/bdf.vim
@@ -139,6 +139,98 @@ let s:font.hexbits = [
       \ [1, 1, 1, 1],
       \ ]
 
+let s:utf8len = [
+\ 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,
+\ 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,
+\ 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,
+\ 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,
+\ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+\ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+\ 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,
+\ 3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,4,4,4,4,4,4,4,4,5,5,5,5,6,6,0,0,
+\]
+
+function! s:dec2bin(v)
+  let v = a:v
+  if v == 0 | return 0 | endif
+  let ret = ""
+  while v > 0
+    let i = v % 2
+    let ret = i . ret
+    let v = v / 2
+  endwhile
+  return ret
+endfunction
+
+function! s:bin2dec(v)
+  let v = a:v
+  if len(v) == 0 | return 0 | endif
+  let i = 1
+  let ret = ""
+  for n in reverse(split(v, '\zs'))
+    if n == 1
+      let ret = ret + i
+    endif
+    let i = i * 2
+  endfor
+  return ret
+endfunction
+
+function! s:bitshift(a,b)
+  let a = s:dec2bin(a:a)
+  let a = repeat('0', 32-len(a)) . a
+  if a:b < 0
+    let a = (repeat('0', -a:b) . a[: a:b-1])[-32:]
+  elseif a:b > 0
+    let a = (a . repeat('0', a:b))[-32:]
+  endif
+  return s:bin2dec(a)
+endfunction
+
+function! s:bitand(a,b)
+  let a = s:dec2bin(a:a)
+  let b = s:dec2bin(a:b)
+  return s:bin2dec(tr((a + b), '21', '10'))
+endfunction
+
+function! s:byte2code(byte)
+  let p = a:byte
+  let n0 = char2nr(p[0])
+  if n0 < 0x80
+    return n0
+  endif
+  let l = s:utf8len[n0]
+  let n1 = char2nr(p[1])
+  if l > 1 && s:bitand(n1, 0xc0) == 0x80
+    if l == 2
+      return s:bitshift(s:bitand(n0, 0x1f), 6) + s:bitand(n1, 0x3f)
+    endif
+    let n2 = char2nr(p[2])
+    if s:bitand(n2, 0xc0) == 0x80
+      if l == 3
+        return s:bitshift(s:bitand(n0, 0x0f), 12) + s:bitshift(s:bitand(n1, 0x3f), 6) + s:bitand(n2, 0x3f)
+      endif
+      let n3 = char2nr(p[3])
+      if s:bitand(n3, 0xc0) == 0x80
+        if l == 4
+          return s:bitshift(s:bitand(n0, 0x07), 18) + s:bitshift(s:bitand(n1, 0x3f), 12) + s:bitshift(s:bitand(n2, 0x3f), 6) + s:bitand(n3, 0x3f)
+        endif
+        let n4 = char2nr(p[4])
+        if s:bitand(n4, 0xc0) == 0x80
+          if (l == 5)
+            return s:bitshift(s:bitand(n0, 0x03), 24) + s:bitshift(s:bitand(n1, 0x3f), 18) + s:bitshift(s:bitand(n2, 0x3f), 12) + s:bitshift(s:bitand(n3 & 0x3f), 6) + s:bitand(n4, 0x3f)
+          endif
+          let n5 = char2nr(p[5])
+          if s:bitand(n5, 0xc0) == 0x80 && l == 6
+            return s:bitshift(s:bitand(n0, 0x01), 30) + s:bitshift(s:bitand(n1, 0x3f), 24) + s:bitshift(s:bitand(n2, 0x3f), 18) + s:bitshift(s:bitand(n3, 0x3f), 12) + s:bitshift(s:bitand(n4, 0x3f), 6) + s:bitand(n5, 0x3f)
+          endif
+        endif
+      endif
+    endif
+  endif
+  return n0
+endfunction
+
 "
 " |hello, world
 " +------------
@@ -146,7 +238,8 @@ let s:font.hexbits = [
 " origin
 function s:font.draw_text(canvas, text, org, color)
   let [ox, oy] = a:org
-  for c in map(split(a:text, '\zs'), 'char2nr(v:val)')
+  for c in map(split(a:text, '\zs'), 's:byte2code(iconv(v:val, &encoding, "utf-8"))')
+    call garbagecollect()
     if !has_key(self.glyphs, c)
       let c = self.default_char
     endif
ビットシフト関数は結構適当。最新のvimならbitwize関数が入ってるはずなので、そっちを使った方が良い。さらにunifontからbdfフォントを貰ってくる。
GNU Unifont Glyphs

This page contains the latest release of the GNU Unifont, with glyphs for every printable code point...

http://unifoundry.com/unifont.html
そしてコード
scriptencoding utf-8
let canvas = paint#canvas#new(10050)
let font = paint#bdf#loadfile(globpath(&rtp, 'font/unifont/unifont-5.1.20080820.bdf'))
let text = "あけまして"
call canvas.draw_text(text, [1020], font, [000])
let text = "おめでとう"
call canvas.draw_text(text, [1040], font, [000])

call canvas.save('kakizome.bmp')
出来上がり
vim-de-kakizome
ちなみに画像ファイル出力までに5分くらいかかります。
Posted at 14:00 in ソフトウェア::vim
Tagged as: vim
Bookmarks: add to hatena add to hatena | add to delicious.com | add to livedoor.clip add to livedoor.clip


このエントリーをはてなブックマークに追加
僕がサクラエディタからVimに乗り換えるまで - ITは芸術だ

僕がサクラエディタからVimに乗り換えるまで エディタ はじめに 恐怖のエディタ、Vim。 僕はこの間までずっとサクラエディタを愛用していましたが、最近 Vim を使うようになりました。 ええ、Vim...

http://d.hatena.ne.jp/JunichiIto/20120101/1325420213
Vimテクニックバイブルの著者略歴でも書いたけど、僕は「生涯Vimを使う」と決めた。僕のブログを読んでくれている人なら、だいたいの人は僕がVimを使っているのは知ってると思うけど、今日は「なぜ僕がVimを選んでいるのか」を書こうと思う。
こんな僕だけど、Vim以外が使えない訳じゃない。PCにVim以外のテキストエディタが入ってない訳でもない。Emacsも一応は使える。もちろんEmacsもxyzzyもsakuraエディタも秀丸もTeraPadもK2Editorも、他ありとあらゆるテキストエディタもインストールしてあって常時起動出来る様にしてある。
それらを完全にマスターしている訳じゃないけど、個々の特徴は知ってるつもり。なぜインストールしているのかというと、Vimを一生使い続ける為にVimに足りない物を探す為。

なぜVimを使っていると玄人っぽく見えるのか

Vimを取り上げられてよく言われるのが、「なぜEclipseやVisual Studioの様なIDEを使わないのか」。これは都度出てくる話題で、その度に盛り上がる。
そして毎回僕はこう言ってる。
Vim等のテキストエディタは言うなれば板前が使う包丁。そしてIDEはフードプロセッサ。
野菜をみじん切りにしたり、一定の薄さでスライスするのにはIDEはとても便利だし、それを使う価値は十分にある。逆にVim使いが玄人っぽく見えるのはそのせいで、包丁で大根の桂剥きをする様は誰が見ても玄人であって、IDEは初心者にとっての敷居が低い。野菜を入れてスイッチ入れればそれ相応の物が出来上がる。「じゃぁIDE使えよ」そう思われる方も多いと思う。しかしIDEでは少し凝った細工や調整が効かない事が多い。いつもは3mmでスライスしていた人参を今日のお客さんだけは2.7mmでスライスしたい。時には波状にスライスしたい。そして花の模様にカットしたい。そんな事もあると思う。IDEでも出来なくないかもしれないけど、その度に違う操作感のプラグインに慣れるのは苦痛にもなりえるし、そこで思考を停止してしまうとせっかく浮かんだアイデアが飛んでいってしまう。できればそこはアイデアの事だけを考えながら操作したいというのがプログラマにとっての本音であろう。
この2.7mmでスライス出切る様になる事がVim使いへの道だろうし、挫折の多い所だろうと思う。「もういいよ3mmで」そう思ってしまうかもしれない。

「板前の包丁めんどくせぇな」そう思われるかも知れないが、それは職人がフードプロセッサだけで料理を作らない理由と同じであろう。

なぜVimを使っていると変態っぽく見えるのか

Vimは言わば包丁だ。フードプロセッサなら使い終わったら水で流して乾かせば良い。しかし包丁は時にはメンテナンスも必要で、定期的に研がなければならなかったり、錆びない様に気を使わなければならなかったりもする。職人はいつも包丁を持ち歩いている。
路上でフードプロセッサを持ち歩いていたらどうだろう。それ程不自然ではないと思う。何かの搬入にも見えるかもしれない。
しかし包丁を持ち歩いていたらどうだろう。弁解しなければ捕まってしまうかもしれない。変人どころか危ない人に見えるかもしれない。事ある毎に大根の桂剥きをする様は、時には自慢に見えるかもしれないし、無駄な作業に見えるかもしれない。

だからと言って、Vimを使える人が玄人であって、一般的なテキストエディタやIDEを使う人が素人と言ってる訳ではない。おそらくいろんな所で書かれているVimの記事にもそういった事は書かれていないと思うし、もしそう書いてあったとしてもアクセス数を稼ぐ為に誇張した表現だと受け取って欲しい。

Vimを知らない人からすればVimは明らかに変だし、無駄な行動が多いように見えるし、面倒臭そうだし、加齢臭がしそうだし、モテなさそうだし、オタクっぽいだろう。IDE使ってる方が「○○先輩教えて下さい><」って可能性は高いだろう。間違っても「えー!ネオコン?なにそれ!? 知りたい知りたーい♪」なんて娘は出てこない。繰り返して言っておく。
そんな娘は現れない
でも僕はVimを使い続けるだろう。

なぜなら、僕が作った料理を見て「ここの料理は他のお店と違うわ。」と思ってもらえる事に最大の喜びを感じるからだ。
Posted at 11:25 in ソフトウェア::vim
Tagged as: vim
Bookmarks: add to hatena add to hatena | add to delicious.com | add to livedoor.clip add to livedoor.clip

2011/12/28


このエントリーをはてなブックマークに追加
この記事は、Vim Advent Calendar 2011の記事です。欠番が出そうだったので、勝手ながら割り込ませて頂きます。

CtrlP.vim Vimを使って開発をする際、リポジトリ内のファイルにどうやってアクセスしていますか?NERDTree?vimshell?unite.vim?FuzzyFinder?

色んな方法があるかと思います。ただこれらは若干古かったりニュアンスが異なっていたり、物によっては開発に向かない物もあります。単純にファイルを選択するのであれば、それで事足りるでしょう。しかしながら本当に開きたいファイルを最短の方法で選ぶには、これまでの方法では時に無駄であったり、余計なお世話だったりもしました。
僕はバッファセレクタやファイルセレクタというのは使わない方なのですが、ちょっと前にこれを見つけて「おっ...よさげなインタフェース」と思った物があったので紹介しようと思います。

ctrlp.vim ÷ home

Full path fuzzy file, buffer and MRU file finder for Vim. » Written in pure Vimscript for MacV...

http://kien.github.com/ctrlp.vim/
ctrlp.vimの特徴は以下の通り。
  • pure vimscriptで書かれている
  • vimの正規表現を使った検索
  • MRU(Most Recently Used)ファイルモニタリングおよび検索
  • ルートディレクトリ検知
  • 複数ファイルの同時オープン
  • ファイルおよびディレクトリの作成
  • 開いているファイル上でのExコマンド実行(行や文字列へジャンプ、もしくは他の動作)
  • キャッシュと履歴を使ったクロスセッションと高速な初期化
  • マッピングとvimとの親和性
インストールは上記サイトのリンクを辿ってgithubの物をgit cloneするのが良いでしょう。
起動するにはその名の通り <c-p> をタイプします。すると画面下部にファイル一覧が表示されるのが分かると思います。初回は検索とキャッシュに時間が掛かりますが、次回起動時にはそのキャッシュを使って高速に起動します。
さて何か文字を打ってみて下さい。文字を打つごとにファイルが絞り込まれているのが分かるかと思います。
この文字は連続していなくても構いません。例えば
/foo/bar/baz
/foo/bar/bar
この様なファイルが一覧されている場合に
> fooz
とタイプすると
/foo/bar/baz
に絞り込まれます。候補を選ぶには <c-h><c-j> で移動出来ます。入力のヒストリは <c-n><c-p> で参照可能。絞り込まれたらエンターキーを押してファイルを開きます。恐らく開発で使用する場合、同名のファイルで拡張子のみが異なる事が多いかと思います。C++であればソースとヘッダ、あるフォルダ配下にあるcssファイル、バージョン番号が付いたファイルなど人間がおおよそ見当の付く入力を行えば自然とファイルがマッチするという良くできた検索になっています。

またgit等VCSリポジトリ上であった場合には検索の範囲がリポジトリ内に限られるという親切な設計になっています。
ですので開発プロジェクトのフォルダの中であればどこにいても目的のファイルを開くこと出来ます。
実行中に <c-r> をタイプすると部分一致検索モードから正規表現検索モードにスイッチします。入力した文字を正規表現パターンとしてファイルを検索出来ます。
もう一度タイプすると通常モードに戻ります。また <c-d> でフルパスモードからファイル名モードへ、<c-f> でMRUファイル検索、<c-b> でバッファ検索へとスイッチ出来ます。
入力欄で / もしくは \ はプロジェクトのルートフォルダに相当し、.. による親フォルダの参照も可能です。

そしてパターンの後ろに : を付与すると、一覧に表示されているファイル群にコマンドを実行する事が出来ます。
abc:45 であればファイル abc の45行目にジャンプ、abc:/my\:function でファイルabc内で見つかる my:function へジャンプします。
任意の複数のファイルを開くには、候補一覧で <c-z> を使ってマークし、<c-o> をタイプします。

これだけあれば、「ファイル一覧→選択→検索開始」というアクションを一度に、しかも複数のファイルに対して行う事が出来ます。

さて、例えば日本語のファイルにマッチしたくなったとしたらどうしたいですか?
ctrlp.vim には日本語ファイル名にマッチ出来る仕組みが入っています。
cmigemo をインストールし、以下の様に vimrc に追記します。
let g:ctrlp_use_migemo = 1
なお、cmigemo の辞書ファイル migemo-dict は以下の位置に配置しておく必要があります。
~/.vim/dict/migemo-dict
もしくは以下の様にエンコーディング毎に格納しても良いです。
~/.vim/dict/utf-8/migemo-dict
ctrlp.vim を起動して、<c-r> をタイプして正規表現モードにスイッチします。通常であればここに正規表現パターンを入力するのですが、ここに
kanji
の様にmigemoのクエリを入力出来ます。クエリは空白文字列で分割出来るので、例えば
ore kyuuyo
とタイプすると
俺の給与明細
「俺の給与明細.xls」をマッチさせる事が出来ます。

これさえあれば、仕事中に給与明細をvimで開く事が出来ますね!
Posted at 02:32 in ソフトウェア::vim
Tagged as: vim
Bookmarks: add to hatena add to hatena | add to delicious.com | add to livedoor.clip add to livedoor.clip