rcmdnk's blog

20170925_vimale_200_200

Vimではプラグインを入れることでプログラミングコードの 構文をチェックしてエラーなどをハイライトすることが出来ますが 構文チェック用のプラグインを新しくして ALE を使い始めました。

VimのSyntaxチェッカープラグイン

構文チェック用のプラグインとして老舗で一番有名なのは syntastic だと思います。

今まではこれを使ってました。 このプラグインは同期処理で行っていて保存時等に 構文チェックを行います。

一方、 最近、NeoVimの登場やVim 8 でも非同期な操作が可能になったことから 非同期で処理できるプラグインも出てきました。

watchdogsなんかはVim自体で非同期処理が出来る様になる前に vimproc などを用いて非同期処理を行える様にしていました。 watchdogsは一時期使っていましたが全体的な動作がもっさりしてしまう状態になったこともあり Syntasticに戻していました。 これを今使うには余計なものを入れる必要が出てくるのでちょっと古い感じです。

NeomakeやALEはVim自体の非同期処理を使ったもので、 ALEの方が新しいプラグインだと思いますがGitHubのスターだとすでにALEの方が多くなっています。

後継ということもあってNeomakeからALEに移った、というブログ記事もちらほら見かけました。

Neomakeも以前使ったことがありましたが、やはり動作に影響がある感じがあったので Syntasticに戻していました。

今回また色々見直してる中でALEという新しいプラグインを見つけた、という状態で試してみることにしました。

Asynchronous Lint Engine (ALE)

インストールはプラグイン管理プラグインなんかで適当に。

dein 1 であれば

.vimrc
1
2
3
4
5
6
" Syntax checking
if has('job') && has('channel') && has('timers')
  call dein#add('w0rp/ale')
else
  call dein#add('vim-syntastic/syntastic')
endif

jobchanneltimersは Vim 8.0で導入された非同期関連の新しい機能で 2 aleではこれらの機能付きでコンパイルされている事を要求します。 (通常のインストールなら入っているはず。)

こんな感じで書いておくと非同期処理が使えない環境ではSyntasticを使う、ということも出来ます。

ALEのレポジトリがちょっと大きい(~20MB)ので、場合によってインストール時にタイムアウトになってしまいインストールエラーが起こる可能性があります。 deinだと初期値で120秒になってますが、実際に

[dein] /home/user/.vim/dein/repos/github.com/w0rp/ale
[dein] Remove the installed directory:/home/user/.vim/dein/repos/github.com/w0rp/ale
[dein] Process timeout: (xxxx/xx/xx xx:xx:xx)
[dein] Error installing plugins:
[dein]   ale
[dein] Please read the error message log with the :message command.

こんな感じのエラーが出てしまう環境がありました。 試しに

$ git clone https://github.com/w0rp/ale

とかやってみて、clone出来るものの時間がかかるようだったら

let g:dein#install_process_timeout =  600

.vimrcに加えると600秒待つことが出来ます。

プラグインの設定はこんな感じ。

.vimrc
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
if s:dein_enabled && dein#tap('ale')
  let g:ale_lint_on_enter = 0

  nmap <silent> <Subleader>p <Plug>(ale_previous)
  nmap <silent> <Subleader>n <Plug>(ale_next)
  nmap <silent> <Subleader>a <Plug>(ale_toggle)

  function! s:ale_list()
    let g:ale_open_list = 1
    call ale#Queue(0, 'lint_file')
  endfunction
  command! ALEList call s:ale_list()
  nnoremap <Subleader>m  :ALEList<CR>
  autocmd MyAutoGroup FileType qf nnoremap <silent> <buffer> q :let g:ale_open_list = 0<CR>:q!<CR>
  autocmd MyAutoGroup FileType help,qf,man,ref let b:ale_enabled = 0

  if dein#tap('lightline.vim')
    autocmd MyAutoGroup User ALELint call lightline#update()
  endif

  let g:ale_sh_shellcheck_options = '-e SC1090,SC2059,SC2155,SC2164'
endif

dein_enabledはファイルの最初の方で自分で設定している変数です。

まず最初にg:ale_lint_on_enterを0にして ファイルを開いた瞬間のチェックを外しています。 (開く時はぱっと開きたいし、ただ見たいだけでエラー表示も必要ないこともあるので。)

<Subleader><Leader>の様に使える様にしてあり、 <Space>にあてています。 (<Leader>,に変更。)

.vimrc
1
2
3
4
5
let g:mapleader = ','
noremap <Subleader> <Nop>
map <Space> <Subleader>
nnoremap <Subleader>, ,
xnoremap <Subleader>, ,

これを使って前/次のerrorやwarningが出てる行に飛ぶキーをSpace-P/N に割り当てています。 ここではale_previous/ale_nextと言った値を使ってますが、 ale_previous_wrap/ale_next_wrapと言う一番上/下に行った後に 一番下/上に周って検索を続ける、というmappingの値もあります。

ale_toggleはaleをオン/オフする機能。

その後でALEListというコマンドを定義してこれを:ALEListと実行すると 別ウィンドウでエラー/警告一覧を出せる様にしています。 g:ale_open_listを1にしておくとこの別ウィンドウが出る様になりますが常にあると邪魔なので。 これも<Subleader>mに割り当てています。

ウィンドウを出した後、そのウィンドウに行って消すだけだとその後のチェックの際にまた開いてしまうので、 ウィンドウタイプがqf(quickfix)の時にはg:ale_open_list = 0してから閉じる様にしています。 MyAutoGroup.vimrcの中で他のグループに属さないものを全部入れてるグループです。

元々、

autocmd MyAutoGroup FileType help,qf,man,ref nnoremap <silent> <buffer> q :q!<CR>

の様な設定をしていてヘルプとかquickfixとか編集用に開いたものでない場合には Qを押すだけで閉じる用にしていたのでqfのときだけちょっと加える形で。 ALEのウィンドウのときだけ、というのをやりたいところですが 特別な名前を付けてるわけでもなさそうなのでとりあえずはこれで。

加えてこれらhelpqfなどでは基本編集はしないですし構文チェックする必要もないので そのバッファではALEをオフにするようにバッファ変数のb:ale_enabledを0にしています。

この辺ALE本体にあったらいいな、と思う機能でもあるのできちんと出来たらプラグインに加えて見てPull Requestしてみるかも。

その次ではlightlineのプラグインを入れている時、 ステータスラインにaleに関する表示を出すので ALELint(構文チェック)を行った際にすぐにステータスラインをアップデートするための設定です。 (lightlineについては後述。)

最後には各言語のチェッカー(linter)に関するオプションですが、 ここではshellcheckに対するオプションで sourceする先が変数だったりする時に出すwarningなどをオフにする設定です。

ALEでは使用できるlinter全てを使って補完的にエラーやおかしなところを探して結果を出す様です。 (Syntasticとかだと複数のlinterがある場合には最初のlinterでエラーなどが無ければ次ので探して、 みたいなことをやります。)

linterを指定したいときには

.vimrc
1
2
3
let g:ale_linters = {
\   'javascript': ['eslint'],
\}

の様な感じで指定するとそのlinterだけを使うようになります。

SyntasticやNeomakeに比べるとaleで最初に指定してあるlinterはまだ少し少ない感じもありますが 有用なものはどんどん追加されてくと思います。

lightlineでの表示

lightline側で以下のような設定を加えることで なにも問題ない時はOK、エラーなどがある場合にはE: 10 W:8 の様にエラーの数などを表示できる様になります。

.vimrc
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
if s:dein_enabled && dein#tap('lightline.vim')
  let g:lightline = {
        \'active': {
              \'right': [['ale']]},
        \'component_function': {
              \'ale': 'LLAle',
              \},
        \}
  if dein#tap('ale')
    function! LLAle()
      let l:count = ale#statusline#Count(bufnr(''))
      let l:errors = l:count.error + l:count.style_error
      let l:warnings = l:count.warning + l:count.style_warning
      return l:count.total == 0 ? 'OK' : 'E:' . l:errors . ' W:' . l:warnings
    endfunction
  else
    function! LLAle()
      return ''
    endfunction
  endif
endif

実際には他の表示との兼ね合いでちょっと違った設定を使ってます。 実際に使ってるのは下記で。

いずれにしろ大事なのはale#statusline#Count(bufnr(''))で現在の情報を取ってこれるという所。 (Countの引数はバッファ番号でbufnr('')で現在のバッファ番号を与えています。)

取れるのは辞書オブジェクトで、

  • error : 構文エラーの数。
  • warning : 構文警告の数。
  • info : インフォタグの付いた数。
  • style_error : スタイルに関するエラーの数。
  • style_warning : スタイルに関する警告の数。
  • total : トータル数。

これらを使って後は好きなように表示するだけです。

これに対してALEGetStatusLine()(またはale#statusline#Status())という 直接適当な形で情報を表示を返してくれる関数もありますが、 これはdeprecatedということなのでCountを使って表示を作るべきです。 (g:ale_echo_msg_formatという変数もこの出力のためだけのなので使わない。 ちょっと前のブログ記事だとALEGetStatusLineを使ってるのが多いのでちょっと注意。)

表示はリスト表示もするとこんな感じになります。

vim ale

vim-airlineでの表示

vim-airline もステータス表示プラグインですが、 こちらにはALE用の設定が元々あり、

let g:airline#extensions#ale#enabled = 1

をするだけで表示できる様になります。

必要な場合はALEのREADMEに従って表示を変更することも可能です。

その他のメモ

コマンド

  • ALELint: チェックを手動実行。
  • ALEFix: g:ale_fixersで指定された修正の実行(fixersは自分で指定する必要がある)。
  • ALEFixSuggest: 現在のバッファでの修正の提言。
    • 'remove_trailing_lines' - Remove all blank lines at the end of a file.というのがどこでも出る。(fixerを指定しないとこれが出る?)

オプション

  • g:ale_completion_max_suggestions: 1にすると補完が出来るようになる。
    • Neocompleteを使ってるので取り敢えずオフのまま。
  • g:ale_fixers: ALEFixで使う修正用ツールの指定。
  • g:ale_fix_on_save: 1だとファイルを保存するタイミングでALEFixを行う。初期値0。
  • チェックのタイミング:
    • g:ale_lint_on_enter: ファイルを開いた時にチェックを実行。初期値1。設定で0に。
    • g:ale_lint_on_filetype_changed: filetypeが変わった時にチェックを実行。初期値1。
    • g:ale_lint_on_save: ファイルを保存する時にチェックを実行。初期値1。
    • g:ale_lint_on_text_changed: 内容が変更された時にチェックを実行。初期値1。余りにガチャガチャしすぎなら0に。
    • g:ale_lint_on_insert_leave: インサートモードを終了する時にチェックを実行。初期値0。text_changedを0にしたらこちらを1にした方が良い。
  • g:ale_maximum_file_size: チェックを行う最大ファイルサイズ。初期値は0。1以上に設定するとそのbyte数より大きいファイルをチェックしない。
    • 使ってて辛いのが出てきたら設定してみる。
  • 左枠の表示の調整:
    • g:ale_sign_column_always: 1にするとエラーや警告がない場合でも左側にその分の枠を空けておく。初期値0。ガチャガチャ動くのが嫌な場合は1に。
    • g:ale_sign_offset: signのオフセット。初期値1000000。エラー箇所にsignのIDを振っておいてそこにjump出来たりするようにしている。Vimの機能で他のプラグインも含めてIDはユニークじゃないといけない。もし他のプラグインを入れて上手く動作しない場合は同じ様な初期値からIDを振ってる可能性がありその場合はこの初期値を変える事で回避できる。
      • ALEの様に大きな番号のオフセットを使ってるものは無かったが幾つかsign placeを使ってるプラグインがあって小さい番号でconflictが起こりそうな感じもあったので今後注意してみる。
    • g:ale_sign_error: エラーの指標。初期値>>
    • g:ale_sign_warning: 警告の指標。初期値--
    • g:ale_sign_info: インフォの指標。初期値g:ale_sign_warning
    • g:ale_sign_style_error: スタイルエラーの指標。初期値g:ale_sign_error
    • g:ale_sign_style_warning: スタイル警告の指標。初期値g:ale_sign_warning
  • リスト表示
    • g:ale_open_list: 1でエラーや警告一覧を別ウィンドウで表示する様にする。初期値0。
    • g:ale_keep_list_window_open: 1でエラーや警告がない場合でも一覧用のウィンドウを消さない様にする。初期値0。
    • g:ale_list_window_size: 一覧表示用ウィンドウサイズ。初期値10。
  • g:ale_set_loclist: 1でエラーなどの一覧をloclistに保存。初期値1。
  • g:ale_set_quickfix: 1でエラーなどの一覧をquickfixに保存。初期値0。loclistではなくquickfixにしたい場合は上を0にしてこれを1に。

まとめ

とりあえず入れてみて使ってる感じでは特に動作に影響は無いように見えます。 (マシン自体の向上もありますが。)

Syntasticで行っていた様なことは出来ているのでしばらく使ってみます。

Sponsored Links
Sponsored Links

« Vimのlightlineでのステータスライン表示の調整 Vimスクリプトでバッファ変数とグローバル変数を順に調べてチェックする方法 »

}