🈲

Vimでやべー名前のファイルが保存されるのを防止する

2023/07/07に公開

この記事はVim駅伝の2023-07-07の記事です。
前回の記事はtaniさんのタイポ修正を支える技術です。
次回の記事はtaniさんのVimmerのレベル10です。


先日Vimで:write <>.txtとしてみたら保存できてしまいました。
その文字はリダイレクトに使われるんです (><)

ファイル名にやばそうな文字が入っていたときには保存を中止できると良さそうです。
autocmdのBufWritePreイベントを使ったファイル名の検証処理を書いてみました。

vimrc
function! s:validate_filename(filename) abort
  " 特定の文字が含まれていたらerror
  const invalid_chars = '!&()[]{}<>^*=+:;''",`~?|'
  for char in split(invalid_chars, '\zs')
    if stridx(a:filename, char) >= 0
      throw 'Filename has invalid char: ' .. a:filename
    endif
  endfor

  " 正規表現にあっていなかったらerror
  const valid_pattern = '\.\?[[:alnum:]]\+$'
  if a:filename !~ valid_pattern
    throw 'Filename is invalid format: ' .. a:filename
  endif
endfunction

augroup on_save
  autocmd!
  autocmd BufWritePre * call s:validate_filename(expand('<afile>:p'))
augroup END

上記の例では「ファイル名に記号類が含まれていないこと」「拡張子が英数字であること」を検証しています(ファイル名も英数字限定なら単純なのですが、日本語環境だとそうもいきませんね)。
検証したい内容は内容は環境に応じて適宜変更してください。

なお、設定をミスってしまうと、vimrc自体の保存もできなくなる可能性があります。その場合は、いったん上記の設定を無効化し、noautocmd writeを使ってautocmdを回避して保存しましょう。


…という記事を書いたあとに、interrupt()のヘルプにもっと良い例があったことを知りました。
本記事は残しておきますが、ヘルプの例も参考になるので、ぜひご覧ください。

https://vim-jp.org/vimdoc-ja/builtin.html#interrupt()

Discussion