Vim の 5 つのタブとスペース関連のややややこしいオプションをできるだけ簡単に解説するよ
Vim の 5 つのオプション tabstop, softtabstop, shiftwidth, expandtab, smarttab は, タブとスペースの入力方法をとても細かく設定できるが故に, やや混乱を招きがちという感じですので, できるだけ簡単に解説します.
Vim のバージョンは 8.1 を使用しております.
それぞれのオプション
'tabstop', 'softtabstop', 'shiftwidth', 'expandtab', 'smrattab' という 5 つのオプションは, Vim においてタブとスペースをどのように入力するかを決めるためのものです.
それぞれ 5 つのオプションの簡単な説明をさせていただきます.
'tabstop'
'tabstop' は何個分のスペースで 1 つのタブとしてカウントするかを設定するオプションです.
デフォルトの値は 8 です.
'softtabstop'
'softtabstop' は <Tab> を押した時, 何個分のスペースを挿入するかを設定するオプションです.
もし挿入されたスペースの数が 'tabstop' の値に達すると, そのスペースはタブに変換されます. ('expandtab' がオフの場合)
デフォルトの値は 0 です.
この値が 0 の場合, 'softtabstop' の機能はオフになります.
この値が -1 など負の数の場合, 'shiftwidth' の値が使われます.
'shiftwidth'
'shiftwidth' は <Enter> を押して改行した時や, ノーマルモードの <<, >>, インサートモードの CTRL-D, CTRL-T コマンドなどで行をインデントした時, スペース何個分インデントさせるかを設定するオプションです.
'softtabstop' と同じく, 挿入されたスペースの数が 'tabstop' の値に達すると, そのスペースはタブに変換されます. ('expandtab' がオフの場合)
デフォルトの値は 8 です.
この値が 0 の場合, 'tabstop' の値が使われます.
'expandtab'
'expandtab' がオンの場合, 'softtabstop' や 'shiftwidth' で設定されている値分のスペースが挿入された時, 挿入されたスペースの数が 'tabstop' の値に達してもタブに変換されず, スペースのまま保たれます.
タブ (CHARACTER TABULATION) を一切使わず, 常にスペース (SPACE) を使いたいという時のオプションです.
デフォルトはオフです.
'smarttab'
'smarttab' がオンの場合, 行頭の前で <Tab> を押した時, 'shiftwidth' 分のスペースが挿入されます.
挿入されたスペースの数が 'tabstop' の値に達した場合, タブに変換されます. ('expandtab' がオフの場合)
もし 'smarttab' がオフの場合, 行頭の前に挿入されるスペースの数は 'tabstop' や 'softtabstop' の値によります.
設定の例
それぞれのオプションの説明をさせていただいたところで, 実際にそれぞれのオプションをどのように設定すると, どのような感じでタブとスペースが挿入されるのかという例を紹介させていただきます.
尚, Vim の :help 'tabstop' のヘルプを参考にさせていただきました.
タブとスペースをミックスさせて使う
'tabstop' をデフォルトの 8 のままにし, 'softtabstop' と 'shiftwidth' を 4 にします. そして 'expandtab' をオフにします:
:set tabstop=8
:set softtabstop=4
:set shiftwidth=4
:set noexpandtab
この設定だと, 一回 <Tab> を押すと 4 つのスペースが挿入されますが, もう一回押すと 8 つのスペース分のタブに変換されます. このようにタブとスペースを状況に応じて使い分けたい時に便利な設定です. また 'shiftwidth' が 4 なので, << や >> で行をインデントさせる時に, スペース 4 つ分インデントされます.
スペースのみ使う
'tabstop' を 2 に設定し, 'shiftwidth' も 2 にします. そして 'expandtab' をオンにします:
:set tabstop=2
:set shiftwidth=2
:set expandtab
この設定だと, <Tab> を何回押してもタブに変換されることはなく, 常に 2 つ分のスペースが挿入されます.
'softtabstop' を設定していないため, デフォルトの 0 となり, 機能がオフになっているので, 'tabstop' の値分スペースが挿入されることになります.
また 'shiftwidth' を 0 にすると, 'tabstop' の値が使われるため, 次のように 0 にしても同じ意味の設定になりますね:
:set tabstop=2
:set shiftwidth=0
:set expandtab
個人的には 'tabstop' と 'shiftwidth' を同じ値にするのであれば, 'tabstop' のみ任意の値に設定すれば良いこちらの方法がより好みです.
もし <Tab> を押して 4 つのスペースを挿入させたい場合, 次のように 'tabstop' の値を 4 に変更するだけでいいですからね:
:set tabstop=4
:set shiftwidth=0
:set expandtab
ファイルタイプ別に設定する
.vimrc に直接 'tabstop', 'softtabstop', 'shiftwidth', 'expandtab', 'smarttab' を設定すると, C, C++, Java, JavaScirpt, PHP, Python, Ruby など全てのファイルタイプで同じ設定が使われてしまいます.
それだと都合が悪いですよね.
なので autocmd というコマンドを使って, ファイルタイプ別にそれらのオプションを設定する方法を紹介します.
.vimrc で autocmd を次のような構文で使うと, 特定の <filetype> の時のみ, 指定の <option>... を設定することができます:
autocmd FileType <filetype> setlocal <option>...
また setlocal というのは, 結構重要なコマンドでして, setlocal でオプションを設定することによって, 特定のファイルタイプのバッファのみにその設定が適用されます. もし setlocal の代わりに set を使ってしまうと, 開いたバッファに適用された設定が, そのバッファと同じウィンドウで後から開いた別のバッファにも適用されてしまいます.
この autocomd を使って, 例えば .vimrc で, ファイルタイプが Python の時, 'tabstop' を 4, 'shiftwidth' を 0, 'expandtab' をオンに設定して, ファイルタイプが Ruby の時, 'tabstop' を 2, 'shiftwidth' を 0, 'expandtab' をオンに設定する場合, 次のようになります:
autocmd FileType python setlocal tabstop=4 shiftwidth=0 expandtab
autocmd FileType ruby setlocal tabstop=2 shiftwidth=0 expandtab
もしくは, 共通の 'tabstop', 'shiftwidth', 'expandtab' を設定して, 異なる値のオプションだけ autocmd で設定するという方法もあります:
set tabstop=2
set shiftwidth=0
set expandtab
autocmd FileType python setlocal tabstop=4
また autocmd は Vim が autocmd フラグ付きでコンパイルされている必要があります.
それを確かめる場合, 次のコマンドで確かめられます:
$ vim --version | grep autocmd
+autocmd +find_in_path +mouse_urxvt +termguicolors
このように +autocmd と + サインが頭に付いた autocmd が表示されれば, autocmd という機能が有効であると確認できます.
またファイルタイプを検知するため, :filetype on と設定する必要もあります.
なので最後の例の場合ですと, より厳密には次のようにするといいです:
filetype on
set tabstop=2
set shiftwidth=0
set expandtab
if has("audocmd")
autocmd FileType python setlocal tabstop=4
endif
まとめ
'tabstop', 'softtabstop', 'shiftwidth', 'expandtab', 'smarttab' という 5 つのオプションは Vim を使い始めた人にとって, なかなか混乱を招きかねないややこしい設定かと思います.
実際僕はそれらのオプションを理解するのに, いろいろ値を変えて試したりして, なんとなく理解したという感じです.
詳しい挙動まで完全に理解しているという自信は全くありませんが, 今の僕の理解している範囲で説明させていただきました.
それら 5 つのオプションは, タブとスペースをどのように入力するかという重要な設定だけに, 理解せざるを得ない感じなので, Vim でタブとスペースの設定をしたいけど, どのようにすればいいのかよくわからないという方は, 今回の内容を参考にしていただけましたら幸いです.
ところで Neovim の場合, 'smarttab' はデフォルトでオンになっているので, Neovim の設定ファイル init.vim に set smarttab と設定する必要はありませんね.
参照資料
関連記事
Git の mergetool で vimdiff を指定して Vim でマージコンフリクトを解決してみた2018.08.20
Vim プラグイン ri.vim で Ruby のドキュメントを Vim の中でも見れてしまう2018.09.13
Vim で最後に選択した範囲を再選択するのに gv コマンドが便利2018.07.10
Vim の :nmap と :nnoremap の違い2018.08.02
Ruby のクラスやメソッドのドキュメントを見れる ri コマンドが便利な件2018.09.08