vim-users.jp

Vim Advent Calendar 2012 ujihisa 4

Posted at 2013/02/28
このエントリーをはてなブックマークに追加

Vim Advent Calendar 2012 の 90 日目の記事です。 昨日はthincaさんによる魔改造でした。ちなみにcleverは大人が子供に「デキる子だねえ」というときや、大人同士が皮肉でずるがしこいなにかを褒めるときに使える便利な単語らしいです。

Scalaとsbt

RubyにおけるRake, HaskellにおけるCabal, ClojureにおけるLeiningen, CにおけるMakeがScalaにおけるSBT (Simple Build Tool)で、これは挙動が他のほとんどのビルドツールよりも複雑なことで有名なデキる子です。毎日愛用しています。

sbt (SBTのコマンド) を起動するには果てしない時間がかかるため、一般にはsbtコマンドを対話モードで起動して、そのプロセスを使い続けるというスタイルが一般的です。つまり、sbtとvimは本質的に同じです。

sbt

:VimShellSendString

VimShellのiexeならびに:VimShellInteractiveで立ち上げた外部プロセスにメッセージを投げる便利な方法として:VimShellSendStringコマンドがあります。これは引数として与えられた文字列または選択範囲を”background buffer”に投げます。

たとえばfiletypeがscalaであるファイルを編集中は、

  1. ファイルを保存する
  2. sbtにcompileメッセージを送って適切にコンパイルできるかどうか確認する

を順にまとめて行う必要がかなり頻繁にあります。

nnoremap <Space>m :<C-u>update<Cr>:VimShellSendString compile<Cr>

などと設定することでワンキーで保存・コンパイルを行うことができ、便利です。quickrunやsyntasticやwatchdogsなどのプラギンと違い、すでにライブラリの読み込みなどが完了して起動しているプロセスを再利用するので、10~30倍くらい高速で動作します。

しかしながら、シェルとしてのVimShellと対話環境としてのiexe窓の両方を開いていると、どちらが”background buffer”なのかが曖昧になるという問題があります。

1 2

失敗している様子:

3

成功している様子:

4

解決

t:スコープの変数、vimshell#interactive#set_send_buffer(), vimshell#interactive#send()の合わせ技で対処します。

function! s:ujihisa_start_sbt()
  execute 'VimShellInteractive sbt'
  stopinsert
  let t:sbt_bufname = bufname('%')
  if !has_key(t:, 'sbt_cmds')
    let t:sbt_cmds = [input('t:sbt_cmds[0] = ')]
  endif
  wincmd p
endfunction

command! -nargs=0 StartSBT call <SID>ujihisa_start_sbt()

function! s:sbt_run()
  let cmds = get(t:, 'sbt_cmds', 'run')

  let sbt_bufname = get(t:, 'sbt_bufname')
  if sbt_bufname !=# ''
    call vimshell#interactive#set_send_buffer(sbt_bufname)
    call vimshell#interactive#send(cmds)
  else
    echoerr 'try StartSBT'
  endif
endfunction

function! s:vimrc_scala()
  nnoremap <buffer> <Space>m :<C-u>write<Cr>:call <SID>sbt_run()<Cr>
endfunction

augroup vimrc_scala
  autocmd!
  autocmd FileType scala call s:vimrc_scala()
  autocmd FileType scala nnoremap <buffer> <Space>st :<C-u>StartSBT
augroup END

上記のように~/.vimrcに記述し、scalaのファイルを編集するときにiexe sbt:VimShellInteractive sbtのかわりに:StartSBTコマンドを使います。以後、コンパイルなど行いたいときには<Space>mを打鍵します。なおcompile以外のコマンドにも対応するため、t:sbt_cmdsという変数を用意しています。ここに実行させたいコマンド列を指定します。なお初回起動などでそのタブにこの変数がセットされていないときは、入力を求められます。

これで<Space>mを打鍵するだけでファイルの保存・コンパイルができ、しかも30倍高速化しました。Scalaにおける開発がはかどります。

余談

HootSuiteという会社はHootSuiteの実装に一部Scalaを用いています。Scala開発チームの約50%の人が上記テクニックを用いて|<Space>m|だけで保存・コンパイルなどの定形操作を自動化かつ高速化しています。

ujihisa

もどる
blog comments powered by Disqus