コマンド「set」の結果を保存して復元する方法は?


7

:h :set私たちはそれを知っているから

:se[t] デフォルト値と異なるすべてのオプションを表示します。

vimscriptでは、ユーザーが変更したこれらのオプションをすべて保存し、それらを変更して、後でユーザーが設定した値に戻したいと思います。

どうすれば簡単にできますか?

:set(または同様のコマンド)の結果を変数に格納し、後でソースまたは別のコマンドに渡して、その内容を復元できる方法はありますか?

または、コマンドの出力を手動で解析する必要がありますか(これは実行できますが、より簡単な代替手段が存在する場合、何の作業もありません)。


オプションは&記号で始まることはすでに知っています。verbose setコマンドを指定して、出力を変数またはレジスターに記録し、それぞれを分割してそれらの値をディクショナリーに保管し、そこから復元することができます。
SibiCoder

@SibiCoder:はい、手動で結果を解析できますが、それはあまり便利ではありません。私の質問は、より自動化された方法を見つけることに関するものでした。
statox

1
私が知る限り、これを行うための標準的な方法はなく、Vimのサポートなしでそれを行うことは、せいぜい問題があります。ただし、:optionコマンドとOptionSet自動コマンドイベントが存在するため、「状態の保存/復元」機能には十分な関心があるかもしれません。質問してくださいvim_dev
佐藤桂

2
@SatoKatsura:なんてこった、私は:optionそれがかなりクールなコマンドを知らなかった!多分私はvim_devを打つでしょう。@クリスチャン:はい、これは一般的なワークフローではないことがわかりました。実際、私は自分のアイデアを実装しようとしているだけですが、それはそれほど良いものではないかもしれません:-)
statox

1
@ChristianBrabandtデフォルトと異なるオプション(グローバルおよびローカル)を見つけることができると便利です。現在(1)Vimにオプションの完全なリストを表示する方法はありません(つまり、コンパイルモデルなどを考慮に入れています)。(2)ローカルバージョンのオプションについてはドキュメント化されていませselectionん(Fiにはローカルバージョンがあります)バージョン?調べるにはソースを読む必要があります。)
佐藤桂

回答:


5

1。 :mkexrc

最も簡単な方法は、:mkexrcコマンドを使用することです。このコマンドを使用すると、変更されたすべてのオプションをファイルに保存できます。保存したすべてのオプションをファイルから復元する必要がある場合は、:sourceそれだけです。

mkexrc snapshot
source snapshot

2. :setおよび:redir

:mkexrcこのコマンドは、必ずしもすべてのオプションを保持するために、ファイルを使用しています(そしてそれはまた、現在のキーマッピングを保存します。)私たちは任意のファイルを使用したくない場合は、我々はの出力リダイレクトすることができ:setてvimの変数にコマンドを:redir

redir => snapshot
silent set
redir END

その後、次のようにして、スナップショットからすべてのオプションを復元できます。

for opt in split(snapshot,'\n')[1:]
    exe "silent set " . opt
endfor

上記のアプローチは、すばやく簡単に使用できます。しかし、このアプローチには2つの問題があります。最初に、空白を含む一部の文字をsnapshot(:help option-backslashからエスケープする必要があります。そうしないと、これらの文字がエスケープされないときにエラーが発生する可能性があります。例えば、

set breakat=@ !+=

エラー「E518」が発生しますが、

set breakat=@\ \!+=

うまくいきます。

2番目の問題は、出力をスナップショットにリダイレクトすると、すべての特殊キーが通常の文字に変更されることです。たとえば、^I(タブ)は文字通り^andに変更されIます。回避策は少し複雑になる可能性があります。

let g:optionDict = {}

function SaveOpts()
    redir => snapshot
    " We make a snapshot of options which differ from their default value.
    " If we want to make a snapshot of all options, do set all.
    silent set
    redir END

    for opt in split(snapshot, '\W\+')
        if strlen(opt) > 3
            if exists('&' . opt)
                exe 'let g:optionDict.'. opt . '=&' . opt
            elseif opt[0:1] == 'no' && exists('&' . opt[2:])
                exe 'let g:optionDict.'. opt[2:]. '=&' . opt[2:]
            endif
        endif
    endfor
endfunc

function RestoreOpts()
    for [opt, val] in items(g:optionDict)
        try
            exe 'silent set ' . opt . '=' . escape(val, " \t|\\\"")
        catch /:E474/ " Invalid argument, do set {option} or no{option}
            if val == '1'
                exe 'silent set ' . opt
            elseif val == '0'
                exe 'silent set no' . opt
            endif
        endtry
    endfor
endfunc

3。 :setlocal

で手動で復元オプションを保存することもできます:setlocal

:setlocal現在のバッファまたはウィンドウにのみ影響します。オプションをで変更した場合:setlocal:setlocal {option}<または変更したオプションを:set {option}<元に戻すことができる場合。前者はグローバル値から{option}のローカル値を設定し、後者はすべてのローカルオプションを削除してすべてのオプション値をグローバル値に戻します。例えば、

setlocal ts=16
set ts<

4

let option_val = &optionスクリプトを使用して設定の値にアクセスできます。私が見たのは、dictを使用して、変更するオプションを格納することです。dictを繰り返し処理して古い値を格納し、新しい値を設定します。

これはより直接的なアプローチです。事前に設定がわかっている場合は、これを使用します。

function! s:do_something() abort
  " Options needed by the plugin
  let plugin_options = {
        \ 'list': 0,
        \ 'winfixwidth': 1,
        \ 'autoindent': 0,
        \ 'filetype': 'ini',
        \ }

  echo 'desired:' plugin_options

  for option in keys(plugin_options)
    execute 'let old_val = &'.option
    execute 'let &'.option.' = plugin_options[option]'
    let plugin_options[option] = old_val
  endfor

  echo 'changed:' plugin_options

  for option in keys(plugin_options)
    execute 'let &'.option.' = plugin_options[option]'
  endfor
endfunction


call s:do_something()

plugin_options変数は、関数にスコープされているので、古いオプション値を保存するために再利用することができます。

高度な例

以下のスクリプトを使用すると、呼び出すまで元の設定を維持しながら、スクリプト内の任意の場所で設定を変更できます s:restore_settings()

function! s:set(option, value) abort
  if !exists('b:_saved_settings')
    let b:_saved_settings = {}
  endif

  " Only save the original values
  if !has_key(b:_saved_settings, a:option)
    execute 'let b:_saved_settings[a:option] = &'.a:option
  endif

  execute 'let &'.a:option.' = a:value'
endfunction

function! s:restore_settings(...) abort
  if !exists('b:_saved_settings')
    return
  endif

  if a:0
    for option in a:000
      if has_key(b:_saved_settings, option)
        execute 'let &'.option.' = b:_saved_settings[option]'
        call remove(b:_saved_settings, option)
      endif
    endfor
  else
    for option in keys(b:_saved_settings)
      execute 'let &'.option.' = b:_saved_settings[option]'
    endfor

    unlet! b:_saved_settings
  endif
endfunction


" Options needed by the plugin
call s:set('list', 0)
call s:set('winfixwidth', 1)
call s:set('autoindent', 0)
call s:set('filetype', 'ini')

echo 'original:' b:_saved_settings
call s:restore_settings('list', 'filetype')
echo 'partial restore:' b:_saved_settings

call s:restore_settings()

s:set()と似ていsetます。まだ保存されていない場合は、元の設定の値を保存し、設定の値を使用します。

s:restore_settings()引数なしで呼び出すと、変更が完全に復元されます。引数を指定すると、部分的に復元されます。これを使用する場合、スクリプトが復元前にエラーに陥った場合に備えて、s:restore_settings()最初に呼び出す前に呼び出すことをお勧めしますs:set()


1
これは予想したほど自動ではありませんが、適切な回避策のようです。ありがとう!
statox

1
@statoxええ、しかしそれは意図的なことです。もう少し抽象的なスクリプトを使用して回答を更新します。設定を準備する必要はありません。
トミーA

@TommA、オプション値から空白、パイプなどの一部の文字をエスケープしたい場合があります。それらは問題があるかもしれません。
MS.Kim 2016

@ MS.Kimこれは、実行されて'set statusline='.a:valueいる場合にのみ必要です。変数割り当てを使用しているため、問題ではありません。あなたはでそれをテストすることができますs:set('statusline', 'pipe | test')s:set('errorformat', '%A testing %m%Z')
トミーA

@TommyAそうですね。私let &{option}=a.valueは問題を引き起こす可能性があると考えました'set {option}'=a.value。しかし、あなたの言及は、おそらく私だけを使用した可能性のある人々(私を含む)にとって依然として価値があり'set {option}='a.valueます。
MS.Kim、2016

1

ではLH-VIM-libに、私が提供しlh#on#exit()、以前の値にいろいろなものを復元することを可能にする機能を。

オプションに関しては、本質的には(後で)aを登録するだけexe 'let &opt='.&optです。私はそれをこのように使用します:

let cleanup = lh#on#exit()
      \.restore('&efm')
try
   ... change &efm here ...
   do stuff that may fail
finally
   call cleanup.finalize()
endtry

修復物はいくつでも登録できます。たとえば、バッファローカルオプションを明示的に対象とすることができますl:&efm。ただし、「グローバルオプション値へのフォールバック」とは言い切れません。

このfinally条項は重要です。いずれかの操作が失敗する可能性がある場合、それがないと、オプションはエンドユーザーの設定に復元されません。

可能なオプションを復元する方法は提供していません。@ MS.Kimの回答を参照して、リストを取得する方法を確認してください。または、オプション変更イベントをリッスンしたり、古いc_CTRL-A_HOMEトリック(1)で遊んだりすることもできます。しかし、正直なところ、私は本当にそのポイントがわかりません。ローカルで(関数内で)オプションの値を変更すると、調整するオプションが正確にわかります。

私もできることに注意してください:

  • グローバルまたはバッファーローカルにできるプラグインオプション(変数)を復元します-> .restore_option(varname)
  • アクションを登録-> .register(':q')
  • バッファローカルマッピングを復元(または未定義)-> .restore_buffer_mapping('<c-y>', 'i')

(1)(いつものように)lh-vim-libで因数分解したこと-> echo lh#command#matching_askvim('option', '')

" Function: lh#command#matching_askvim(what, lead) {{{3
function! lh#command#matching_askvim(what, lead) abort
  let cleanup = lh#on#exit()
        \.register('delcom LHAskVimMatchingCompletion')
  try
    exe 'command! -complete='.a:what.' -nargs=* LHAskVimMatchingCompletion :echo "<args>"'
    silent! exe "norm! :LHAskVimMatchingCompletion ".a:lead."\<c-a>\"\<home>let\ cmds=\"\<cr>"
    return split(cmds, ' ')[1:]
  finally
    call cleanup.finalize()
  endtry
endfunction

それは非常に興味深いプラグインのように見えます。私はあなたがここでかなり良い点を作ったと思います:I haven't provided a way to restore any possible option [...]. I don't see the point. When, locally (in a function), I change option values, I exactly know which options I'll tweak.公平にするために、なぜそれが必要だったのか思い出せませんが、変更する必要があるオプションのみを切り替える方が良いことに同意します。
statox

ああ。あなたのコメント以来、コマンドライン補完のおかげですべての既存のオプションを一覧表示する方法を追加しました-中身は汚いトリックです。
Luc Hermitte、2016年

(追記:私が別のタッパービムに出席した場合は、質問してください)
Luc

これがベテランのビミストを認識する方法です。;-)私はこの古いc_CTRL-A_HOMEトリックを知りませんでした。コードを理解するために少し時間が必要ですが、解決策を提供してくれてありがとうございました。(PS私は次のtuppervimで喜んであなたにお会いしましょう!)
statox

1
get(g:, これが以前のやり方です-発見するのにしばらく時間がかかりました。それはまだなどのオプション、環境変数、のような非正式に暴露もののために便利です
リュックHermitte
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.