純粋なvimscriptで置換( `:s`なし)


12

私は私のvimrcに以下を持っています:

func! AddSpaceBeforeEqual()
  s/\([a-z)_0-9"'\[\]]\)=/\1 =/ge
endfunc

vimrcのlintにvintを使用していて、次の警告が表示されました。

ProhibitCommandWithUnintendedSideEffect 意図しない副作用のあるコマンドを回避します。:s [ubstitute]を使用すると、カーソルが移動してエラーメッセージが出力されるため、使用しないでください。スクリプトにより適した関数(search()など)を優先します。多くのvimコマンドには、副作用が少なく同じことを行う関数が存在します。組み込み関数のリストについては、:help functions()を参照してください。Google Vimscriptスタイルガイド

ただし、:sコマンドを使わずに置換を行う方法だとは思いません。

たとえば、search()関数はパターンに一致する行を提供しますが、置換を行う方法はありません。このsubstitute()関数は文字列を操作し、ファイル全体を置き換えません。

自分で代替メソッドを実装する必要がありますか、それとも私の関数を書き換えるよりスマートな方法ですか?

回答:


10

意図しない副作用について警告しているのは:substitute、がカーソルを移動し、以前の検索を上書きするためです(関数の外で使用した場合)。ただし、これは、の副作用を元に戻すことができるため、これを使用してはならないという意味ではありません:substitute。たとえば、次の関数は、代替コマンドを使用して末尾の空白を削除する関数です。

function! StripTrailingWhitespace()
    " Save cursor position
    let l:save = winsaveview()
    " Remove trailing whitespace
    %s/\s\+$//e
    " Move cursor to original position
    call winrestview(l:save)
    echo "Stripped trailing whitespace"
endfunction

:markコマンドを使用してカーソル位置を保存することもできますが、使用するマークを上書きすることにも注意してください。私は以前ヴィントを使ったことがありませんが、リンターに関する一つのヒントは、あなたが彼らの警告を塩の粒で取ることができるということです。この場合、:substitute副作用があることは事実ですが、それは防止できる副作用です。それに加えて、ファイル内で検索と置換を行うためのより良い方法はありません。


6
関数を終了すると、最後に使用された検索語が自動的に復元されるため、関数内で使用する場合は、保存して復元する必要はありません。参照:help function-search-undo
Martin Tournoij

1
代わりに、cursor()の代わりにwinsaveview()/ winrestview()を使用してください
クリスチャンブラバンド

9

以下は、関数を単純化して実装したものですsubstitute()

function! AddSpaceBeforeEqualInWholeBuffer()
    let l = 1
    for line in getline(1,"$")
        call setline(l, substitute(line, '\([^= ]\)=', '\1 =', "g"))
        let l = l + 1
    endfor
endfunction

好みに合わせて検索パターンを調整してください。


1

:sこのコマンドは、純粋なVimscriptアプローチです。

私の推測では、警告は、カーソルがその使用後に誤って配置される可能性が高いことを意味します(使用winsaveview()前とwinrestview()使用後のコマンドを使用することで回避できます)。また、発生する可能性のあるエラーに注意する必要があります。これは通常、eフラグを使用して処理されます。またgdefaultgフラグの意味を反転させる設定など、いくつかの設定に注意する必要があります。

これらの詳細に注意する必要があり、それがおそらくこれらの警告の根本的な原因です。しかし、それは:sコマンドの使用を避けることを意味するものではありません。:s現在のバッファの何かを置き換えたい場合は、コマンドを使用しても問題ありません。

(もちろん、すべての行をループしてsearch()/ getline()/ setline()アプローチを使用することもできますが、通常は遅くなります。)

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.