39

In Vim, I often find myself wanting to do a quick zk or zj to jump to the previous or next fold in a file. The problem is, I frequently want to skip all the open folds, and just jump to the nearest closed fold.

Is there a way to do this? I see no built-in keymap in the help.

David
  • 13,133
  • 1
  • 30
  • 39

2 Answers2

42

Let me propose the following implementation of the described behavior.

nnoremap <silent> <leader>zj :call NextClosedFold('j')<cr>
nnoremap <silent> <leader>zk :call NextClosedFold('k')<cr>

function! NextClosedFold(dir)
    let cmd = 'norm!z'..a:dir
    let view = winsaveview()
    let [l0, l, open] = [0, view.lnum, 1]
    while l != l0 && open
        exe cmd
        let [l0, l] = [l, line('.')]
        let open = foldclosed(l) < 0
    endwhile
    if open
        call winrestview(view)
    endif
endfunction

If it is desirable for the mappings to accept a count for the number of repetitions of the corresponding movement, one can implement a simple function for repeating any given command:

function! RepeatCmd(cmd) range abort
    let n = v:count < 1 ? 1 : v:count
    while n > 0
        exe a:cmd
        let n -= 1
    endwhile
endfunction

and then redefine the above mappings as follows:

nnoremap <silent> <leader>zj :<c-u>call RepeatCmd('call NextClosedFold("j")')<cr>
nnoremap <silent> <leader>zk :<c-u>call RepeatCmd('call NextClosedFold("k")')<cr>
ib.
  • 27,830
  • 11
  • 80
  • 100
  • 1
    @David: Thanks! I have made a refactoring on the code to simplify the jumping loop and to keep the cursor in place if there is no closed fold in desired direction. (The latter behavior conforms to that of `zj`/`zk` commands when no fold can be found below/above.) – ib. Feb 24 '12 at 07:11
  • @ib. could you please provide the changed script? – Glenn Jorde Aug 23 '16 at 09:57
  • @Glenn: If you refer to the refactoring I mentioned in my comment, the code in the answer has been already updated to include it. – ib. Aug 24 '16 at 07:13
  • Is there any way to adapt this function to allow a count, such as `[count]zj`? – travisw Aug 14 '19 at 11:28
  • 1
    @travisw: There is. I have updated the answer to show one way to support the count for repetitions in the proposed mappings. – ib. Feb 20 '20 at 08:51
1

No, there isn't, as far as I know, a build-in method to do that. Interesting idea, though.

If I had some time at the moment, I might try to figure out a way to do it — unfortunately, being busy nowadays, all I can suggest you is to look at the Detecting a folded line or an incremental search question (particularly the foldclosed function) and try to make a function yourself. Checking every line, if fold is open, skip… something along those lines.

ib.
  • 27,830
  • 11
  • 80
  • 100
Rook
  • 60,248
  • 49
  • 165
  • 242