読者です 読者をやめる 読者になる 読者になる

Re: listchars=trail:$してたら気持ち悪いのでbuffer保存時に行末スペースを削除するようにした

コメント書こうかと思ったけど長くなりそうなのでこっちに。

listchars=trail:$してたら気持ち悪いのでbuffer保存時に行末スペースを削除するようにした - 日々是鍛錬

コード転載。

command! -bang -bar -complete=file -nargs=0 DeleteSpaceEachLine
\ execute ':%s/\s\+$//'

function! s:AutoUpdate()
  if expand('%') =~ s:savebuf_regex && !&readonly && &buftype == ''
    silent! DeleteSpaceEachLine
    silent update
  endif
endfunction

autocmd MyAutoCmd CursorHold * call s:AutoUpdate()
set updatetime=500
if !exists('s:savebuf')
  let s:savebuf_regex = '.\+'
endif

気になった部分がいくつかあったので添削してみた。
ちなみに以下の添削後のコードは動作確認してないので間違っているかも。間違い見付けたら教えてください><

コマンド定義
command! -bang -bar -complete=file -nargs=0 DeleteSpaceEachLine
\ execute ':%s/\s\+$//'
  • -bang はコマンドが ! を受け付けるようにするもの。今回は使ってないので要らない。
  • -complete はコマンドライン補完の指定。このコマンドは引数がないので要らない。
  • -nargs=0 はデフォルトなので(好みもあるだろうけど)なくてもよい。
  • 実行しているコマンドは変数などを含んでいないので :execute する必要はない。
  • :s にはマッチしなかったときにエラーを出さない e フラグを追加するといいかも。
    • 下見ると :silent で実行しているからなくても良いけど。
command! -bar DeleteSpaceEachLine %s/\s\+$//e
autocmd
autocmd MyAutoCmd CursorHold * call s:AutoUpdate()

多分これは意図的だとは思うけど、この設定はカーソルを止めてしばらくしたら空白を取り除きつつ自動で保存する設定。
自動保存だと知らない人がコピペするといけないので老婆心ながら指摘。
手動保存の際に行うには BufWritePre を使う。

autocmd MyAutoCmd BufWritePre * call s:AutoUpdate()

この場合は s:AutoUpdate() 内の update の行は必要ない。
自動保存と削除を分けるのもアリかも。

function! s:AutoUpdate()
  if expand('%') =~ s:savebuf_regex && !&readonly && &buftype == ''
    silent update
  endif
endfunction

autocmd MyAutoCmd CursorHold * nested call s:AutoUpdate()
autocmd MyAutoCmd BufWritePre * DeleteSpaceEachLine

nested がないと update したときに BufWritePre が発生しないので注意。

exists()
if !exists('s:savebuf')
  let s:savebuf_regex = '.\+'
endif

この exists() の引数はミス?

if !exists('s:savebuf_regex')
  let s:savebuf_regex = '.\+'
endif

ちなみに私の場合

誰も聞いてないだろうけど、私の該当部分の設定はこんな感じ。

" 実際には listchars には他の指定もある
set list listchars=trail:_

行末空白は発見次第抹消するのでそこまで気になったことはないです。
自動化するとたまにいる空行もインデントする派のインデントも消しかねないので自重。
あ、でも今思ったけど以下のようにすれば大丈夫か。

%s/\S\zs\s\+$//e

これなら自動化はアリかもなー。