vim-insert-point というものを作った

追記

暫定でカスタマイズ可能にした。もっとカスタマイズ方法については練りたい。

let g:insert_point_config.default = [
    \ { 'target': '.)', 'offset': 0, 'direction': 0 },
    \ ]

上記のように記述することで自分の設定を行うことができる。
上記の意味は、

  • target
    • ジャンプしたい定義箇所
  • offset
    • 正規表現でマッチした先頭位置からのオフセット位置(マイナス値で後ろから指定できるようにすごくしたい)
  • direction
    • 通常はいじらなくてよい 1 は next キーマッピングの時だけ有効、0 は next & prev で有効、-1 は prev のみ有効

導入

vim を使っていると括弧を自動入力するキーマッピングを一度は経験すると思う。

inoremap ( ()<Left>

上記のようなやつ。


でも、上記のマッピングだと括弧から抜けるときにノーマルモードに戻るのが面倒臭い。
自分の場合は、.vimrc にゴリゴリ書きまくっていい感じにしていたのだが、
あまりにも雑多になってきたので、今回 すごく適当に プラグイン化した。
この手のプラグインはかなり多いが、こればかりは人それぞれかなーと思うので自作もしょうがない。

インストール

人それぞれかなー とかいいつつ、一応使い方とかを残しておく。
すごく適当に作ってしまったので正直問題が山積み。


上記を取得し、下記のキーマッピングを .vimrc に記述する。

imap <Tab> <Plug>(insert_point_next_point)
imap <S-Tab> <Plug>(insert_point_prev_point)

これで、インサートモードで を入力すると、なんかいい感じにカーソルが移動するようになる。

※ 「 は補完に使ってるんだが・・・」って人は、なりなんなりにどうぞ。
※ 初期設定は結構移動箇所多めの設定にしてある。

カスタマイズ

現状ではカスタマイズできない。
あまりにもナンセンスなのでここは改善する予定。
無理矢理でも改善したい場合は、vim-insert-point/autoload/config/default.vim をいじってください。
ここは近日中になんとかする予定。


※ ちなみに filetype ごとに移動箇所を定義できます。

サンプル

imap <Tab> <Plug>(insert_point_next_point)
imap <S-Tab> <Plug>(insert_point_prev_point)
inoremap [ []<Left>
inoremap { {}<Left>
inoremap ( ()<Left>
inoremap ' ''<Left>
inoremap " ""<Left>

終わりに

この機能をプラグイン化することができたのは自分にとっては結構でかい。
この挙動は結構こだわって作ったので気になる方はぜひ使ってみてください。

vim-unite-matcher-context というものを作った

追記

unite.vim 本体に取り込まれました!
別途のインストールは不要です。

導入

例によって vim ネタです。
unite.vim を使っていない人には本当に無価値な記事なのでスルーしてもよいです。

先日、vim-unite-vcs という unite.vim の source を書いたんだけど、
デフォルトの絞り込み挙動では満足できなかったので対策をした。

本題

unite.vim を使っているみなさん。


絞り込みを先頭からマッチさせたい!!!!


と思ったことはありませんか。自分は何度もあります。
ということで、入力された文字列によって
「glob」「正規表現」をいい感じに切り替えて絞り込む matcher を書きました。

本当はもっときれいに多機能な感じで書きたかったけど先に公開することにします。
github に置いたほうが都合がいいので。。。

インストール

まず、vim-unite-matcher-context をインストールします。

そして .vimrc に以下を記述します。

call unite#filters#matcher_default#use(['matcher_context'])

以上です。

使い方

絞り込み文字列の先頭文字を ^ にすると正規表現マッチを行い、
それ以外の文字列の場合は glob マッチを行います。

本当は g:unite_matcher_context_table かなんかで定義できるようにしたかったけど、
見切り発射で公開しました。

以上です。

終わりに

なんかすごい適当な感じの記事になってしまったけど、
実際の挙動は本家に取り込んで欲しいと思えるぐらい使いやすいと思っています。
ということでかなりおすすめなので導入してもらえるとうれしいです。

float と position: relative を使って 2 カラムレイアウト

導入

css では、position: absolute 神話が自分の中にあって、基本的にそれで戦えると思っている。
例えば、右端に 20px 余裕を持たせて残り全部の幅を持った要素を定義する場合などがこれにあたる。
ただ、position: absolute では戦えないケースも当然あって例えば、

    1. 高さが決まっていない要素を良い感じに配置する

なんて時には position: absolute が使えない。

上記のケースのありがちなものとして、2カラムレイアウトで、1カラム目の幅が決まっている場合などがあげられる。
今回は自分の備忘録として 2カラムレイアウト + 固定幅 + 残りの幅全部 を position: relative で倒す方法を書く。

本題

オーソドックスに html と css だけ書く。

<html>
  <body>
    <div id="wrapper">
      <div id="column1">
        <ul id="navigation">
          <li class="item">item1</li>
          <li class="item">item2</li>
          <li class="item">item3</li>
        </ul>
      </div>
      <div id="column2">
        <div id="content1">
          content1
        </div>
        <div id="content2">
          content2
        </div>
      </div>
    </div>
  </body>
</html>
#wrapper {
  position: relative;
  width: 900px;
}

#column1 {
  width: 280px;
  float: left;
}

#column1:after {
  /* clearfix */
}

#column2 {
  position: relative;
  right: 0;
  margin: 0 0 0 280px;
}

#column2:after {
  /* clearfix */
}

終わりに

今回は備忘録なので特に何もなし。

ポイントは固定値が 900px と 280px しかでてこないところ。
ナビゲーションの幅が変わっても考えることが少なくて済む。

socket.io で動的に名前空間(namespace)を追加する方法

導入

node.js で socket.io を使って、なんかゲーム作れないかな?と最近いろいろ試している。
そこで、例えばこういうケース

  • ユーザが「部屋の新規作成」を選ぶと、新しいチャットルーム的なものができる

に対応する場合、動的に名前空間を追加したくなる。

本題

socket.io で動的に名前空間を追加する際の情報って意外と少ないし、
なんか良さげな方法が見つかりにくいのでとりあえず自分が使っている方法を残す。

説明

クライアント側で、接続時に ID を送る

socket.io は「クライアントがサーバに接続した時」というフックを持っている


[サーバ側]

  io.configure(function () {
    io.set('authorization', function (handshake, callback) {
      // 処理
    });
  });


上記のようにかける。
また、クライアント側からはハンドシェイク向けのデータを送信することもでき、


[クライアント側]

  var con = io.connect('http://localhost:3000?debug=1');


上記のように、クエリストリングに書くことができる。
つまり、ID を debug=1 の部分に埋め込めば、ソケットサーバ側で ID をとれるということになる。

名前空間(namespace)は動的に追加できる

また、socket.io は動的に名前空間を定義でき、それは、authorization のタイミングでも可能。
上記を踏まえて、このように記述できる。


[クライアント側]

/**
  * 名前空間 /chat/1 を指定し、
  * id=1 をソケットサーバに送信
  */
var socket = io.connect('http://localhost:3000/chat/1?id=1');


[サーバ側]

io.configure(function () {
  io.set('authorization', function (handshake, callback) {

  /**
    * クライアントからきた id=1  の部分を取得
    * /chat/1 名前空間が存在しなければ、io.of('/chat/' + id) で作成する。
    */
    var id = handshake.query.id;
    if (!io.namespaces.hasOwnProperty('/chat/' + id)) {
      var room = io.of('/chat/' + id);
      room.on('connection', function (socket) {
        // 処理
      });
    }

    callback(null, true);
  });
});
上記を踏まえた全体の流れ

上記を踏まえてこのような動作が可能になる。

  1. ユーザは、「チャットルームの作成」リンクをクリックする
  2. サーバ側で、 MySQL などにチャットルームの 1 レコードを作成する
  3. クライアントを、チャットルームページに飛ばし、その際に2で作ったチャットルームの ID をページに埋め込む
  4. クライアント側からチャットルームの特定の名前空間に接続する
  5. この際、「名前空間がない && MySQL にチャットルームのレコードが存在する」場合、名前空間を作る
  6. クライアントは、元々指定していたチャットルームの ID の名前空間に接続する

終わりに

上記の流れで、動的に名前空間を作れるようになり、チャットルーム自体もサーバ側で管理できるようになる。

もっといい方法があれば教えてください。

unite で vcs の操作を行えるソース書いた

導入

unite で vcs を扱えるソースというと kmnk さんの

などが有名。

本題

上記のプラグインはすごく便利だったんだけど、diff が unified 形式だったりするのが個人的に合わなかったので新しく書いた。

※ 作成に際して、協力してもらってる人がいたりします。

特徴
  • git, svn を透過的に扱える(vcscommand 的な位置づけ)
  • unite を使うことを想定しているが、vcs#... な関数を使うことで他のプラグインからも扱える

使い方

概要

何らかの vcs で管理されたファイルを開いた状態で、

  • ログを見る
    • :Unite vcs/log
  • 作業コピーの変更を一覧する
    • :Unite vcs/status
  • リポジトリのファイル一覧を見る
    • :Unite vcs/file_rec

などができます。

vcs/log
  • ログの一覧が出力される
  • 2つのログを選択して、diff を取ることができる
  • 1つのログを選択して、作業コピーとの diff を取ることができる
  • 特定のログで行われた変更を見ることができる(diff_prev)
vcs/status
  • ステータスの一覧が出力される
    • 変更のあったファイル、管理されていないファイル、削除されたファイル、等
  • add, delete, commit, revert ができる
vcs/file_rec
  • リポジトリのファイル一覧が出力される
  • ステータスも一緒に表示される。変更があるファイルだったら M など。
  • ファイルを選択して vcs/log を起動できる

などです。

困り事

git がよくわからない

仕事では svn を使っているので、git を使っていて欲しい機能なんかがよくわからない。
そのため、git メインで使ってる方には違和感があるかもしれない。(意見があったらガンガン言ってください。)

svn, git で違うコマンドをうまく扱えない

svn と git だとコマンド名が違ったり、そもそも git にしかないコマンドがあったりして難しい。
これはある程度しょうがないこととして割り切ろうかと思っている。


VimFiler で NERDTree のような Explorer を快適に実現する方法

導入

vim を使い始めた最初の頃、 NERDTree というプラグインを知った。
NERDTree を導入してから vim にのめり込んでいった気がする。

NERDTree というのは、いわゆるファイラーの機能を実現するプラグインで、Windows のエクスプローラに非常に近い直感的な使い勝手ですごく気に入っていた。


今は VimShell や Unite を使い始めて、それらとの親和性が非常に高く(もはや融合してる)、機能も豊富な VimFiler に乗り換えてる。


ただ、NERDTree の「エクスプローラ感」はかなり自然だったので、VimFiler の設定がよくわからない間は結構違和感を感じていた。

本題

VimFiler でも超快適なエクスプローラとして使えるし、機能の豊富さや更新の速さなどを考えると VimFiler がおすすめということで、
NERDTree から VimFiler に移行する人向けに設定とかを残す。

インストール

まずはインストールしないとはじまらないので、VimFiler をインストールする。
VimFiler は同じ作者のプラグインである Unite に依存しているので、そちらも導入する。


※ 「とりあえず必要だから Unite も入れよう」っぽく見えますが、Unite も本当に便利なのでガンガン使いましょう。


導入後、vim で :VimFiler コマンドを試して、ファイラが起動すれば OK。

エクスプローラとして使う為の設定

次に、VimFiler をエクスプローラとして使う為の設定を .vimrc に記述する。

nnoremap <F2> :VimFiler -buffer-name=explorer -split -winwidth=45 -toggle -no-quit<Cr>
autocmd! FileType vimfiler call g:my_vimfiler_settings()
function! g:my_vimfiler_settings()
  nmap     <buffer><expr><Cr> vimfiler#smart_cursor_map("\<Plug>(vimfiler_expand_tree)", "\<Plug>(vimfiler_edit_file)")
  nnoremap <buffer>s          :call vimfiler#mappings#do_action('my_split')<Cr>
  nnoremap <buffer>v          :call vimfiler#mappings#do_action('my_vsplit')<Cr>
endfunction

let s:my_action = { 'is_selectable' : 1 }
function! s:my_action.func(candidates)
  wincmd p
  exec 'split '. a:candidates[0].action__path
endfunction
call unite#custom_action('file', 'my_split', s:my_action)

let s:my_action = { 'is_selectable' : 1 }                     
function! s:my_action.func(candidates)
  wincmd p
  exec 'vsplit '. a:candidates[0].action__path
endfunction
call unite#custom_action('file', 'my_vsplit', s:my_action)

※ nmap や nnoremap は好きなキーに読み替えてください。

使い方

上記のキーマッピングの場合、

  • VimFiler の起動
    • ノーマルモードで を打鍵
  • ファイルを開く
    • VimFiler 上で開きたいファイルを選択してエンターを打鍵
  • ファイルを縦分割で開く
    • VimFiler 上で開きたいファイルを選択して v を打鍵
  • ファイルを横分割で開く
    • VimFiler 上で開きたいファイルを選択して s を打鍵
終わりに

上の設定で NERDTree から VimFiler への移行がスムーズにできる気がする。

自分の場合は他にもカオスなハックを加えたりして自分好みの挙動に変えたりしています。
(例えば vimshell バッファはファイルを開く際に上書きせず残すなど)

低 vimscript 力でこんな記事を書いてしまったけど、
なにか間違いとかあったら指摘してもらえるとキャンキャン喜びます。
(そもそも誰も見てない感あるけど)

Rails3のActiveRecordでtimezoneが適用されない問題

※ この記事は最後まで読んでください。

Ruby on Rails3 では、設定ファイル(config/application.rb)に

config.time_zone = 'Tokyo'

とすることで、タイムゾーンを指定できる。
でも、そのままActiveRecordを利用してデータを保存しても、
created_at, updated_at はUTCとして保存されてしまう。

今回は、根が深そうだったので、

config/initializers/time_formats.rb

Time::DATE_FORMATS[:local] = lambda {|time|
  time.localtime.to_s(:db)
}

とし、ビュー側では

<%= post.updated_at.to_s(:local) %>

とすることで回避

追記

なんか application.rb に

config.time_zone = 'Tokyo'
config.active_record.default_timezone = :local

を追記するだけで、DBに保存する日付も問題なく動作するらしいので、
こちらのほうがよいかと思います。