1

In Emacs org-mode, folds use * at the start of the lines, and any * added consecutively, will add a level of indentation to the header.

Furthermore, the header text placed after * or any number of it, will be the only thing shown when folded/folding (in contrast, Vim's fold show part of the text that was folded, instead of only showing the header's text).

Here a gif (roughly 2 seconds) with one fold level.

example

And here another one (roughly 5 seconds) with more than one fold level (three levels).

another

Any way/or existing plugin to do this?

  • 1
    You could try foldmarker=*,*, though you'll almost certainly have to use numbers, and it might not work. – D. Ben Knoble Sep 17 at 0:43
  • 1
    There’s an option which controls the foldtext shown – D. Ben Knoble Sep 17 at 1:38
  • 1
    I'm not sure I got your case 100% right... But take a look at my answer and see if that does it. Otherwise, maybe post an example? Either a picture of what you get in Emacs, or just post some sample text and explain where it should fold and where it should not... Thanks! – filbranden Sep 17 at 2:34
  • 1
    Yeah thanks! That's what I had in mind. So that should be exactly what the snippet in my answer does. Take it for a spin, let me know if you find any corner case where it doesn't do what you expect... You might want to drop the optional leading whitespace if you expect the *s to always start on the first column. – filbranden Sep 17 at 3:11
  • 1
    Just updated the answer to include a 'foldtext' that does exactly what's on your animations. (Well, except for the highlighting, but I think a lot of that should be doable in Vim as well, though I'm not totally sure whether you can have different styles for different closed folds... Ask a question about that part if you like!) – filbranden Sep 17 at 3:49
2

You can accomplish this kind of folding fairly easily by using a file expression, using a function to calculate the fold level of the current line.

You can start a new fold of level n on a line that starts with n *s (possibly followed by whitespace.) For a line that doesn't start with *, simply use the fold level of the most recent * line above it.

That's easily implemented with:

 function OrgFold(lnum)
  let level = strlen(matchstr(getline(a:lnum), '\v^\s*\zs\*+'))
  if level > 0
    return '>'.level
  else
    return '='
  endif
endfunction

The folding function can return something like >2 to start a level 2 fold on the current line. Returning = means use the fold level of the preceding line which had the fold level explicitly set.

Enable this folding with:

set foldmethod=expr foldexpr=OrgFold(v:lnum)

You can customize the text displayed when the block is folded. For example, to simply display the first line followed by three dots, you can use:

set foldtext=getline(v:foldstart).'...'.repeat('\ ',999)

This expression also suppresses the dashes to the right of the fold text, by padding the string with enough spaces to fully hide them.

| improve this answer | |

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.