設定ファイルの編集などでは、書き方を間違えるとアプリケーションが動作しなくなることがある。そのため、設定ファイルの編集は慎重に行うものだが、急いでいたり、慣れてきたりすると、どうしてもミスを犯す。その度にどこで間違えているのか目を皿のようにして調べることになるのだが、考えてみればこういった作業は自動化すべきものだ。人が必死になってやるようなことではないように思う。

LinuxやmacOSといったUNIX系OSには、設定ファイルやさまざまな種類のテキスト、またはプログラミング言語などの文法をチェックするツールがたくさんある。通常はコマンドを実行してチェック(静的解析)を行うのだが、Vimでは「ALE」というプラグインを使うと、この作業を自動化することができる。編集中に適当なタイミングでALEが自動的にチェックツールを実行し、エラーがあればユーザーに知らせてくれる。とても便利なプラグインだ。今回は、このALEの使い方を説明しよう。

ALEの設定

ALEの設定方法について説明する前に、前回までに作成してきた設定ファイル「~/.vimrc」を次に掲載しておこう。

"dein Scripts-----------------------------
if &compatible
  set nocompatible               " Be iMproved
endif

" Required:
set runtimepath+=~/.cache/dein/./repos/github.com/Shougo/dein.vim

" Required:
if dein#load_state('~/.cache/dein/.')
  call dein#begin('~/.cache/dein/.')

  " Let dein manage dein
  " Required:
  call dein#add('~/.cache/dein/./repos/github.com/Shougo/dein.vim')

  " Add or remove your plugins here
  call dein#add('junegunn/seoul256.vim')
  call dein#add('vim-airline/vim-airline')
  call dein#add('vim-airline/vim-airline-themes')
  call dein#add('preservim/nerdtree')
  call dein#add('tpope/vim-commentary')
  call dein#add('tpope/vim-fugitive')
  call dein#add('fholgado/minibufexpl.vim')

  " Required:
  call dein#end()
  call dein#save_state()
endif

" Required:
filetype plugin indent on
syntax enable

" If you want to install not installed plugins on startup.
if dein#check_install()
  call dein#install()
endif

" seoul256
let g:seoul256_background = 233
colo seoul256

" vim-airline
let g:airline_powerline_fonts = 1
let g:airline_theme = 'molokai'

" NERDTree
"  <C-o> open NERDTree
nnoremap <silent> <C-o> :NERDTreeToggle<CR>

" minibufexpl
nnoremap <silent> bn :<C-u>:bnext<CR>
nnoremap <silent> b1 :<C-u>:b1<CR>
nnoremap <silent> b2 :<C-u>:b2<CR>
nnoremap <silent> b3 :<C-u>:b3<CR>
nnoremap <silent> b4 :<C-u>:b4<CR>
nnoremap <silent> b5 :<C-u>:b5<CR>
nnoremap <silent> b6 :<C-u>:b6<CR>
nnoremap <silent> b7 :<C-u>:b7<CR>
nnoremap <silent> b8 :<C-u>:b8<CR>
nnoremap <silent> b9 :<C-u>:b9<CR>

"End dein Scripts-------------------------

set number
syntax on
set whichwrap=b,s,[,],<,>,~,h,l
set cursorline
set incsearch
set hlsearch
set ignorecase

上記の設定ファイルの「call dein#add(‘fholgado/minibufexpl.vim’)」の部分を、次のように編集する。

  call dein#add('fholgado/minibufexpl.vim')
  call dein#add('dense-analysis/ale')

ALEの設定はこれだけだ。後は、環境と状況に応じて適宜動作してくれる。

静的解析ツールをインストール

ALEはVimで静的解析ツールに仕事を割り当てる、いわば執事のように動いてくれるプラグインであり、静的解析ツールとしては動作しない。そのため、静的解析ツールは別途インストールしておく必要がある。本稿執筆時点において、ALEが対応するプログラミング言語とテキスト形式、ツールは以下の通りだ。

プログラミング言語 チェックツール
Ada gcc、gnatpp (保存時にチェック)
Ansible ansible-lint
API Blueprint drafter
AsciiDoc alex (保存時にチェック)、proselint、redpen、textlint、vale、write-good
ASM gcc
Awk gawk
Bash language-server、bash -n、shellcheck、shfmt
Bats shellcheck
BibTeX bibclean
Bourne Shell sh -n、shellcheck、shfmt
C ccls、clang、clangd、clang-format、clangtidy (保存時にチェック)、cppcheck、cpplint、cquery、flawfinder、gcc、uncrustify
C# csc (保存時にチェック)、mcs、mcsc (保存時にチェック)、uncrustify
C++ ccls、clang、clangcheck (保存時にチェック)、clangd、clang-format、clangtidy (保存時にチェック)、clazy (保存時にチェック)、cppcheck、cpplint (保存時にチェック)、cquery、flawfinder、gcc、uncrustify
Chef cookstyle、foodcritic
Clojure clj-kondo、joker
CloudFormation cfn-python-lint
CMake cmake-format、cmakelint
CoffeeScript coffee、coffeelint
Crystal ameba (保存時にチェック)、crystal (保存時にチェック)
CSS csslint、fecs、prettier、stylelint
Cucumber cucumber
CUDA nvcc
Cypher cypher-lint
Cython cython
D dfmt、dls、dmd、uncrustify
Dafny dafny
Dart dartanalyzer (保存時にチェック)、dartfmt、language_server
Dockerfile dockerfile_lint、hadolint
Elixir credo、dialyxir (保存時にチェック)、dogma (保存時にチェック)、elixir-ls (デフォルト無効)、mix (保存時にチェック(デフォルト無効))
Elm elm-format、elm-ls、elm-make
Erb erb、erubi、erubis、ruumba
Erlang erlc、SyntaxErl
Fish fish -n
Fortran gcc、language_server
Fountain proselint
FusionScript fusion-lint
Git Commit Messages gitlint
GLSL glslang、glslls
Go bingo (デフォルト無効)、go build (保存時にチェック(デフォルト無効))、gofmt、goimports (デフォルト無効)、golangci-lint (保存時にチェック(デフォルト無効))、golangserver (デフォルト無効)、golint、gometalinter (保存時にチェック(デフォルト無効))、go mod (保存時にチェック(デフォルト無効))、gopls (デフォルト無効)、gosimple (保存時にチェック(デフォルト無効))、gotype (保存時にチェック(デフォルト無効))、go vet (保存時にチェック)、revive (保存時にチェック(デフォルト無効))、staticcheck (保存時にチェック(デフォルト無効))
GraphQL eslint、gqlint、prettier
Hack hack、hackfmt、hhast (デフォルト無効)
Haml haml-lint
Handlebars ember-template-lint
Haskell brittany、cabal-ghc、floskell、ghc、ghc-mod、hdevtools、hfmt、hie、hindent、hlint、stack-build (保存時にチェック)、stack-ghc、stylish-haskell
HCL terraform-fmt
HTML alex (保存時にチェック)、fecs、html-beautify、HTMLHint、prettier、proselint、tidy、write-good
Idris idris
Ink ink-language-server
ISPC ispc (保存時にチェック)
Java checkstyle、eclipselsp、google-java-format、javac、javalsp、PMD、uncrustify
JavaScript eslint、fecs、flow、jscs、jshint、prettier、prettier-eslint、prettier-standard、standard、tsserver、xo
JSON fixjson、jq、jsonlint、prettier
Julia languageserver
Kotlin kotlinc (保存時にチェック)、ktlint (保存時にチェック)、languageserver
LaTeX alex (保存時にチェック)、chktex、lacheck、proselint、redpen、texlab、textlint、vale、write-good、
Less lessc、prettier、stylelint
LLVM llc
Lua luac、luacheck
Mail alex (保存時にチェック)、languagetool (保存時にチェック)、proselint、vale
Make checkmake
Markdown alex (保存時にチェック)、languagetool (保存時にチェック)、markdownlint (保存時にチェック)、mdl、prettier、proselint、redpen、remark-lint、textlint、vale、write-good
MATLAB mlint
Mercury mmc (保存時にチェック)
NASM nasm (保存時にチェック)
Nim nim check (保存時にチェック)、nimlsp、nimpretty
nix nix-instantiate、nixpkgs-fmt
nroff alex (保存時にチェック)、proselint、write-good
Objective-C ccls、clang、clangd、uncrustify
Objective-C++ clang、clangd、uncrustify
OCaml merlin、ocamlformat、ocp-indent、ols
Pawn uncrustify
Perl perl -c (デフォルト無効)、perl-critic、perltidy
Perl6 perl6 -c (デフォルト無効)
PHP langserver、phan see :help ale-php-phan to instructions、phpcbf、phpcs、php-cs-fixer、php -l、phpmd、phpstan、psalm (保存時にチェック)
PO alex (保存時にチェック)、msgfmt、proselint、write-good
Pod alex (保存時にチェック)、proselint、write-good
Pony ponyc
PowerShell powershell (保存時にチェック)、psscriptanalyzer (保存時にチェック)
Prolog swipl
proto protoc-gen-lint
Pug pug-lint
Puppet languageserver、puppet、puppet-lint
PureScript purescript-language-server、purty
Python autopep8、bandit (デフォルト無効)、black、flake8、isort、mypy、prospector (デフォルト無効)、pycodestyle (デフォルト無効)、pydocstyle (デフォルト無効)、pyflakes、pylama (保存時にチェック)、pylint (保存時にチェック)、pyls (デフォルト無効)、pyre (デフォルト無効)、reorder-python-imports、vulture (保存時にチェック(デフォルト無効))、yapf
QML qmlfmt、qmllint
R lintr、styler
Racket raco
ReasonML merlin、ols、reason-language-server、refmt
reStructuredText alex (保存時にチェック)、proselint、redpen、rstcheck、textlint、vale、write-good
Re:VIEW redpen
RPM spec rpmlint (デフォルト無効)
Ruby brakeman (保存時にチェック)、debride (保存時にチェック)、rails_best_practices (保存時にチェック)、reek、rubocop、ruby、rufo、solargraph、sorbet、standardrb
Rust cargo (保存時にチェック)、rls (デフォルト無効)、rust-analyzer (デフォルト無効)、rustc (デフォルト無効)、rustfmt
Sass sass-lint、stylelint
Scala fsc、metals、sbtserver、scalac、scalafmt、scalastyle
SCSS prettier、sass-lint、scss-lint、stylelint
Slim slim-lint
SML smlnj
Solidity solc、solhint、solium
SQL pgformatter、sqlfmt、sqlformat、sqlint
Stylus stylelint
SugarSS stylelint
Swift sourcekit-lsp、swiftformat、swiftlint
Tcl nagelfar (保存時にチェック)
Terraform fmt、tflint
Texinfo alex (保存時にチェック)、proselint、write-good
Text alex (保存時にチェック(デフォルト無効))、languagetool (保存時にチェック)、proselint (デフォルト無効)、redpen (デフォルト無効)、textlint (デフォルト無効)、vale (デフォルト無効)、write-good (デフォルト無効)
Thrift thrif
TypeScript eslint、fecs、prettier、standard、tslint、tsserver、typecheck
VALA uncrustify
Verilog iverilog、verilator、vlog、xvlog
VHDL ghdl、vcom、xvhdl
Vim vimls、vint
Vim help alex (保存時にチェック(デフォルト無効))、proselint (デフォルト無効)、write-good (デフォルト無効)
Vue prettier、vls
XHTML alex (保存時にチェック)、proselint、write-good
XML xmllint
YAML prettier、swaglint、yamllint
YANG yang-lsp

上記テーブルはGitHubに公開されている「ALE Supported Languages and Tools」のデータを表にしたものだ。最新の対応状況はこちらのページの内容を参照してほしい。

例えば、JSONファイルの編集をするなら「fixjson」「jq」「jsonlint」「prettier」をインストールしておけばよい。どれか1つでもよいし、全部インストールしてもかまわない。ALEでは個々のツールは排他的ではなく補完的に利用されるので、インストールしておけばそれだけ包括的にチェックが行われることになる。

また、XMLファイルの静的解析を行いたいのであれば、「xmllint」がインストールされていればよいことになる。Ubuntu 18.04 LTSで調べると、xmllintは「libxml2-utils」というパッケージに含まれていることがわかる。

xmllintはlibxml2-utilsに含まれている

パッケージをインストールしておけば、後はALEがこのツールを使って適当なタイミングで静的解析を行い、問題があれば報告してくれる。

ALEの動作サンプル

実際にALEが動作するところを見てみよう。次のスクリーンショットは、誤ったフォーマットのXMLファイルをVimで編集しているものだ。しかし、xmllintがインストールされていないため、ユーザーには何の報告も行われていない。

静的解析ツールがインストールされていないので動作していない

ここでxmllintをインストールしてから同じ操作を行うと、次のようにxmllintの動作結果がVimの画面に表示されるようになる。問題がある行に自動的に通知が入り、さらにVim下部にエラー内容を示すメッセージが表示されるようになる。

静的解析ツールがインストールされていると、チェック結果が報告される

動作させているとわかると思うが、この機能はかなり便利だ。シンタックスエラーのような単純なミスをミスした段階で知ることができる。編集するファイルがあまりにも巨大だったり、PCのスペックが相当に低いと処理の重さを感じることがあるかもしれないが、その場合は機能を無効化するなり、設定を変更するなりしてチェックの頻度を調整すればよい。

今回の成果物

今回のプラグイン設定を追加した設定ファイルは以下の通りだ。

"dein Scripts
if &compatible
  set nocompatible               " Be iMproved
endif

" Required:
set runtimepath+=~/.cache/dein/./repos/github.com/Shougo/dein.vim

" Required:
if dein#load_state('~/.cache/dein/.')
  call dein#begin('~/.cache/dein/.')

  " Let dein manage dein
  " Required:
  call dein#add('~/.cache/dein/./repos/github.com/Shougo/dein.vim')

  " Add or remove your plugins here
  call dein#add('junegunn/seoul256.vim')
  call dein#add('vim-airline/vim-airline')
  call dein#add('vim-airline/vim-airline-themes')
  call dein#add('preservim/nerdtree')
  call dein#add('tpope/vim-commentary')
  call dein#add('tpope/vim-fugitive')
  call dein#add('fholgado/minibufexpl.vim')
  call dein#add('dense-analysis/ale')

  " Required:
  call dein#end()
  call dein#save_state()
endif

" Required:
filetype plugin indent on
syntax enable

" If you want to install not installed plugins on startup.
if dein#check_install()
  call dein#install()
endif

" seoul256
let g:seoul256_background = 233
colo seoul256

" vim-airline
let g:airline_powerline_fonts = 1
let g:airline_theme = 'molokai'

" NERDTree
"  <C-o> open NERDTree
nnoremap <silent> <C-o> :NERDTreeToggle<CR>

" minibufexpl
nnoremap <silent> bn :<C-u>:bnext<CR>
nnoremap <silent> b1 :<C-u>:b1<CR>
nnoremap <silent> b2 :<C-u>:b2<CR>
nnoremap <silent> b3 :<C-u>:b3<CR>
nnoremap <silent> b4 :<C-u>:b4<CR>
nnoremap <silent> b5 :<C-u>:b5<CR>
nnoremap <silent> b6 :<C-u>:b6<CR>
nnoremap <silent> b7 :<C-u>:b7<CR>
nnoremap <silent> b8 :<C-u>:b8<CR>
nnoremap <silent> b9 :<C-u>:b9<CR>

"End dein Scripts

set number
syntax on
set whichwrap=b,s,[,],<,>,~,h,l
set cursorline
set incsearch
set hlsearch
set ignorecase