この記事は Vim script Advent Calendar 2015 の 16日目の記事です。
Shell から特定の target.vim
を実行した時に何かしらの出力を得たい。
実行自体は次のようにすることで可能です。
$ vim -S target.vim -c 'qa!'
あるいは、
$ vim -c 'so target.vim | qa!'
-N
と -u NONE
が必要かは場合によります。
詳細はヘルプを見ましょう。(--cmd
という選択肢もある 1)
:h -N
:h -u
:h -S
:h -c
:h --cmd
:h :so
:h :bar
さて、おもむろに次のヘルプを見ましょう。
:h Q
:h gQ
:h -E
:h -s-ex
:h :put
:h :print
:h [range]
簡単に説明すると、Q
, gQ
というのは Ex モード
に入るキーバインドです。あまり使う機会がないので別のマッピングをしている人も多いと思います2。そのような場合は vim -E
などで試すことができます(-s
をつけると試す分には辛い)。
編集用のコマンドは :h inserting-ex
, :h change.txt
などで /^:
を探すのが参考になります。
なお、途中で :redraw
を用いることでバッファの表示を更新することができます。
さて、上記のスクリーンショットでは Vim
のコマンドラインウィンドウによる対話環境で実行されていますが -s
オプションをつけると Shell
で実行されるようになります。その際に Vim
は標準出力を用いるわけです。
実践
つまり、こうです。
put ='Hello, world!'
watiko@local $ vim -NEsS hello.vim -c '2,$print | qa!'
Hello, world!
これを次のスクリプトで試してみます。
let s:fib = {
\ 'memo' : [0, 1]
\ }
fu! s:fib.calc(to)
let l:from = len(self.memo)
for i in range(l:from, a:to)
let l:next = self.memo[i - 1] + self.memo[i - 2]
call add(self.memo, l:next)
endfor
endfu
fu! s:fib.get(n)
let l:last_index = len(self.memo) - 1
if l:last_index < a:n
call s:fib.calc(a:n)
endif
return self.memo[a:n]
endfu
put =s:fib.get(10)
put =s:fib.get(45)
put =s:fib.get(46)
put =s:fib.get(47)
watiko@local $ vim -NEsS fib.vim -c '2,$print | qa!'
55
1134903170
1836311903
-1323752223
?!3
let s:save_cpo = &cpo
let v:errors = []
set cpo&vim
let s:BASE = 10
fu! s:add_positives(r0, r1)
let l:i = len(a:r0) - 1
let l:j = len(a:r1) - 1
let l:carry = 0
let l:r2 = ''
while l:i >= 0
if l:j < 0
let l:sum = a:r0[l:i] + l:carry
else
let l:sum = a:r0[l:i] + a:r1[l:j] + l:carry
endif
if l:sum >= s:BASE
let l:carry = 1
let l:sum -= s:BASE
else
let l:carry = 0
endif
let l:r2 = l:sum . l:r2
let l:i -= 1
let l:j -= 1
endw
if l:carry != 1
return l:r2
else
return l:carry . l:r2
endif
endfu
fu! s:fib(n)
let l:a = '0'
let l:b = '1'
let l:count = 0
while l:count < a:n
let l:count += 1
let l:tmp = s:add_positives(l:b, l:a)
let l:a = l:b
let l:b = l:tmp
endw
return l:a
endfu
call assert_equal('200', s:add_positives('191', '9'))
call assert_equal('55', s:fib(10))
put =string(v:errors)
put =s:fib(45)
put =s:fib(46)
put =s:fib(47)
put =s:fib(1000)
let &cpo = s:save_cpo
watiko@local $ vim -NEsS fib_big.vim -c '2,$print | qa!'
[]
1134903170
1836311903
2971215073
43466557686937456435688527675040625802564660517371780402481729089536555417949051890403879840079255169295922593080322634775209689623239873322471161642996440906533187938298969649928516003704476137795166849228875
注: 普段は QuickRun を使っています。技術的興味があっただけで、あまりおすすめしません(面倒なので)。