Evite la actualización de la pantalla hasta que se complete la función

10

Tengo una función que mueve y genera mucho texto en el búfer vim actual, y cuando lo ejecuto, ver todo lo que sucede a una velocidad cegadora es un poco desconcertante.

¿Cómo puedo congelar la pantalla hasta que se complete la función?

Aquí está la función en cuestión:

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
fuente
2
Ciervas :set lazyredrawayuda?
VanLaser
Lo siento, no. Eso solo ayuda para las macros. Lo intenté y no funcionó para mi función.
Flurrywinde
2
No conozco ninguna forma de hacer esto, aparte de congelar la ventana del terminal (que no funcionará para gVim). ¿Pero quizás hay otra manera de hacer que su función se ejecute con menos actualizaciones de pantalla? Sería útil si publicaras tu función ;-)
Martin Tournoij
Lo pediste, @Carpetsmoker. ;-) Función añadida. (Es bastante largo.)
Flurrywinde

Respuestas:

5

Creo que el problema no es el :lazyredrawque, según tengo entendido por los documentos, debería funcionar para las funciones (vea :help :redraw, dice "Útil para actualizar la pantalla a la mitad ejecutando un script o función").

El problema es que usas normalpara actualizar el búfer y funciona como si realmente escribieras algo y aquí :lazyredrawno tiene ningún efecto.

En lugar de normalusar las funciones de manipulación de texto (como setline()) y los comandos ex (como :delete).

Compare estas dos funciones, la primera MakeChangesNorm()hará algunas actualizaciones locas de la pantalla, mientras que la segunda MakeChangesFunctions()hará la actualización al instante:

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

El archivo en el que lo probé se ve así:

*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
fuente
Para ser claro; ¿no hay forma de emitir varios comandos normales y posponer por completo la actualización de la pantalla hasta un comando posterior de "restaurar la pantalla"? Entiendo winsaveviewy winrestviewsimplemente almacene la ubicación del cursor y la posición relativa de la línea en la ventana.
Luke Davis
Haré esto en otra pregunta.
Luke Davis