Vimでタブ・改行・行末スペースを可視化する(listchars)
インデントがタブなのかスペースなのか、目で見ただけでは判別できずレビューで指摘されたことがあります。見えない文字を記号として表示させれば、この手の混在は一目で分かるようになります。
目次(11項目)
基本の設定
set list
set listchars=tab:>\ ,trail:-,eol:$
listを有効にし、listcharsでそれぞれの記号を指定します。設定した瞬間から、タブや行末の余分なスペース、改行位置が記号として見えるようになります。
listchars=tab:>-,trail:-,eol:$,multispace:. を指定した画面。タブとスペースの混在が見分けられる主なlistcharsの項目
| 項目 | 対象 |
|---|---|
tab | タブ文字 |
trail | 行末の余分な半角スペース |
eol | 改行位置 |
space | 通常の半角スペース |
nbsp | 見た目上は空白だが実体が異なる特殊なスペース |
extends | 画面幅が足りず右に隠れた文字がある印 |
precedes | 画面幅が足りず左に隠れた文字がある印 |
タブとスペースの混在を見つける
インデントの規約が統一されていないプロジェクトで問題になりやすいのが、タブとスペースの混在です。tabstopの設定次第では、タブ1個とスペース数個が画面上ほとんど同じ幅に見えてしまい、目視では区別が付きません。
foo();
bar();
> foo(); ....bar();
1行目はタブ1個、2行目は半角スペース4個のインデントですが、:set listを実行するまで見た目では判別できません。tabとspaceそれぞれに違う記号を割り当てておけば、混在している箇所が視覚的にすぐ分かります。
set listchars=tab:»\ ,space:·,trail:-
全角スペースも見分けたい場合
日本語文書では全角スペースが紛れ込んでいても気づきにくいものです。listchars自体は全角スペース専用の項目を持ちませんが、シンタックスハイライトのルールを別途追加することで、全角スペースだけを背景色付きで強調表示することもできます。listcharsと組み合わせれば、半角・全角どちらの見えない文字も洗い出せます。
切り替えて使う
常時表示しておくと文字が多くて読みにくいと感じるなら、必要なときだけ:set list/:set nolistで切り替えても構いません。トグルするキーマッピングを用意しておくと、確認したいときだけサッと表示できます。
nnoremap <Leader>l :set list!<CR>
set list+listcharsを使います。常時表示が煩わしければトグル用のマッピングを用意すると便利です。
Pull Requestでインデントの指摘を何度か受けてから、listcharsを設定するようになりました。保存前に一目で混在に気づけるようになり、レビューで同じ指摘を受けることがほぼ無くなりました。地味な設定ですが、チーム開発をする人ほど恩恵が大きいと思います。行末の余分なスペースも同時に見えるようになったのは、想定外の副産物でした。
expandtab/tabstopとあわせて設定する
可視化と同時に、インデントの実際の挙動も統一しておくと効果が高まります。expandtabを有効にするとタブキー入力が自動的にスペースへ変換され、tabstop/shiftwidthで幅を揃えられます。可視化だけして実際のインデント設定がバラバラのままだと、根本的な混在は解消しません。すでにファイルに入っているタブは設定を変えても残るので、:retab で変換するほうへ回してください。
set expandtab
set tabstop=2
set shiftwidth=2
空白の連なりを見分ける
trail は行末の空白しか出しません。行の途中に紛れ込んだ余分な空白や、全角スペースは見えないままです。Vim 9.1.1752では次の項目も使えます。
set listchars=tab:>-,trail:-,nbsp:%,multispace:···,leadmultispace:\ \ \
nbsp はノーブレークスペース、multispace は連続する空白、leadmultispace は行頭のインデント部分の空白に別の記号を割り当てる指定です。インデントだけは目立たせず、本文中の連続空白だけを出す、といった使い分けができます。
行末の空白をまとめて消す
見えるようになったら、次は消し方です。置換1行で済みます。
:%s/\s\+$//e " 行末の空白を全部消す
autocmd BufWritePre *.py :%s/\s\+$//e
e フラグは、対象が見つからなくてもエラーにしないという指定です。保存時に自動で消す設定は便利ですが、他人のリポジトリで有効にすると、自分が触っていない行まで差分に出ます。拡張子やパスで対象を絞ってください。
この置換はカーソル位置と検索履歴を動かすので、気になる場合は実行前後の位置を保存して戻す関数にまとめておくと使いやすくなります。
全角スペースを目立たせる
日本語の文書では全角スペースが紛れ込みます。listchars には項目がないので、ハイライトの指定で色を付ける方法を使います。
highlight IdeographicSpace ctermbg=DarkGreen guibg=DarkGreen
match IdeographicSpace / /
match はウィンドウごとに1つしか持てないので、他の用途で使っている場合は 2match や matchadd() を使います。コードに全角スペースが混ざると構文エラーになるうえ、原因が見た目から分からないので、日本語を扱う環境では入れておく価値があります。
まとめ
listcharsは見えない文字のトラブルを未然に防ぐための地味だが効果的な設定です。チームでインデント規約を統一している環境では特に価値が高くなります。