Wie speichere und stelle ich das Ergebnis des Befehls 'set' wieder her?

7

Daraus :h :setwissen wir das

:se[t] Alle Optionen anzeigen, die von ihrem Standardwert abweichen.

In einem Vimscript möchte ich alle diese vom Benutzer geänderten Optionen speichern, ändern und später auf den vom Benutzer festgelegten Wert zurücksetzen.

Wie kann ich das einfach machen?

Kann ich das Ergebnis :set(oder einen ähnlichen Befehl) einfach in einer Variablen speichern, die ich später als Quelle verwenden oder an einen anderen Befehl übergeben kann, um dessen Inhalt wiederherzustellen?

Oder muss ich die Ausgabe des Befehls manuell analysieren (was ich tun kann, aber viel Arbeit für nichts ist, wenn es eine einfachere Alternative gibt)?

statox
quelle
Wir wissen bereits, dass Optionen mit & symbol beginnen. Wir können einen ausführlichen Befehl set geben und dann die Ausgabe in einer Variablen oder einem Register aufzeichnen und dann jeden von ihnen aufteilen und ihre Werte in einem Wörterbuch speichern und dann daraus wiederherstellen.
SibiCoder
@SibiCoder: Ja, ich kann das Ergebnis manuell analysieren, aber das ist nicht wirklich praktisch. Meine Frage war, einen automatischeren Weg zu finden, dies zu tun.
Statox
1
Soweit ich weiß, gibt es keinen Standardweg, und dies ohne die Unterstützung von Vim zu tun, wäre bestenfalls problematisch. Es gibt jedoch einen :optionBefehl und ein OptionSetAutocommand-Ereignis, sodass möglicherweise genügend Interesse für eine Funktion zum Speichern / Wiederherstellen des Status besteht. Fragen Sie weiter vim_dev.
Sato Katsura
2
@SatoKatsura: Verdammt, ich wusste nicht, dass der :optionBefehl ziemlich cool ist! Du hast recht, vielleicht drücke ich vim_dev. @ Christian: Ja, ich verstehe, dass dies kein allgemeiner Workflow ist, eigentlich versuche ich nur, eine Idee von mir umzusetzen, aber vielleicht ist das nicht so gut :-)
statox
1
@ChristianBrabandt Es wäre nützlich herauszufinden, welche Optionen (global und lokal) von den Standardeinstellungen abweichen. Derzeit (1) gibt es keine Möglichkeit, Vim dazu zu bringen, eine vollständige Liste von Optionen zu erstellen (dh Kompilierungsmodelle usw. zu berücksichtigen), und (2) es ist nicht einmal dokumentiert, welche Optionen lokale Versionen haben (Fi hat selectioneine lokale Version? Man muss die Quellen lesen, um herauszufinden.)
Sato Katsura

Antworten:

5

1. :mkexrc

Der einfachste Weg ist die Verwendung eines :mkexrcBefehls. Mit diesem Befehl können wir alle geänderten Optionen in einer Datei speichern. Wenn Sie alle gespeicherten Optionen aus der Datei wiederherstellen müssen, nur :sourcediese.

mkexrc snapshot
source snapshot

2. :setund:redir

Der :mkexrcBefehl verwendet notwendigerweise eine Datei, um alle Optionen zu speichern. (Und er speichert auch aktuelle Schlüsselzuordnungen.) Wenn wir keine Datei verwenden möchten, können wir die Ausgabe des :setBefehls in die vim-Variable mit umleiten :redir.

redir => snapshot
silent set
redir END

Anschließend können wir alle Optionen aus dem Snapshot wie folgt wiederherstellen.

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

Der obige Ansatz ist schnell und einfach anzuwenden. Der Ansatz hat jedoch zwei Probleme. Zuerst müssen wir einige Zeichen, einschließlich Leerzeichen, aus dem Schnappschuss ( :help option-backslash) entfernen . Andernfalls können Fehler auftreten, wenn diese Zeichen nicht maskiert werden. Zum Beispiel,

set breakat=@ !+=

löst den Fehler 'E518' aber aus,

set breakat=@\ \!+=

funktioniert gut.

Und das zweite Problem ist, dass alle Sonderschlüssel in normale Zeichen geändert werden, wenn wir die Ausgabe auf den Schnappschuss umleiten. Zum Beispiel wird ^I(tab) buchstäblich in ^und geändert I. Die Problemumgehung könnte etwas kompliziert sein.

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

Wir können eine Wiederherstellungsoption auch manuell mit speichern :setlocal.

:setlocalwirkt sich nur auf den aktuellen Puffer oder das aktuelle Fenster aus. Wenn wir Optionen ändern mit :setlocal, :setlocal {option}<oder :set {option}<können die geänderten Optionen wiederherstellen zurück. Ersteres setzt den lokalen Wert von {Option} von seinem globalen Wert und letzteres entfernt alle lokalen Optionen, sodass alle Optionswerte zu ihren globalen Werten zurückkehren. Zum Beispiel,

setlocal ts=16
set ts<
MS.Kim
quelle
4

Sie können mit let option_val = &optioneinem Skript auf den Wert einer Einstellung zugreifen . Was ich gesehen habe, ist die Verwendung eines Diktats zum Speichern der Optionen, die Sie ändern möchten. Sie durchlaufen das Diktat, um den alten Wert zu speichern und den neuen festzulegen.

Beispiel

Dies ist ein direkterer Ansatz. Ich würde dies verwenden, wenn die Einstellungen im Voraus bekannt sind.

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()

Die plugin_optionsVariable ist auf die Funktion beschränkt, sodass sie zum Speichern der alten Optionswerte wiederverwendet werden kann.

Erweitertes Beispiel

Mit dem folgenden Skript können Sie die Einstellungen an einer beliebigen Stelle in Ihrem Skript ändern, während Sie die ursprünglichen Einstellungen beibehalten, bis Sie aufrufen 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()ist etwas ähnlich zu set. Der Wert der ursprünglichen Einstellung wird gespeichert, wenn er noch nicht gespeichert wurde. Verwenden Sie dann den Wert Ihrer Einstellung.

Wenn Sie s:restore_settings()ohne Argumente aufrufen, werden Ihre Änderungen vollständig wiederhergestellt. Mit Argumenten werden sie teilweise wiederhergestellt. Wenn Sie sich für diese Option entscheiden, sollten Sie s:restore_settings()vor dem ersten Aufruf aufrufen, s:set()falls in Ihrem Skript vor der Wiederherstellung zuvor ein Fehler aufgetreten ist.

Tommy A.
quelle
1
Das ist nicht so automatisch, wie ich erwartet hätte, aber das scheint eine gute Lösung zu sein. Vielen Dank!
Statox
1
@statox Ja, aber es ist absichtlich, was meiner Meinung nach besser sein kann, wenn Sie nichts Aufwändiges tun. Ich werde die Antwort mit einem Skript aktualisieren, das etwas abstrakter ist und bei dem Sie die Einstellungen nicht vorbereiten müssen.
Tommy A
@TommA, Wir möchten möglicherweise einige Zeichen wie Leerzeichen, Pipe usw. aus Optionswerten entfernen. Diese könnten problematisch sein.
MS.Kim
@ MS.Kim Das wird nur benötigt, wenn es ausgeführt wurde 'set statusline='.a:value. Da die Variablenzuweisung verwendet wird, ist dies kein Problem. Sie können es mit s:set('statusline', 'pipe | test')oders:set('errorformat', '%A testing %m%Z')
Tommy A
@ TommyA Du hast recht. Ich dachte, ich let &{option}=a.valuekönnte Probleme verursachen 'set {option}'=a.value. Aber Ihre Erwähnung ist immer noch wertvoll für die Leute (einschließlich mir), die wahrscheinlich nur benutzt haben 'set {option}='a.value.
MS.Kim
1

In lh-vim-liblh#on#exit() stelle ich eine Funktion bereit , mit der verschiedene Dinge auf ihren vorherigen Wert zurückgesetzt werden können.

In Bezug auf Optionen werden im Wesentlichen nur (für später) a registriert exe 'let &opt='.&opt. Ich benutze es so:

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

Wir können so viele Restaurationen registrieren, wie wir möchten. Wir können explizit auf eine lokale Pufferoption abzielen, zum Beispiel : l:&efm. Mir ist jedoch keine Möglichkeit bekannt, zu sagen: "Auf den globalen Optionswert zurückgreifen".

Beachten Sie, dass die finallyKlausel wichtig ist. Wenn ein Vorgang fehlschlägt, wird die Option ohne diese Option nicht auf die Einstellungen des Endbenutzers zurückgesetzt.

Ich habe keine Möglichkeit bereitgestellt, eine mögliche Option wiederherzustellen. In der Antwort von @ MS.Kim erfahren Sie, wie wir ihre Liste erhalten können. Oder wir könnten das Ereignis mit geänderter Option anhören oder mit dem alten c_CTRL-A_HOMETrick spielen (1). Aber ehrlich gesagt verstehe ich den Punkt wirklich nicht. Wenn ich lokal (in einer Funktion) Optionswerte ändere, weiß ich genau, welche Optionen ich optimieren werde.

Beachten Sie, dass ich auch:

  • Plugin-Optionen (Variablen) wiederherstellen, die global sein oder lokal puffern können -> .restore_option(varname)
  • Aktionen registrieren -> .register(':q')
  • Lokale Pufferzuordnung wiederherstellen (oder deren Definition aufheben) -> .restore_buffer_mapping('<c-y>', 'i')

(1) Dass ich lh-vim-lib (wie üblich) berücksichtigt habe -> 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
Luc Hermitte
quelle
Das sieht nach einem sehr interessanten Plugin aus. Ich denke, Sie machen hier einen ziemlich guten Punkt: Um 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.fair zu sein, kann ich mich nicht erinnern, warum ich das gebraucht habe, aber ich stimme zu, dass es besser ist, nur die Optionen zu wechseln, die Sie ändern müssen.
Statox
Ah. Seit Ihrem Kommentar habe ich eine Möglichkeit hinzugefügt, alle vorhandenen Optionen dank der Befehlszeilenvervollständigung aufzulisten - ein schmutziger Trick im Inneren.
Luc Hermitte
(PS: Wenn ich jemals an einem anderen Tuppervim teilnehme, fragen Sie einfach)
Luc Hermitte
Ok, so erkennst du einen erfahrenen Vimmisten ;-) Ich kannte diesen alten c_CTRL-A_HOMETrick nicht und ich werde etwas Zeit brauchen, um deinen Code zu groken, aber vielen Dank für die Bereitstellung einer Lösung! (PS Ich würde dich gerne in einem nächsten Tuppervim treffen!)
statox
1
So sind wir schon früher vorgegangen get(g:, - was mich einige Zeit gekostet hat, um es herauszufinden. Es ist immer noch nützlich für nicht offiziell exponierte Dinge wie Optionen, Umgebungsvariablen usw.
Luc Hermitte