Neovim x null-ls x cspellの設定詳解
先日mason.nvimを導入しました。
mason.nvimは前身のnvim-lsp-installerができなかったlinterのインストールにも対応しているため、これを機にcspellを使ってみようと思い立ちました。
いい感じに動くところまで作れたので、設定を解説します。
cspellのインストール
mason.nvimを使います。
vim-plugなどのプラグインマネージャでmason.nvimを読み込んでください。
call plug#begin(stdpath('config') .. '/plugged')
Plug 'williamboman/mason.nvim'
call plug#end()
:MasonInstall cspell
でcspellをインストールできます。
:Mason
で開く設定画面のInstalledに表示されればOKです(この画面内からインストールすることもできます)。
:!cspell -V
で確認しても良いでしょう。
cspellをnull-lsに設定
cspellをインストールしただけではスペルチェックが動作しません。
null-lsを使ってcspellを実行し、バッファに反映させましょう。
call plug#begin(stdpath('config') .. '/plugged')
Plug 'williamboman/mason.nvim'
Plug 'jose-elias-alvarez/null-ls.nvim' " 追加
call plug#end()
" luaヒアドキュメントで設定を書くこともできますが、
" 設定が多くなる場合は、別ファイルに書いてluafileで呼び出すほうが
" 見通しが良くなると思います
luafile ~/.config/nvim/plugin_config/null_ls.lua
local null_ls = require('null-ls')
local sources = {
null_ls.builtins.diagnostics.cspell.with({
diagnostics_postprocess = function(diagnostic)
-- レベルをWARNに変更(デフォルトはERROR)
diagnostic.severity = vim.diagnostic.severity["WARN"]
end,
condition = function()
-- cspellが実行できるときのみ有効
return vim.fn.executable('cspell') > 0
end
})
}
null_ls.setup({
sources = sources
})
これで画面に表示が出るはずです。
なお、ここではwith()
を使って、cspellのエラーレベルの変更と、コマンド実行確認を行っています。
詳細は https://github.com/jose-elias-alvarez/null-ls.nvim/blob/main/doc/BUILTIN_CONFIG.md を確認してください。
cspell設定ファイルの追加
cspellの標準設定では、一般的な英単語以外はすべて警告対象になってしまいます。
設定ファイルで辞書の追加などを行うことができます。
{
"allowCompoundWords": true,
"dictionaries": [
"dotfiles",
"lua",
"user",
"vim"
],
"dictionaryDefinitions": [
{
"name": "dotfiles",
"path": "~/.config/cspell/dotfiles.txt",
"description": "dotfiles dictionary"
},
{
"name": "user",
"path": "~/.local/share/cspell/user.txt",
"description": "User local dictionary"
},
{
"name": "vim",
"path": "~/.local/share/cspell/vim.txt.gz",
"description": "Vim Script Language dictionary"
}
],
"languageSettings": [
{
"languageId": "lua",
"locale": "*",
"ignoreRegExpList": [
"/require.*/"
],
"dictionaries": [
"lua"
]
},
{
"languageId": "vim",
"locale": "*",
"ignoreRegExpList": [
"/Plug .*/"
],
"dictionaries": [
"vim"
]
}
]
}
null-lsでcspellを起動するときにこのファイルを読み込むよう設定します。
-- 無関係の部分は省略
local sources = {
null_ls.builtins.diagnostics.cspell.with({
-- 起動時に設定ファイル読み込み
extra_args = { '--config', '~/.config/cspell/cspell.json' }
})
}
以下では、各設定項目について解説します。
allowCompoundWords
複合語を許容する設定です。
cspellはデフォルトでsnake_case
やcamelCase
を解釈するため、例えばdot_files
dotFiles
dotfiles
を例に取ると以下のようになります。
-
dot_files
/dotFiles
はdot
+files
とみなされ、エラーが出ない -
dotfiles
は1単語とみなされ、エラーになる
このオプションをtrue
に設定しておくと、dotfiles
もdot
+files
と認識され、エラーが出なくなります。
dictionaries
追加辞書の名前の配列です。デフォルトの辞書にない語彙を追加することができます。
公式のリストはこちらです。
各種プログラミング言語の辞書だけでなく、非英語の辞書や、companies
やlorem-ipsum
などの面白い語彙の辞書も提供されています。
(city-names-finland
はなぜ公式で出しているのか謎…)
また、公式で提供されていない辞書も、次のdictionaryDefinitions
で設定することができます。
dictionaryDefinitions
ユーザー辞書の定義の配列です。
配列の要素は、name
とpath
の要素をもつオブジェクトである必要があります。
-
name
は辞書の名前です。ここで定義した名前をdictionaries
の配列にも登録しておく必要があります。 -
path
は辞書のパスです。相対パスを使うとcspell.json
からの相対パスとして解釈されます。基本的には.txt
ファイルですが、.txt.gz
ファイルもそのまま使えました。
例えば、Vimのキーワード辞書はcspell公式では提供されていないので、ここで設定する必要があります。
筆者はcoc-spellのリポジトリから拝借しました。
また、筆者はdotfiles
とuser
の2つのユーザー辞書を作成し、以下のように使い分けています。
-
dotfiles
: dotfilesリポジトリに入れて公開し、他の環境でも使いたい語彙(kawarimidoll
など) -
user
: スペルチェックからは除外したいが、公開はしたくない語彙(仕事で使う単語など)
null-lsの設定に、辞書を自動でダウンロード・作成する処理を追加しておくと便利です。
-- vim辞書がなければダウンロード
if vim.fn.filereadable('~/.local/share/cspell/vim.txt.gz') ~= 1 then
local vim_dictionary_url = 'https://github.com/iamcco/coc-spell-checker/raw/master/dicts/vim/vim.txt.gz'
io.popen('curl -fsSLo ~/.local/share/cspell/vim.txt.gz --create-dirs ' .. vim_dictionary_url)
end
-- ユーザー辞書がなければ作成
if vim.fn.filereadable('~/.local/share/cspell/user.txt') ~= 1 then
io.popen('mkdir -p ~/.local/share/cspell')
io.popen('touch ~/.local/share/cspell/user.txt')
end
languageSettings
言語ごとにスペルチェックを無視する設定ができます。
筆者は、luaでは/require.*/
、vimでは/Plug .*/
が無視されるよう設定しています。
どちらもプラグイン名が後ろに続くことが想定され、特殊な語彙が含まれる可能性が高いためです。
設定ファイルまとめ
これまでの設定をまとめると、以下のようになります。
call plug#begin(stdpath('config') .. '/plugged')
Plug 'williamboman/mason.nvim'
Plug 'jose-elias-alvarez/null-ls.nvim'
call plug#end()
luafile ~/.config/nvim/plugin_config/null_ls.lua
-- $XDG_CONFIG_HOME/cspell
local cspell_config_dir = '~/.config/cspell'
-- $XDG_DATA_HOME/cspell
local cspell_data_dir = '~/.local/share/cspell'
local cspell_files = {
config = vim.call('expand', cspell_config_dir .. '/cspell.json'),
dotfiles = vim.call('expand', cspell_config_dir .. '/dotfiles.txt'),
vim = vim.call('expand', cspell_data_dir .. '/vim.txt.gz'),
user = vim.call('expand', cspell_data_dir .. '/user.txt'),
}
-- vim辞書がなければダウンロード
if vim.fn.filereadable(cspell_files.vim) ~= 1 then
local vim_dictionary_url = 'https://github.com/iamcco/coc-spell-checker/raw/master/dicts/vim/vim.txt.gz'
io.popen('curl -fsSLo ' .. cspell_files.vim .. ' --create-dirs ' .. vim_dictionary_url)
end
-- ユーザー辞書がなければ作成
if vim.fn.filereadable(cspell_files.user) ~= 1 then
io.popen('mkdir -p ' .. cspell_data_dir)
io.popen('touch ' .. cspell_files.user)
end
local null_ls = require('null-ls')
local sources = {
null_ls.builtins.diagnostics.cspell.with({
diagnostics_postprocess = function(diagnostic)
-- レベルをWARNに変更(デフォルトはERROR)
diagnostic.severity = vim.diagnostic.severity["WARN"]
end,
condition = function()
-- cspellが実行できるときのみ有効
return vim.fn.executable('cspell') > 0
end
-- 起動時に設定ファイル読み込み
extra_args = { '--config', cspell_files.config }
})
}
null_ls.setup({
sources = sources
})
{
"allowCompoundWords": true,
"dictionaries": [
"dotfiles",
"lua",
"user",
"vim"
],
"dictionaryDefinitions": [
{
"name": "dotfiles",
"path": "~/.config/cspell/dotfiles.txt",
"description": "dotfiles dictionary"
},
{
"name": "user",
"path": "~/.local/share/cspell/user.txt",
"description": "User local dictionary"
},
{
"name": "vim",
"path": "~/.local/share/cspell/vim.txt.gz",
"description": "Vim Script Language dictionary"
}
],
"languageSettings": [
{
"languageId": "lua",
"locale": "*",
"ignoreRegExpList": [
"/require.*/"
],
"dictionaries": [
"lua"
]
},
{
"languageId": "vim",
"locale": "*",
"ignoreRegExpList": [
"/Plug .*/"
],
"dictionaries": [
"vim"
]
}
]
}
ユーザー辞書への単語の追加
スペルチェックから除外したい単語があった場合、ユーザー辞書にその単語を追加すれば警告を消すことができます。
しかし、いちいち辞書ファイル(上記の設定でいうと~/.local/share/cspell/user.txt
)を開いて単語をコピペするのは面倒です。
これについては別の記事で解説します。
謝辞
Vimのキーワード辞書に関しては@yutkatさんに教えていただきました。
また、null-lsとcspellの設定も@yutkatさんのdotfilesをかなり参考にさせていただきました。
Discussion