jqという非常に便利なコマンドラインツールがある. これは,jsonの整形を行うものだ. jqコマンド自体については,公式のマニュアルや以下の記事を参考にすればよくわかるだろう.
- jq コマンドを使う日常のご紹介 - Qiita
- 軽量JSONパーサー『jq』のドキュメント:『jq Manual』をざっくり日本語訳してみました | Developers.IO
- jq コマンドが強力すぎてヤバい件 | CUBE SUGAR STORAGE
- jqコマンドが実は高性能すぎてビビッた話 - beatsync.net
この便利なjqコマンドをVim上で利用したい. そのように考えた人は既におり,以下のいくつかの記事が参考になる.
これらの記事に書いてあるように,
:%!jq .
と外部コマンドを実行したり,
if executable('jq') function! s:jq(...) execute '%!jq' (a:0 == 0 ? '.' : a:1) endfunction command! -bar -nargs=? Jq call s:jq(<f-args>) endif
のようなコマンドを定義し,:Jq
とコマンドを実行すればよい.
しかし,Json自体に誤りがあった場合は,Jsonを表示しているカレントバッファからJsonが消え,エラーメッセージに置き換えられてしまう. いちいちundoするのも面倒だ. そこで,エラーがある場合は,別のバッファにエラーメッセージを表示し,カレントバッファに変更を加えないようにしたい. 前回書いた記事:VimでC言語のソースコードを整形したいを模倣し,コマンドを改良する.
if executable('jq') function! s:jq(has_bang, ...) abort range execute 'silent' a:firstline ',' a:lastline '!jq' string(a:0 == 0 ? '.' : a:1) if !v:shell_error || a:has_bang return endif let error_lines = filter(getline('1', '$'), 'v:val =~# "^parse error: "') " 範囲指定している場合のために,行番号を置き換える let error_lines = map(error_lines, 'substitute(v:val, "line \\zs\\(\\d\\+\\)\\ze,", "\\=(submatch(1) + a:firstline - 1)", "")') let winheight = len(error_lines) > 10 ? 10 : len(error_lines) " カレントバッファがエラーメッセージになっているので,元に戻す undo " カレントバッファの下に新たにウィンドウを作り,エラーメッセージを表示するバッファを作成する execute 'botright' winheight 'new' setlocal nobuflisted bufhidden=unload buftype=nofile call setline(1, error_lines) " エラーメッセージ用バッファのundo履歴を削除(エラーメッセージをundoで消去しないため) let save_undolevels = &l:undolevels setlocal undolevels=-1 execute "normal! a \<BS>\<Esc>" setlocal nomodified let &l:undolevels = save_undolevels " エラーメッセージ用バッファは読み取り専用にしておく setlocal readonly endfunction command! -bar -bang -range=% -nargs=? Jq <line1>,<line2>call s:jq(<bang>0, <f-args>) endif
前回の記事とほとんど内容は変わらない. フィルタリングに用いるコマンドのエラーを判別し,エラー用の処理を加えることで,いくつかの記事で紹介されているjqを用いるコマンドより便利になったというだけだ.