neoformatで使うshfmtはデフォルトだとインデントがスペースだが、チームのコーディング規約に合わせてタブ文字へ変更したかったときにちょっと引っかかったのでメモ。

まずは、shfmt のヘルプとneoformatshfmtの定義を見てみる。

  -i uint   indent: 0 for tabs (default), >0 for number of spaces
function! neoformat#formatters#sh#shfmt() abort
    return {
            \ 'exe': 'shfmt',
            \ 'args': ['-i ' . shiftwidth()],
            \ 'stdin': 1,
            \ }
endfunction

shfmtのヘルプから、インデントをタブにしたければ-i引数で0を渡せば良さそう。neoformatの定義ではインデントの値にshiftwidthの値をしているようだったので、プロジェクトでのVimの設定を以下のように設定してみた(プロジェクト固有の設定ができるようにしている)。

autocmd Filetype sh setlocal sw=0 sts=0 noexpandtab

しかし、どうしてもインデントがスペースになってしまうためちゃんとshiftwidth()の挙動を調べてみると、shiftwidthが0に設定されているとtabstopの値を使うようになっているらしい。

https://vim-jp.org/vimmagazine/2012/08/31/vimmagazine.html

tabstopは0を設定できないため、結局以下のようにneoformatshfmt設定をプロジェクト固有の設定で上書きして対処した。

let g:neoformat_sh_shfmt = {
      \   'exe': 'shfmt',
      \   'args': ['-i', 0],
      \   'stdin': 1,
      \ }