Verhindern Sie die Aktualisierung des Bildschirms, bis die Funktion abgeschlossen ist

10

Ich habe eine Funktion, die viel Text in den aktuellen VIM-Puffer verschiebt und ausgibt, und wenn ich ihn ausführe, ist es etwas beunruhigend zu sehen, was alles mit blendender Geschwindigkeit passiert.

Wie kann ich den Bildschirm einfrieren, bis die Funktion abgeschlossen ist?

Hier ist die fragliche Funktion:

function! MakeChoices()
    :let save_view = winsaveview()
    let start = line('.')

    "Locate previous *choice. (b=backwards, W=nowrap, n=doNot move cursor)
    let choiceStartLine = search('^*choice', 'bW')

    if !choiceStartLine
        echo "No *choice found. (*choice must not be indented. This is to avoid finding *choice blocks nested in another *choice block.)"
        return -1
    endif
    "return getline(target_line_num, target_line_num+4)
    "Locate end of *choice block
    "echo getline(choiceStartLine, choiceStartLine+2)
    let choiceEndLine = search('^\S.*', 'W') "End is first line that starts with non-whitespace

    "If above search fails, might be at bottom of buffer
    if choiceEndLine == 0
        let choiceEndLine = search('^$', 'W') "End is first empty line
    endif

    "Now go back up to the last *goto
    let choiceEndLine = search('*goto', 'bW')

    "Get the entire *choice block and put it in gotoBlock
    let gotoBlock = getline(choiceStartLine, choiceEndLine)

    "Make labelArray (contains all labels to goto)
    let labelArray = []

    for cur in gotoBlock
        if match(cur, '*goto') != -1
            "echo 'cur: '.cur
            let curParsed = matchlist(cur, '*goto \(\S\+\)')
            "echo curParsed
            if len(curParsed) > 1
                let curLabel = curParsed[1]
            else
                echo 'ERROR: Bad *goto ('.cur.')'
                return -1
            endif
            call add(labelArray, curLabel)  
        endif
    endfor

    "Restore window to what it looked like (in case the searches scrolled
    "it)
    call winrestview(save_view)

    "Make newline after choice block if needed
    if strlen(getline(choiceEndLine+1)) > 0
        echo 'big line: '.getline(choiceEndLine+1)
        call cursor(choiceEndLine, 1)
        put=''
    endif

    call cursor(choiceEndLine+1, 1)

    "Put the new label blocks
    let skippedLabels = ''
    let numNewLabels = 0
    for cur in labelArray
        if !search('*label '.cur, 'wn')
            let numNewLabels += 1
            put='*label '.cur
            put='[This option is yet to be written.]'
            put=''
        else
            let skippedLabels .= cur.' '
        endif
    endfor

    "Remove trailing blank lines (Up to a point)
    let nextlines = getline(line('.')+1, line('.')+3)
    if len(nextlines) == 3
        if nextlines[0] == '' && nextlines[1] == '' && nextlines[2] == ''
            normal "_3dd
        elseif nextlines[0] == '' && nextlines[1] == ''
            normal "_2dd
        elseif nextlines[0] == ''
            normal "_dd
        endif
    endif

    "Move to first label's text (use ctrl-v ctrl-m to input the <CR> at
    "end)
    if numNewLabels != 0
        call cursor(choiceEndLine, 1)
        normal /\[This option is yet to be written.\]
        let @/='\[This option is yet to be written\.\]'
    endif

    "Print status message
    if len(skippedLabels) > 0
        echo 'Skipped: '.skippedLabels
    else
        echo 'New labels created: '.numNewLabels
    endif
endfunction
Flurrywinde
quelle
2
Hilft das :set lazyredraw?
VanLaser
Entschuldige Nein. Das hilft nur für Makros. Ich habe es gerade versucht und es hat für meine Funktion nicht funktioniert.
Flurrywinde
2
Ich kenne keine Möglichkeit, dies zu tun, außer vielleicht das Terminalfenster einzufrieren (was für gVim nicht funktioniert). Aber vielleicht gibt es eine andere Möglichkeit, Ihre Funktion mit weniger Bildschirmaktualisierungen auszuführen? Es wäre hilfreich, wenn Sie Ihre Funktion gepostet hätten
;-)
Sie haben danach gefragt, @Carpetsmoker. ;-) Funktion hinzugefügt. (Es ist ziemlich lang.)
Flurrywinde

Antworten:

5

Ich denke, das Problem ist nicht, :lazyredrawwelches, wie ich aus den Dokumenten verstehe, für Funktionen funktionieren sollte (siehe :help :redraw"Nützlich, um den Bildschirm nach der Hälfte der Ausführung eines Skripts oder einer Funktion zu aktualisieren").

Das Problem ist, dass Sie normalzum Aktualisieren des Puffers verwenden und es so funktioniert, als ob Sie tatsächlich etwas eingeben und hier :lazyredrawkeine Auswirkung haben.

Stattdessen müssen normalSie Textmanipulationsfunktionen (wie setline()) und Ex-Befehle (wie :delete) verwenden.

Wenn Sie diese beiden Funktionen vergleichen, führt die erste MakeChangesNorm()einige verrückte Bildschirmaktualisierungen durch, während die zweite MakeChangesFunctions()die Aktualisierung sofort ausführt:

function! MakeChangesNorm()
    let lastline = line('$')
    norm gg
    let linenum = line('.')
    let lastline = line('$')
    while linenum < lastline
        norm ^
        norm s/choice/test/
        norm j
        normal "_3dd
        let linenum = line('.')
        let lastline = line('$')
    endwhile
endfunction


function! MakeChangesFunctions()
    norm gg
    let linenum = line('.')
    let lastline = line('$')
    while linenum < lastline
        let line = getline(linenum)
        " Substitute using substitute() and setline()
        let line = substitute(line, 'choice', 'test', '')
        call setline(linenum, line)
        " Delete lines using :delete
        execute '.,.+2delete _'
        let linenum = line('.')
        let lastline = line('$')
    endwhile
endfunction

Die Datei, an der ich es getestet habe, sieht folgendermaßen aus:

*choice test2 test3 super
*choice test2 test3 super
*choice test2 test3 super
*choice test2 test3 super
*choice test2 test3 super
*choice test2 test3 super
*choice test2 test3 super
*choice test2 test3 super
*choice test2 test3 super
*choice test2 test3 super
... 60 lines like this ...
Boris Serebrov
quelle
Deutlich sein; Gibt es keine Möglichkeit, mehrere normale Befehle auszugeben und die Aktualisierung des Bildschirms bis zu einem nachfolgenden Befehl "Bildschirm wiederherstellen" vollständig zu verschieben? Mein Verständnis ist winsaveviewund winrestviewspeichern Sie einfach die Cursorposition und die relative Position der Linie im Fenster.
Luke Davis
Ich werde dies in einer anderen Frage stellen.
Luke Davis