2011年11月19日

【作ってみた】vimのバッファ内にrubyをインラインで書いて実行するスクリプト

Vimでテキストを打っている時にスクリプト言語や他のアプリケーションを使いたくなる時がある。ちょっとしたパターンを打ち込んだり、文字列をバラしたり、数式を計算したくなったり。大抵は正規表現とパイプを駆使して何とか頑張るが、頑張りたくない私のために。rubyを数行書く→実行→結果をバッファに挿入できるようにしてみた。

■ダウンロード

  • rubyinline_20111119.vim
  • rubyinline_20111120.vim
  • sourceコマンドで読み込んで使う。
    :source rubyinline_20111119.vim
    

    ■使い方:コードブロックとして評価
    rubyスクリプトはrubyの文法が許す限り何を書いてもよい。 visualモードでrubyスクリプトの箇所を選択した状態で(Leader)srbの順にキーを打つ(普通、Leaderはバックスラッシュキーのことらしい)。

    普通のテキスト文書
    ↓ここから
    5.times(){|iter|
      puts iter.to_s
    }
    ↑ここまで
    
    スクリプトは消去されて、標準出力の内容がバッファに追記される。
    普通のテキスト文書
    0
    1
    2
    3
    4
    
    現在のところ、実行結果が挿入される位置が1〜2行ずれる。どうやらr!コマンドでrubyを叩いているのがいけない様子。

    ■使い方:電卓モード(式として評価)
    テキスト上に現れる数式の評価値を知るためにいちいち整ったrubyの構文を書くのは面倒である。そこで、選択範囲のテキストを評価した結果を挿入するモードを作成。 こちらは(Leader)crbと打ち込む。

    たとえば、sin(1.57)*2の計算結果がほしいとしよう
    
    結果はこうなる。
    たとえば、1.99999936586367の計算結果がほしいとしよう
    
    rubyのブロック評価を使って実装しているので、複数の式を選択した場合には最後の式の評価結果が返る。また、定数を使ったりメソッドを宣言したりできない。

    ■コード
    はじめてvimのスクリプトを書いた。なんかvimな人にもrubyな人にも怒られそうな汚いコードだ。(11/20修正:putsじゃなくてprint使えば最後の改行を正規表現で落とす必要ない)

    rubyinline_20111120.vim
    "Private Functions
    :function! s:Rbscr_impl(scriptbody)
      "name of output file
      :let l:tempfile = tempname()
      :try
        "writeout and execute ruby script
        :call writefile(a:scriptbody, l:tempfile)
        :execute "r! ruby " . l:tempfile
      :finally
        "delete file
        :if filewritable(l:tempfile)
          :call delete(l:tempfile)
        :endif
      :endtry
    :endfunction
    
    :function! s:Rbculc_impl(scriptbody)
      :let l:culcPrefix  = ["#!/usr/bin/ruby"]
      call add(l:culcPrefix, "include Math")
      call add(l:culcPrefix, "def vscrEvalDescr() return yield(); end ")
      "変更:putsじゃなくてprint
      call add(l:culcPrefix, "print vscrEvalDescr(){")
    
      :let l:culcPostfix = ["}"]
    
      call extend(a:scriptbody, l:culcPrefix, 0)
      call extend(a:scriptbody, l:culcPostfix)
    
      :let l:tempfile = tempname()
      :try
        "writeout and execute ruby script
        :call writefile(a:scriptbody, l:tempfile)
        :let l:result = system("ruby " . l:tempfile)
        "変更:末尾の置換は要らない
        " :let l:result = substitute(l:result, "\n$", "", "")
        :execute "normal " . "i" . l:result
      :finally
        "delete file
        :if filewritable(l:tempfile)
          :call delete(l:tempfile)
        :endif
      :endtry
    :endfunction
    
    "Public Functions
    :function! Rbscr_visual() range
      :let l:vmode = visualmode()
      :if l:vmode == 'v'
        :let l:save_a = getreg('a')
        :silent :normal! gv"ad
        :let l:selected = split(getreg('a'), "\n")
        :silent :call s:Rbscr_impl(l:selected)
        :call setreg('a', l:save_a)
      :endif
    :endfunction
    
    :function! Rbscr() range
      "Retrive selected text
      :let l:selected = getline(a:firstline, a:lastline)
      "delete selected region
      :silent :execute a:firstline . "," .  a:lastline . " delete"
      "write file and call
      :silent :call s:Rbscr_impl(l:selected)
    :endfunction
    
    :function! Rbculc_visual() range
      :let l:vmode = visualmode()
      :if l:vmode == 'v'
        :let l:save_a = getreg('a')
        :silent :normal! gv"ad
        :let l:selected = split(getreg('a'), "\n")
        :silent :call s:Rbculc_impl(l:selected)
        :call setreg('a', l:save_a)
      :endif
    :endfunction
    
    "Key Mappings
    :execute ":map  srb :call Rbscr()"
    :execute ":vmap srb :call Rbscr_visual()"
    :execute ":vmap crb :call Rbculc_visual()"
    

    参考にした資料

    posted by yuji_at_radiance at 19:30| Comment(0) | TrackBack(0) | ソフトウェア | このブログの読者になる | 更新情報をチェックする
    この記事へのコメント
    コメントを書く
    お名前:

    メールアドレス:

    ホームページアドレス:

    コメント:

    認証コード: [必須入力]


    ※画像の中の文字を半角で入力してください。

    この記事へのトラックバック
    ×

    この広告は1年以上新しい記事の投稿がないブログに表示されております。