2012/04/27


Vim使ってる人の多くはマウスを触らずキーボードだけで操作する人が多いかと思います。僕もその一人でして、Windows使っていてもマウスは殆ど触りません。 ウィンドウを操作する場合は
目的キー
最大化 ALT + Space & x
ALTキーとスペースキー押した後で x
元のサイズに戻す ALT + Space & r
ALTキーとスペースキー押した後で r
ウィンドウを閉じる ALT + F4
ALTキーとF4
ただし複数のウィンドウを扱うアプリケーションでは CTRLキーとW
こんな感じに。普段コマンドプロンプトで生活しているので
目的キー
コピー ALT + Space & ek
ALTキーとスペースキー押した後で ek
カーソルキーで移動し、シフトキーとカーソルキーで範囲を広げます。選択し終わったらエンターキー
元のサイズに戻す ALT + Space & ep
ALTキーとスペースキー押した後で ep
UNIX系ツールとこういった操作を覚えれば誰でもコマンドプロンプトで生活出来ます。

今日はそんな話じゃなくて、普段Vimを使っていると色んな事をVimから実行したくなってきます。
  • エクスプローラ起動
  • ブラウザ起動
  • TwitVim起動
  • FavStarなんて見ようかしら
その都度、キーマッピングを書いても良いのですが、その度にキーアサインしてるとキーが幾つあっても足りません。あと忘れる事が多い。
そこでランチャー書いてみました。普段リポジトリ内のファイルにアクセスする際、パスが遠いと面倒なので CtrlP(以前書いた紹介記事はこちら) というプラグインを使っているのですが、このプラグインには unite.vim の様に拡張を書ける仕組みがあるのです。 オフィシャルからもバッファや最近触ったファイル(MRU)を選択出来るエクステンションが提供されているのですが、皆さんに紹介の意味も込めて今日適当に何個か作ってみました。
mattn/ctrlp-mark - GitHub
https://github.com/mattn/ctrlp-mark
マーク一覧が表示され、選択するとマークされたファイルの指定位置を開きます。
mattn/ctrlp-register - GitHub
https://github.com/mattn/ctrlp-register
レジスタ一覧が表示され、選択するとレジスタに格納されたテキストをペーストします。「あ、undo中に書き換えて大事な修正消しちゃった...」って時はレジスタに残ってる可能性もあるので便利かもしれません。まぁ普段Vim使ってる人は知ってますよね。

で、横道にそれ過ぎましたが話を戻してランチャーですが
mattn/ctrlp-launcher - GitHub
https://github.com/mattn/ctrlp-launcher
Windowsで動作確認してますが、たぶんUNIXでも動きます。まずこれを起動するキーマッピングを一つ定義して下さい。コマンドは「CtrlPLauncher」になっているので nnoremap <c-e> :<c-u>CtrlPLauncher<cr>
とでも書いておくと良いと思います。起動すると初回は何も出ません。唯一、「--edit-menu--」という候補のみが表示されます。これを選ぶと~/.ctrlp-launcherが開くのでここに以下の様にコマンドを定義します。 # [タイトル(空白含んでOK)] [タブ文字(複数可能] [実行するコマンド]
FavStar             FavStar mattn_jp
Browser             call feedkeys("\<Plug>(openbrowser-open)")
Explorer            !start rundll32 url.dll,FileProtocolHandler .
Command Prompt      !start cmd
System Property     !start c:/windows/system32/control.exe system.cpl
Task Manager        !start taskmgr
Service Manager     !c:/windows/system32/services.msc
Internet Explorer   !start iexplore

# vim:set ts=4
コマンド名と、複数のタブ、実行コマンドのカラムで構成されます。中身は utf-8 で記述する必要があります。先頭が「#」の行は無視されます。
コマンドはVimのコマンドラインで実行出切る物が書けます。なのでTwitVimのコマンドや、他のCtrlPエクステンションの実行にも使えます。
例えばキーを送りたいなら normal コマンドを書いても良いですしfeedkeysを使って URLを開く    call feedkeys(":OpenBrowser ")
コマンドラインの途中入力みたいな事も出来ます。このファイルは毎回読みに行くのでコマンド定義ファイルを書き換える度に再起動する必要はありません。僕の環境では CTRL + E で定義したので、CtrlE って呼んでます(うそです呼んでません)。
起動するとこんな感じになります。
CtrlE
CtrlPはマルチバイト文字が入力出来ないので様は良いですが絞り込み出来ないのでやらない方が良いです。

何か文字を打てば絞り込まれますし、CTRL+J と CTRL+K で上下に移動も出来ます。エンターキーを押すと対応したコマンドが実行されます。

やりたい事が多いのに、キーがバッティングし過ぎて困る人は便利かもしれません。良かったらどうぞ。
Posted at by



2012/04/26


ここ数日、mrubyの拡張を書いてた訳ですが。
mattn/mruby-uv - GitHub

interface to libuv for mruby(experimental)

https://github.com/mattn/mruby-uv
mattn/mruby-http - GitHub

interface to http for mruby(experimental)

https://github.com/mattn/mruby-http
これを使って #include <mruby/proc.h>
#include <mruby/data.h>
#include <compile.h>
#include <mrb_uv.h>
#include <mrb_http.h>

#define _(...) #__VA_ARGS__ "\n"

int
main()
{
  int n;
  mrb_state* mrb;
  struct mrb_parser_state* st;
  char* code =
 _(
)_( require 'UV'
)_( require 'HTTP'
)_(
)_( s = UV::TCP.new()
)_( s.bind(UV::ip4_addr('127.0.0.1', 8888))
)_( cl = []
)_( s.listen(5) {|x|
)_(   return if x != 0
)_(   c = s.accept()
)_(   cl << c
)_(   c.read_start {|b|
)_(     r = HTTP::parse_http_request(b)
)_(     c.write("HTTP/1.1 200 OK\r\nHost: example.com\r\n\r\nhello #{r['PATH_INFO']}") {|x|
)_(       c.close()
)_(     }
)_(   }
)_( }
)_( UV::run()
);

  mrb = mrb_open();
  mrb_uv_init(mrb);
  mrb_http_init(mrb);
  st = mrb_parse_string(mrb, code);
  n = mrb_generate_code(mrb, st->tree);
  mrb_pool_close(st->pool);
  mrb_run(mrb, mrb_proc_new(mrb, mrb->irep[n]), mrb_nil_value());
  return 0;
}
こんなのが動く様になりました。これでデバイス上で、しかもrubyによるWebサーバが動く日も遠くなくなりました。便器にJSONRPCを送ってウォシュレットが動く!なんて事も夢では無くなって来ましたね!

mruby はじまったな!
Posted at by



2012/04/20


C言語の構造体をラップする方法が分からなかった(rubyでいうData_Wrap_Structが見当たらなかった)のでissueに書いた僕と名前の良く似た方matzさんが音速で入れてくれた。
ただrubyの時の様にalloc_funcが無いのでinitializeでメンバに放り込んでる。
まぁしょうがないか。
#include <mruby.h>
#include <mruby/proc.h>
#include <mruby/data.h>
#include <compile.h>
#include <variable.h>
#include <uv.h>

typedef struct {
  mrb_state* mrb;
  mrb_value proc;
  void* data;
} mrb_uv_data;

static void
uv_handle_free(mrb_state *mrb, void *p)
{
  uv_close((uv_handle_t*) ((mrb_uv_data*)p)->data, NULL);
  free(((mrb_uv_data*)p)->data);
}

static const struct mrb_data_type uv_handle_data_type = {
  "uv_handle", uv_handle_free,
};

static mrb_value
mrb_uv_run(mrb_state *mrb, mrb_value self)
{
  return mrb_fixnum_value(uv_run(uv_default_loop()));
}

static mrb_value
mrb_uv_timer_init(mrb_state *mrb, mrb_value self)
{
  mrb_uv_data* uvdata = (mrb_uv_data*) malloc(sizeof(mrb_uv_data));
  uvdata->mrb = mrb;
  uvdata->data = malloc(sizeof(uv_timer_t));
  uvdata->proc = mrb_nil_value();
  uv_timer_init(uv_default_loop(), (uv_timer_t*) uvdata->data);
  mrb_iv_set(mrb, self, mrb_intern(mrb, "data"), mrb_obj_value(
    Data_Wrap_Struct(mrb, (struct RClass*) &self,
    &uv_handle_data_type, (void*) uvdata)));
  return self;
}

void
_uv_timer_cb(uv_timer_t* timer, int status) {
  mrb_uv_data* uvdata = (mrb_uv_data*) timer->data;
  mrb_yield(uvdata->mrb, uvdata->proc, mrb_fixnum_value(status));
}

static mrb_value
mrb_uv_timer_start(mrb_state *mrb, mrb_value self) {
  mrb_value value;
  mrb_uv_data* uvdata;
  struct RProc *b;
  mrb_value argc, *argv;
  int nargs;

  mrb_get_args(mrb, "b*", &b, &argv, &argc);
  if (mrb_fixnum(argc) != 2) {
    mrb_raise(mrb, E_ARGUMENT_ERROR, "too few arguments");
  }
  value = mrb_iv_get(mrb, self, mrb_intern(mrb, "data"));
  Data_Get_Struct(mrb, value, &uv_handle_data_type, uvdata);
  uvdata->proc = mrb_obj_value(b);
  ((uv_timer_t*) uvdata->data)->data = uvdata;

  uv_timer_start((uv_timer_t*) uvdata->data, _uv_timer_cb,
    mrb_fixnum(argv[0]),
    mrb_fixnum(argv[1]));
  return mrb_nil_value();
}

int
main() {
  int n;
  mrb_state* mrb;
  struct mrb_parser_state* st;
  struct RClass *uv, *uv_timer;

  mrb = mrb_open();

  uv = mrb_define_module(mrb, "UV");
  mrb_define_class_method(mrb, uv, "run", mrb_uv_run, ARGS_REQ(1));

  uv_timer = mrb_define_class_under(mrb, uv, "Timer", mrb_class_obj_get(mrb, "Object"));
  mrb_define_method(mrb, uv_timer, "initialize", mrb_uv_timer_init, ARGS_ANY());
  mrb_define_method(mrb, uv_timer, "start", mrb_uv_timer_start, ARGS_ANY());

  {
    char* code =
"require 'UV'             \n"
"t = UV::Timer.new()      \n"
"t.start(1000, 1000) {|x| \n"
"  p x                    \n"
"}                        \n"
"p UV.run()               \n";
    st = mrb_parse_string(mrb, code);
    n = mrb_generate_code(mrb, st->tree);
    mrb_pool_close(st->pool);
    mrb_run(mrb, mrb_proc_new(mrb, mrb->irep[n]), mrb_nil_value());
  }
}

/* vim:set et ts=2 sts=2 sw=2 tw=0: */
実行するとrubyのコード require 'UV'
t = UV::Timer.new()
t.start(10001000) {|x|
  p x
}
UV.run()
の通り、1秒間隔で1秒後に再発動するタイマ、つまりは1秒おきにステータスが表示される。
この辺の引数はUVと合わせた。エラーチェックとかサボリまくってるのでお手本のコードにはならない。


. .: : : : : : : : :: :::: :: :: : :::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
    . . : : : :: : : :: : ::: :: : :::: :: ::: ::: ::::::::::::::::::::::::::::::::::::::
   . . .... ..: : :: :: :: :: :: :: .。oO(寿司食べたい…):::::::
        Λ_Λ . . . .: : : ::: : :: ::::::::: :::::::::::::::::::::::::::::
       /:彡ミ゛ヽ;)ー、 . . .: : : :::::: :::::::::::::::::::::::::::::::::
      / :::/:: ヽ、ヽ、 ::i . .:: :.: ::: . :::::::::::::::::::::::::::::::::::::::
      / :::/;;:   ヽ ヽ ::l . :. :. .:: : :: :: :::::::: : ::::::::::::::::::
 ̄ ̄ ̄(_,ノ  ̄ ̄ ̄ヽ、_ノ ̄ ̄ ̄ ̄

あとは適当にゆっくりやっときます。
mattn/mruby-uv - GitHub

inteface to libuv for mruby

https://github.com/mattn/mruby-uv
Posted at by