Vim already displays folds as a single line. However, in Vim's indent
folding, all the lines that have the same indent are included in a fold. So in your screenshot, the lines you are referring to as "headers" (e.g., the one starting collection_base_url
) are not within the folds.
You can achieve something similar to Atom's folding by using Vim's foldexpr
foldmethod
:
" Finds the indent of a line. The indent of a blank line is the indent of the
" first non-blank line above it.
function! FindIndent(line_number, indent_width)
" Regular expression for a "blank" line
let regexp_blank = "^\s*$"
let non_blank_line = a:line_number
while non_blank_line > 0 && getline(non_blank_line) =~ regexp_blank
let non_blank_line = non_blank_line - 1
endwhile
return indent(non_blank_line) / a:indent_width
endfunction
" 'foldexpr' for Atom-style indent folding
function! AtomStyleFolding(line_number)
let indent_width = &shiftwidth
" Find current indent
let indent = FindIndent(a:line_number, indent_width)
" Now find the indent of the next line
let indent_below = FindIndent(a:line_number + 1, indent_width)
" Calculate indent level
if indent_below > indent
return indent_below
elseif indent_below < indent
return "<" . indent
else
return indent
endif
endfunction
set foldexpr=AtomStyleFolding(v:lnum)
set foldmethod=expr
This defines a fold expression (see :help fold-expr
) as follows:
- For lines immediately preceding indented lines, it returns the indentation of the block that follows.
- For indented lines, it returns the indentation. (Divided by the shiftwidth so each level of indentation increments the returned value by 1)
- For lines at the end of a block of indented lines, it returns a string
"<N"
, where N is set to the indent. This tells Vim that a fold of level N finishes on that line.
Update
@alxndr asks in the comments whether it's possible to extend this to include Ruby's outdented end
s within the folds. You could start by replacing the " Calculate indent level
section with the following:
if indent_below > indent
return indent_below
elseif getline(a:line_number) =~ '^\s*end\s*$'
return "<" . (indent + 1)
else
return indent
endif
As it is, this isn't the most robust solution (e.g. it will fail if the end
statement is on the same line, after a semi-colon). You could tweak the regular-expression and surrounding code to address this, but as you're now within the realms of parsing the actual syntax of the file, I suspect things could get a lot more complicated before you have a good solution.
from __future__ import braces
)... How did you configure folding? And can you paste this code snippet (or another that demonstrates the problem)? Vim folds to a single line, but as muru mentioned, your folds start a line late.