Com que frequência e quando o foldexpr é avaliado?

Aug 30 2020

Quero alternar foldmethodentre expre manualporque se sempre definirmos foldmethod=expr, o cursor tende a se mover lentamente no vim.

Acho que foldexpré avaliado logo após a troca foldmethod=expr, portanto, tento alternar a cada 5000ms da seguinte maneira. No entanto, foldexprnão pode ser avaliado, o que foldexprsignifica que não é avaliado logo após a troca foldmethod=expr.

Então, eu tenho uma dúvida: com que frequência ou quando é foldexpravaliado? Que eu saiba, não existe nenhum documento sobre o momento da avaliação de foldexpr.

function! s:enable_expr(timer_id) abort
  setlocal foldmethod=expr
  setlocal foldmethod=manual
endfunction
autocmd CursorMoved * call s:cursor_moved()

let s:timer_id = timer_start(5000, function('s:enable_expr'))

function! s:cursor_moved() abort
  setlocal foldmethod=manual

  call timer_stop(s:timer_id)
  let s:timer_id = timer_start(5000, function('s:enable_expr'))
endfunction

OBSERVAÇÃO : eu conheço uma maneira de alterná-los usando InsertEntere InsertLeavecurtir aqui . Mas, se usarmos a alternância dessa forma, a alternância entre o modo de inserção e o modo normal pode se tornar lenta. Além disso, utilizo muito o comando <C-o>em modo de inserção, portanto, queremos evitar essa implementação.

Portanto, quero fazer com que o vim avalie foldexpruma vez em todas as linhas quando o cursor for pressionado.

OBSERVAÇÃO adicional : eu alterno-os com a implementação a seguir por enquanto. Uma desvantagem dessa implementação é que, quando movemos o cursor após 5000 ms sob a posição do cursor, o movimento do cursor se torna lento no início devido à troca foldmethod.

function! s:enable_expr(timer_id) abort
  if &l:foldmethod ==# 'manual'
    setlocal foldmethod=expr
  endif
endfunction
autocmd CursorMoved * call s:cursor_moved()

let s:timer_id = timer_start(5000, function('s:enable_expr'))

function! s:cursor_moved() abort
  if &l:foldmethod ==# 'expr'
    setlocal foldmethod=manual
  endif
  call timer_stop(s:timer_id)
  let s:timer_id = timer_start(5000, function('s:enable_expr'))
endfunction

Uma solução temporária

augroup foldmethod-syntax
  autocmd InsertEnter,CursorMoved,CursorMovedI * if &l:foldmethod ==# 'expr'
  \                   |   setlocal foldmethod=manual
  \                   | endif
  autocmd BufWrite * if &l:foldmethod ==# 'manual'
  \                   |   setlocal foldmethod=expr
  \                   | endif
augroup END

Respostas

2 MaximKim Sep 04 2020 at 15:31

Vamos dar uma olhada no código-fonte do vim:

Existe uma função que é chamada quando uma alteração é feita:

https://github.com/vim/vim/blob/85629985b71035608a37ba3bde86968481490d46/src/change.c#L429

Esta função aciona foldUpdate:

https://github.com/vim/vim/blob/85629985b71035608a37ba3bde86968481490d46/src/change.c#L537

O que faz dobrar (incluindo foldexpr):

https://github.com/vim/vim/blob/81fcb67fb32a12414512b72e691a1bbbff9f8511/src/fold.c#L842

Isso também acontece quando você começa a editar um arquivo:

https://github.com/vim/vim/blob/451c2e3536a3cb77d07faf3cb2b834512e174351/src/ex_cmds.c#L1270

E quando você define foldexpropções:

https://github.com/vim/vim/blob/d43906d2e5969288f239df851f5ad7b1dc2c7251/src/optionstr.c#L1994

E assim por diante.

PS

Existe um plugin https://github.com/Konfekt/FastFold isso provavelmente faz o que você deseja.