タンブラー?

Big Sky

1月 27 '12

Vim scriptはウェブアプリケーション記述言語やったんやー

こんにちわ。昨今、ウェブ開発の進化はすざましいですね。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 = ;
        close($f);
        chomp $server;
        $self->{server} = $server;
    }
    if (!$self->{encoding}) {
        open(my $f, sprintf(“%s —servername %s —remote-expr "&encoding"|”,
            $self->{vim}, $self->{server}));
        my $encoding = ;
        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 = ;
    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

=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を開こう!
やたー!
あとはアプリケーション書き放題ですね!
試しに掲示板書いてみるよ!

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”], [“”
.”“
.”“
.”“
.”コメント:

.”“
.”“
.join(map(copy(s:comments), ’html#encodeEntityReference(v:val)’), ’
‘)
.”“
.”“
\]]
  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 Nout Found”]]
  endif
  return json#encode(res)
endfunction
アプリケーションの更新はVimを再起動するかautoload/vimplack.vimを開いている常態なら :so %
で行けるよ!

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

Vim Application Handler for PSGI https://github.com/mattn/p5-Plack-App-Vim http://j.mp/xQfXtG

1月 25 '12

新言語rustでhello world

やっぱり最初はhello worldって事で…

windowsのインストーラがダウンロード出来なかったのでgithubからダウンロードしてビルドした。
mozilla/rust - GitHub

a safe, concurrent, practical language https://github.com/mozilla/rust ビルドはmingw/msysで./configure && make install。
LLVM上のコンパイラなのでビルドは結構リソースを食う。かなり食う。

ただ単にfizzbuzz出しても面白く無かったのでメッセージボックス出してみた。
use std;
import std::io;

#[abi = ”stdcall”]
native mod user32 {
  fn MessageBoxA(h: ctypes::c_uint,
      message: str::sbuf, title: str::sbuf, flag: ctypes::c_uint)
        -> ctypes::c_uint;
}

fn main() {
  str::as_buf(“hello”, { |message|
    str::as_buf(“world”, { |title|
      user32::MessageBoxA(0u, message, title, 0u);
    })
  })
}
abiとしてcdeclやstdcallが指定出切る。rustcコマンドはuser32に対してちゃんと-luser32というリンクオプションを足してくれるので、コマンドラインでガチャガチャやるイメージはあまりない。
なお、CARGO_ROOTという環境変数にc:/rust/binやc:/rust/libでいう所のc:/rustを指定しておくと、ちゃんとリンカが判断してファイルを探してくれる。
vim編集中に簡単に実行出切る様に、quickrunにもプルリクエストを送っておいた。(マージされた)
#22: support mozilla rust. by mattn for thinca/vim-quickrun - Pull Request - GitHub
https://github.com/thinca/vim-quickrun/pull/22
環境が揃うユーザならば、vimでファイル開いてrとタイプすればメッセージボックスが出る様になります。
所感としては、str::as_bufがブロック式なので、rubyっぽく思えると同時に引数2つの場合めんどくさ過ぎる!と思った。言語というか、仕組み的にはGo言語が近いなーとか思ってたら、Dubheadさんから教えてもらったリンクに既に書いてあった。
Doc language FAQ - GitHub

Have you seen this Google language, Go? How does Rust compare? 面白そうなのでしばらく触ってみる。 http://j.mp/wbRvIw

1リアクション

1月 17 '12

trie_tree書いてみた。

trieなんたらが話題になってたのでなんとなく書いてみた。
ベンチとかはやってない。
404 Blog Not Found:Algorithm - 連想配列の実装としてのハッシュはオワコン?

そのデータ構造は、君の魂を差し出すに足るものかい? 連想配列( Associative array )がコレクション( Collection )、すなわち数多のデータ構造をまとめるデータ構造としての覇… http://blog.livedoor.jp/dankogai/archives/51765855.html #include 
#include 

typedef struct _trie {
  char c;
  unsigned int n;
  struct _trie** next;
  void* value;
} trie;

trie*
trie_new() {
  trie* p = (trie*) malloc(sizeof(trie));
  p->c = 0;
  p->n = 0;
  p->next = NULL;
  return p;
}

void
trie_free(trie* p) {
  unsigned int i;
  for (i = 0; i n; i++)
    trie_free(p->next[i]);
  if (p->n)
    free(p->next);
  free(p);
}

trie*
trie_put(trie* p, const char* key, const void* value) {
  if (*key == 0) {
    p->value = (void*) value;
    return p;
  }
  trie* next = NULL;
  int i;
  for (i = 0; i n; i++)
    if (p->next[i]->c == *key) {
      next = p;
      break;
    }
  if (!next) {
    if (!(next = trie_new())) return NULL;
    trie** children = (trie**) realloc(p->next, p->n * sizeof(trie*));
    if (!children) return NULL;
    p->next = children;

    next->c = *key;
    p->next[p->n] = next;
    p->n++;
  }
  return trie_put(next, key+1, value);
}

trie*
trie_get(trie* p, const char* key) {
  if (p->c) {
    if (p->c != *key)
      return NULL;
    if (p->c == *key && *(key+1) == 0)
      return p;
    key++;
  }
  int i;
  trie* value = NULL;
  for (i = 0; i n; i++) {
    if ((value = trie_get(p->next[i], key)))
      return value;
  }
  return NULL;
}

void
safe_puts(const char* key, const trie* p) {
  if (!p)
    printf(“%s not found\n”, key);
  else if (!p->value)
    printf(“%s: null\n”, key);
  else
    printf(“%s: %s\n”, key, (char*) p->value);
}

int
main(int argc, char* argv[]) {
  trie* p = trie_new();
  trie* v;

  trie_put(p, ”foo”, ”bar”);
  trie_put(p, ”bar”, ”baz”);

  v = trie_get(p, ”baz”);
  safe_puts(“baz”, v);

  v = trie_get(p, ”foo”);
  safe_puts(“foo”, v);

  v = trie_get(p, ”bar”);
  safe_puts(“bar”, v);

  trie_put(p, ”うんこ”, ”うんこっこー”);
  v = trie_get(p, ”うんこ”);
  safe_puts(“うんこ”, v);

  v = trie_get(p, ”404 blog”);
  safe_puts(“404 blog”, v);

  trie_free(p);
  return 0;
}
baz not found
foo: bar
bar: baz
うんこ: うんこっこー
404 blog not found http://j.mp/wwX68x

1月 14 '12

Lingr Radar For Linuxってのを書いた

といっても2ヶ月程前の話なんだけど。 mattn/lingr-radar-linux - GitHub

notify messages in lingr. should be work well for linux/windows https://github.com/mattn/lingr-radar-linux ujihisaさんに「ちゃんと動いた」ぽい様な事を報告してもらって、そう言えば紹介してなかったなーと思ったので。
要はオフィシャルが提供しているLingr Radar For MacのLinux版。pythonで書かれています。
Lingr Tools
http://radar.lingr.com/ 動作にはyoshioriさんのpyLingrとpit、gntpが必要。pyLingrはpipなんかでは入らないので手作業が必要。
yoshiori/pyLingr - GitHub
https://github.com/yoshiori/pyLingr リポジトリ内のpylingr.pyをlingr-radar.pyと同じディレクトリに置いて動かせばOK。
pitとgntpはpipなんかで入れる。
起動するとlingrのユーザとパスワードを求められるのでエディタで編集して保存、終了。参加しているルームの通知がGNTPプロトコルのGrowlに通知される。linuxだとgrowl-for-linuxで可能。

mattn/growl-for-linux @ GitHub

Introduction: Growl For Linux is Linux-compatible of Growl. Growl is a notification system for Mac O… http://mattn.github.com/growl-for-linux/ ちなみにどれもwindowsで動作するのでGrowl For Windows入れてる人やgrowl-for-linuxをwindowsでビルド出来る人はwindowsでも実現可能。
よかったらどうぞ。 http://j.mp/xnAFvv

1月 13 '12

ご近所さんから頂いたカレーは高確率で自分の好みの味付けではない。

not enough memory - Pathが新しくなってちょっと盛り上がってたとき、10人くらいしかともだちいないときちょっと楽しいと思…

っていうので思い出した。前に書いたfacebookでunsunscribeしていく話とセット。あなた自身に興味があって、だからなんだってゴミにはならないよ(すばらしいソーシャルネットワーク)、と、あなたのリブログに興味がある(そうするとあなたにも興味を持つよね)のふたつだ。

居心地のいい場所というのは人それぞれだし、共感してもらう様な物ではない。

お気に入りのカフェテラスの窓際の席、これは一つしかない。そこに行きたくなる人が大勢いたらそれは自分にとって都合が悪い。

出来るならば皆に知られずにいたいよね。

随分前から僕はtwitterのfollower申請については単純なバッチ処理化する様になった。実際は手作業で、怪しげでなさそうな日本人か知ってる海外の人しかfollowしない事にした。

でも僕はホームタイムラインは見ていない。いつものお気に入りのリストしか見なくなった。

Web2.0だとかAPIだとか言われ始めた頃に、これからの情報はプッシュ型配信だと言われ始めたけど、ある意味それは押し付けに成り得てしまい、自分のペースを乱される。

最近になって、僕が求めていたのはプッシュという名のプルなんだと気付き始めた。

FacebookやTwitterにトラブルが多いのも、飲酒運転を大衆に露呈するバカが多いのも、皆自分の情報が一定のfollowerからプルされている物だと思ってるからなんだろうな。実際には大衆に向けてプッシュされていて、自分が思っているよりも誰かの目にとまりやすい。

followされたからといって共感されていると思うのはとても危険だし、ご近所さんから頂くカレーの味付けは高確率で自分の好みの味付けではなかったりする。

1月 13 '12

367リアクション (via ku)

1月 13 '12

勝手に添削 - strncpyの罠

まぁソート関数自身の問題じゃないので控えめに。

strncpyは必ず \0 で埋めてくれるとは限らない。 404 Blog Not Found:algorithm - bucketsort.[ch] - 汎用かつlibcの*sortより高速な

dankogai/c-bucketsort - GitHub http://blog.livedoor.jp/dankogai/archives/51764911.html dankogai/c-bucketsort - GitHub

bucketsort - bucket sort that can be used for general purpose https://github.com/dankogai/c-bucketsort strncpy(3)のmanページにはこう書いてある。

The strcpy() function copies the string pointed to by src, including the terminating null byte (‘\0’), to the buffer pointed to by dest. The strings may not overlap, and the destination string dest must be large enough to receive the copy.

The strncpy() function is similar, except that at most n bytes of src are copied. _Warning: If there is no null byte among the first n bytes of src, the string placed in dest will not be null-terminated._ なので… # ./bucketsort README とかするとNULストップしてないバッファで画面が賑やかになり、時にはけたたましいビープ音で心躍る。

サンプルプログラムの仕様が最終行の改行コードなしでも動く様にすべきなのかどうなのかが分からないので diff —git a/main.c b/main.c
index 67e4e00..48391b4 100644
—- a/main.c
+++ b/main.c
@@ -74,6 +74,7 @@ int main(int argc, char **argv)
        if (!lines[lcur])
            EXIT(“malloc failed”);
        strncpy(lines[lcur], buf, slen - 1);    // do not copy \n
+       lines[lcur][slen - 1] = 0;
     }
     size_t i;
     // for (i = 0; i

1月 10 '12

HaskellでGUI

WXやCocoaもあるみたいなんですが、Gtk慣れてるのもあるのでGtkで。
以前から、memcachedに対して簡単なコマンドをやり取りできるGUIクライアントを各言語でやってみようという一人プロジェクトをやっているのだけど、haskellって触った事が殆ど無かったのでやってみた。
module Main (Main.main) where

import Text.Regex
import Graphics.UI.Gtk as Gtk
import Network.Memcache
import Network.Memcache.Protocol
 
main :: IO ()
main = do
  server  textBufferInsert buf end ”ERROR\n”
        ”delete” -> do
          let
            key = (tt !! 1)
          r  textBufferInsert buf end ”OK\n”
            False -> textBufferInsert buf end ”ERROR\n”
    else
      textBufferInsert buf end ”Unknown command\n”
    Gtk.entrySetText entry ”“

  Gtk.boxPackEnd vbox entry Gtk.PackNatural 0
  Gtk.set window [ containerChild := vbox ]
  Gtk.windowSetDefaultSize window 400 300
  Gtk.widgetShowAll window
  Gtk.widgetGrabFocus entry

  Gtk.mainGUI

— vim: set et ts=2:
むむむー。haskell難しい。
なぜif-thenにelseが必須なのか、何故他の言語の変数というものに近い物が存在しないのか、Justってなんだよコノヤロ、gtk2hsのAPIがGTKっぽくないよ!とかいろいろ… http://j.mp/y4NKfW

1月 4 '12

Vimで書初め

まず中平さんの 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 = (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 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(100, 50)
let font = paint#bdf#loadfile(globpath(&rtp, ’font/unifont/unifont-5.1.20080820.bdf’))
let text = ”あけまして”
call canvas.draw_text(text, [10, 20], font, [0, 0, 0])
let text = ”おめでとう”
call canvas.draw_text(text, [10, 40], font, [0, 0, 0])

call canvas.save(‘kakizome.bmp’)
出来上がり ちなみに画像ファイル出力までに5分くらいかかります。 http://j.mp/wDPSbc

1月 4 '12

Vimと包丁

僕がサクラエディタから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を使い続けるだろう。

なぜなら、僕が作った料理を見て「ここの料理は他のお店と違うわ。」と思ってもらえる事に最大の喜びを感じるからだ。 http://j.mp/wCI6wS

1リアクション

12月 28 '11

意外と知られていない便利なvimプラグイン「ctrlp.vim」

この記事は、Vim Advent Calendar 2011の記事です。欠番が出そうだったので、勝手ながら割り込ませて頂きます。

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するのが良いでしょう。
起動するにはその名の通り をタイプします。すると画面下部にファイル一覧が表示されるのが分かると思います。初回は検索とキャッシュに時間が掛かりますが、次回起動時にはそのキャッシュを使って高速に起動します。
さて何か文字を打ってみて下さい。文字を打つごとにファイルが絞り込まれているのが分かるかと思います。
この文字は連続していなくても構いません。例えば /foo/bar/baz
/foo/bar/bar
この様なファイルが一覧されている場合に > fooz とタイプすると /foo/bar/baz
に絞り込まれます。候補を選ぶには と で移動出来ます。絞り込まれたらエンターキーを押してファイルを開きます。恐らく開発で使用する場合、同名のファイルで拡張子のみが異なる事が多いかと思います。C++であればソースとヘッダ、あるフォルダ配下にあるcssファイル、バージョン番号が付いたファイルなど人間がおおよそ見当の付く入力を行えば自然とファイルがマッチするという良くできた検索になっています。

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

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

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

さて、例えば日本語のファイルにマッチしたくなったとしたらどうしたいですか?
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 を起動して、 をタイプして正規表現モードにスィッチします。通常であればここに正規表現パターンを入力するのですが、ここに kanji の様にmigemoのクエリを入力出来ます。クエリは空白文字列で分割出来るので、例えば ore kyuuyo とタイプすると 「俺の給与明細.xls」をマッチさせる事が出来ます。

これさえあれば、仕事中に給与明細をvimで開く事が出来ますね! http://j.mp/vbVRUD

4リアクション

12月 26 '11

Merry Christmas

ちょっと遅れたけど。
scriptencoding utf-8

let s:seed = 0
function! s:srand(seed)
  let s:seed = a:seed
endfunction

function! s:rand()
  let s:seed = s:seed * 214013 + 2531011
  return (s:seed  http://j.mp/uktPHP

1リアクション

12月 22 '11

僕たちプログラマーは、Excelファイルの生成に、Vimを使います。

# vim Vimを起動して

 
 

XMLを書いて

 
  タカッ
  トラッ
  バッタッ
 

データを足して

 
  タカッ
  トラッ
  バッタッ
 

Visual選択してzencoding-vimでラップする。(“CTRL-Y” and “,”) Tag: Table>Row>Cell*>Data[ss:Type=String]

 
  
    
        
            タカッ
        
        
            トラッ
        
        
            バッタッ
        
    
  

後は :w Book1.xls 出来上がり。 http://j.mp/trCg07

12月 16 '11

サラリーマンの為のメールが2倍速く書ける(気がする)vim補完書いた

そんな餌に俺様が釣られクマー… @kaoriya

@mattn_jp あきらかにまっつんさんがvim用の記事を書く流れwww
http://twitter.com/hasegawayosuke/statuses/147123761429217280 サラリーマンの為のメールが2倍速く書ける(気がする)辞書 : ライブドア社長ブログ

お疲れ様です。こちら弊社代表取締役社長、出澤のブログでございますが、出澤の執筆ペースが芳しくないので、本日も社員のスエヒロが「会社」や「社長」について代打で書かせて頂きたいと思います。流し打ちの気持ち… http://blog.idezawa.info/archives/51725271.html Vimのオムニ補完は最高!
:set omnifunc=salaryman#Complete
こう設定すると この状態からCTRL-X CTRL-Oをタイプすると… おぉぉぉ…
さらに… こんな事も 出来る!!!1

日本語禁則処理も入ってるので多い日も安心!

どうぞご利用下さい!
mattn/salaryman-complete-vim - GitHub

サラリーマンの為のメールが2倍速く書ける(気がする)vim補完 https://github.com/mattn/salaryman-complete-vim http://j.mp/sptx65

1リアクション

12月 15 '11

1リアクション