I was able to accomplish something reasonable with the following code:
function CollectFolds() abort
if !exists('s:folds')
let s:folds = []
endif
const line = line('.')
const end = foldclosedend(line)
if !exists('s:prev_end') " first one
let s:prev_end = end
call add(s:folds, [line, end])
elseif end isnot# s:prev_end " new fold
call add(s:folds, [line, end])
let s:prev_end = end
endif
endfunction
command PrintFolds execute 'folddoclosed call CollectFolds()' | echo s:folds | unlet s:folds s:prev_end
You can drop it in ~/.vim/plugin/printfolds.vim
(though it should really have an if exists('g:loaded_printfolds')
guard for that).
Change echo s:folds
if you want to touch up the formatting.
The idea is to maintain a running state of the end of the current fold; when we start a new fold (the end changes), we add the fold start and end to the list of folds.
This approach only counts closed folds, so it skips nested folds and such. See previous edits for other versions. (If you know what foldmethod
is, or use foldmarker
or some other smarter technique, you might do better.)
It might be possible to get more robust by tweaking my fold-detection code from AutoOrigami. Heck, at that point, you migth beĀ better off looping through the file and tracking previous foldlevel()
and such. As filbranden points out below, this comes with its own detection problems; adjacent lines with the same fold level but that belong to different folds need to be distinguished, probably based on foldclosedend
(which limits you to closed folds again; I mocked this up, and it almost works, but not quite).