0

Trying to fold content so the 'method definition' / 'explanatory' lines are all showing regardless of depth, and the content between them is folded.

Folding examples on the wikis and in tutorials all seem to fold by nested depth.

Example code:

# RSpec code example
# '...' represents many lines of content
...
context 'depth 0' do
  ...
  context 'depth 1' do
    ...
    it 'depth 2' do
      ...
    end
  end
  ...
end

Folding with syntax matching, foldlevel=1 will give:

# RSpec code example
# '...' represents many lines
...
context 'depth 0' do
  ...
  +-- 66 lines: context 'depth 1' do {--------------------------
  ...
end

Trying to fold away the content ..., how do I get:

# RSpec code example
# '...' represents many lines of content
+-- MANY lines: ... {--------------------------
context 'depth 0' do
+-- MANY lines: ... {--------------------------
  context 'depth 1' do
+-- MANY lines: ... {--------------------------
    it 'depth 2' do
+-- MANY lines: ... {--------------------------
1

To show the lines ending in do, and fold away everything else:

:set foldexpr=getline(v:lnum)=~'do$'?'=':getline(v:lnum-1)=~'do$'?'a1':getline(v:lnum+1)=~'do$'?'s1':'='

Breakdown

# using '#' as comments
# this is ran on each line to work out its indentation level

:set foldexpr=
  getline(v:lnum)=~'do$' # current line regex match lines that end in 'do'
  ? # if the previous statement is true do this
    '=' # same indent level as previous line
  : # else
    getline(v:lnum-1)=~'do$' # examine previous line, same matcher
    ? # if previous
      'a1' # one indent level deeper than previous line
    : # else
      getline(v:lnum+1)=~'do$'# examine next line, same matcher
      ? # if previous
        's1' # one indent level up from previous line
      : # else
        '=' # same indent level as previous line

# if you want to exclude e.g. lines that are 'before do',
# then change "getline(v:lnum)=~'do$'"
# to "getline(v:lnum)=~'do$'&&getline(v:lnum)!~'before\\sdo$'"
# giving :set foldexpr=getline(v:lnum)=~'do$'&&getline(v:lnum)!~'before\\sdo$'?'=':getline(v:lnum-1)=~'do$'&&getline(v:lnum-1)!~'before\\sdo$'?'a1':getline(v:lnum+1)=~'do$'&&getline(v:lnum+1)!~'before\\sdo$'?'s1':'='

Beginner Notes

If you're a beginner and its not working, remember to:

:set foldmethod=expr
:set foldlevel=0
:set foldenable

This sets foldmethod to use the expression set in foldexpr, sets foldlevel to 0 - which is important as this solution gives every line a foldlevel of 1 or 0, and lastly no matter what commands you run, if foldenable is not set you won't see anything. If you alter the command, make sure there are no spaces, use \s.

  • As a .vimrc shortcut: map <leader>fr :set foldmethod=expr<cr>:set foldlevel=0<cr>:set foldexpr=getline(v:lnum)=~'do$'&&getline(v:lnum)!~'before\\sdo$'?'=':getline(v:lnum-1)=~'do$'&&getline(v:lnum-1)!~'before\\sdo$'?'a1':getline(v:lnum+1)=~'do$'&&getline(v:lnum+1)!~'before\\sdo$'?'s1':'='<cr>:set foldenable<cr> – xxjjnn Apr 16 '18 at 12:19
  • or I could do :set foldexpr=getline(v:lnum)=~'do$'?0:1 ...huh – xxjjnn Apr 17 '18 at 11:10

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.