All patches and comments are welcome. Please squash your changes to logical
commits before using git-format-patch and git-send-email to
patches@git.madduck.net.
If you'd read over the Git project's submission guidelines and adhered to them,
I'd be especially grateful.
2 " folding for Markdown headers, both styles (atx- and setex-)
3 " http://daringfireball.net/projects/markdown/syntax#header
5 " this code can be placed in file
6 " $HOME/.vim/after/ftplugin/markdown.vim
8 " original version from Steve Losh's gist: https://gist.github.com/1038710
10 function! s:is_mkdCode(lnum)
11 let name = synIDattr(synID(a:lnum, 1, 0), 'name')
12 return (name =~# '^mkd\%(Code$\|Snippet\)' || name !=# '' && name !~? '^\%(mkd\|html\)')
15 if get(g:, 'vim_markdown_folding_style_pythonic', 0)
16 function! Foldexpr_markdown(lnum)
21 let l1 = getline(a:lnum)
22 "~~~~~ keep track of fenced code blocks ~~~~~
23 "If we hit a code block fence
24 if l1 =~# '\v^[[:space:]>]*\v(`{3,}|\~{3,})\s*(\w+)?\s*$'
25 " toggle the variable that says if we're in a code block
26 if b:fenced_block == 0
27 let b:fenced_block = 1
28 let b:fence_str = matchstr(l1, '\v(`{3,}|\~{3,})')
29 elseif b:fenced_block == 1 && matchstr(l1, '\v(`{3,}|\~{3,})') ==# b:fence_str
30 let b:fenced_block = 0
33 " else, if we're caring about front matter
34 elseif get(g:, 'vim_markdown_frontmatter', 0) == 1
35 " if we're in front matter and not on line 1
36 if b:front_matter == 1 && a:lnum > 2
37 let l0 = getline(a:lnum-1)
38 " if the previous line fenced front matter
40 " we must not be in front matter
41 let b:front_matter = 0
43 " else, if we're on line one
45 " if we hit a front matter fence
47 " we're in the front matter
48 let b:front_matter = 1
53 " if we're in a code block or front matter
54 if b:fenced_block ==# 1 || b:front_matter ==# 1
59 " keep previous foldlevel
64 let l2 = getline(a:lnum+1)
65 " if the next line starts with two or more '='
67 if l2 =~# '^==\+\s*' && !s:is_mkdCode(a:lnum+1)
68 " next line is underlined (level 1)
70 " else, if the nex line starts with two or more '-'
71 " but is not comment closer (-->)
73 elseif l2 =~# '^--\+\s*$' && !s:is_mkdCode(a:lnum+1)
74 " next line is underlined (level 2)
78 "if we're on a non-code line starting with a pound sign
79 if l1 =~# '^#' && !s:is_mkdCode(a:lnum)
80 " set the fold level to the number of hashes -1
81 " return '>'.(matchend(l1, '^#\+') - 1)
82 " set the fold level to the number of hashes
83 return '>'.(matchend(l1, '^#\+'))
84 " else, if we're on line 1
89 " keep previous foldlevel
94 function! Foldtext_markdown()
95 let line = getline(v:foldstart)
96 let has_numbers = &number || &relativenumber
97 let nucolwidth = &foldcolumn + has_numbers * &numberwidth
98 let windowwidth = winwidth(0) - nucolwidth - 6
99 let foldedlinecount = v:foldend - v:foldstart
100 let line = strpart(line, 0, windowwidth - 2 -len(foldedlinecount))
101 let line = substitute(line, '\%("""\|''''''\)', '', '')
102 let fillcharcount = windowwidth - len(line) - len(foldedlinecount) + 1
103 return line . ' ' . repeat('-', fillcharcount) . ' ' . foldedlinecount
105 else " vim_markdown_folding_style_pythonic == 0
106 function! Foldexpr_markdown(lnum)
111 let l0 = getline(a:lnum-1)
114 " keep track of fenced code blocks
115 if l0 =~# '\v^[[:space:]>]*\v(`{3,}|\~{3,})\s*(\w+)?\s*$'
116 if b:fenced_block == 0
117 let b:fenced_block = 1
118 let b:fence_str = matchstr(l0, '\v(`{3,}|\~{3,})')
119 elseif b:fenced_block == 1 && matchstr(l0, '\v(`{3,}|\~{3,})') ==# b:fence_str
120 let b:fenced_block = 0
123 elseif get(g:, 'vim_markdown_frontmatter', 0) == 1
124 if b:front_matter == 1
126 let b:front_matter = 0
130 let b:front_matter = 1
135 if b:fenced_block == 1 || b:front_matter == 1
136 " keep previous foldlevel
140 let l2 = getline(a:lnum+1)
141 if l2 =~# '^==\+\s*' && !s:is_mkdCode(a:lnum+1)
142 " next line is underlined (level 1)
144 elseif l2 =~# '^--\+\s*$' && !s:is_mkdCode(a:lnum+1)
145 " next line is underlined (level 2)
146 if s:vim_markdown_folding_level >= 2
153 let l1 = getline(a:lnum)
154 if l1 =~# '^#' && !s:is_mkdCode(a:lnum)
155 " fold level according to option
156 if s:vim_markdown_folding_level == 1 || matchend(l1, '^#\+') > s:vim_markdown_folding_level
157 if a:lnum == line('$')
158 return matchend(l1, '^#\+') - 1
163 " headers are not folded
168 if l0 =~# '^#' && !s:is_mkdCode(a:lnum-1)
169 " previous line starts with hashes
170 return '>'.matchend(l0, '^#\+')
172 " keep previous foldlevel
179 let b:fenced_block = 0
180 let b:front_matter = 0
181 let s:vim_markdown_folding_level = get(g:, 'vim_markdown_folding_level', 1)
183 function! s:MarkdownSetupFolding()
184 if !get(g:, 'vim_markdown_folding_disabled', 0)
185 if get(g:, 'vim_markdown_folding_style_pythonic', 0)
186 if get(g:, 'vim_markdown_override_foldtext', 1)
187 setlocal foldtext=Foldtext_markdown()
190 setlocal foldexpr=Foldexpr_markdown(v:lnum)
191 setlocal foldmethod=expr
195 function! s:MarkdownSetupFoldLevel()
196 if get(g:, 'vim_markdown_folding_style_pythonic', 0)
197 " set default foldlevel
198 execute 'setlocal foldlevel='.s:vim_markdown_folding_level
202 call s:MarkdownSetupFoldLevel()
203 call s:MarkdownSetupFolding()
206 " These autocmds need to be kept in sync with the autocmds calling
207 " s:MarkdownRefreshSyntax in ftplugin/markdown.vim.
208 autocmd BufWinEnter,BufWritePost <buffer> call s:MarkdownSetupFolding()
209 autocmd InsertEnter,InsertLeave <buffer> call s:MarkdownSetupFolding()
210 autocmd CursorHold,CursorHoldI <buffer> call s:MarkdownSetupFolding()