1 " Fold expression for asciidoc files |
|
2 " |
|
3 " NOTE: only supports Atx-style, not Setext style sections. See |
|
4 " http://asciidoctor.org/docs/asciidoc-recommended-practices/ for more info. |
|
5 " |
|
6 " Script's originally based on https://github.com/nelstrom/vim-markdown-folding |
|
7 " |
|
8 " vim:set fdm=marker: |
|
9 |
|
10 " Fold expressions {{{1 |
|
11 function! StackedMarkdownFolds() |
|
12 if HeadingDepth(v:lnum) > 0 |
|
13 return ">1" |
|
14 else |
|
15 return "=" |
|
16 endif |
|
17 endfunction |
|
18 |
|
19 function! NestedMarkdownFolds() |
|
20 let depth = HeadingDepth(v:lnum) |
|
21 if depth > 0 |
|
22 return ">".depth |
|
23 else |
|
24 return "=" |
|
25 endif |
|
26 endfunction |
|
27 |
|
28 " Helpers {{{1 |
|
29 function! s:SID() |
|
30 return matchstr(expand('<sfile>'), '<SNR>\d\+_') |
|
31 endfunction |
|
32 |
|
33 function! HeadingDepth(lnum) |
|
34 " 5 ='s is deepest section level, according to `asciidoc --help syntax`. |
|
35 " Only 1 = is the document header, which isn't really worth folding, so we |
|
36 " ignore it and subtract one off the count to get the fold level. |
|
37 let level=0 |
|
38 let thisline = getline(a:lnum) |
|
39 let hashCount = len(matchstr(thisline, '^=\{2,5}')) |
|
40 " Ignore lines with too many ='s (usually block deliminators) |
|
41 if hashCount > 1 && hashCount < 5 |
|
42 let level = hashCount - 1 |
|
43 endif |
|
44 |
|
45 if level > 0 && LineIsFenced(a:lnum) |
|
46 " Ignore ='s if they appear within fenced code blocks |
|
47 let level = 0 |
|
48 endif |
|
49 |
|
50 return level |
|
51 endfunction |
|
52 |
|
53 function! LineIsFenced(lnum) |
|
54 if exists("b:current_syntax") && b:current_syntax ==# 'asciidoc' |
|
55 " It's cheap to check if the current line has 'markdownCode' syntax group |
|
56 return s:HasSyntaxGroup(a:lnum, 'markdownCode') |
|
57 endif |
|
58 endfunction |
|
59 |
|
60 function! s:HasSyntaxGroup(lnum, targetGroup) |
|
61 let syntaxGroup = map(synstack(a:lnum, 1), 'synIDattr(v:val, "name")') |
|
62 for value in syntaxGroup |
|
63 " Likely dependant on the asciidoc syntax file, so will need to be |
|
64 " updated accordingly |
|
65 if value =~ '\vasciidocListingBlock' |
|
66 return 1 |
|
67 endif |
|
68 endfor |
|
69 endfunction |
|
70 |
|
71 |
|
72 function! s:FoldText() |
|
73 let level = HeadingDepth(v:foldstart) |
|
74 let indent = repeat('=', level) |
|
75 let title = substitute(getline(v:foldstart), '^=\+\s*', '', '') |
|
76 let foldsize = (v:foldend - v:foldstart) |
|
77 let linecount = '['.foldsize.' line'.(foldsize>1?'s':'').']' |
|
78 return indent.' '.title.' '.linecount |
|
79 endfunction |
|
80 |
|
81 " API {{{1 |
|
82 function! ToggleMarkdownFoldexpr() |
|
83 if &l:foldexpr ==# 'StackedMarkdownFolds()' |
|
84 setlocal foldexpr=NestedMarkdownFolds() |
|
85 else |
|
86 setlocal foldexpr=StackedMarkdownFolds() |
|
87 endif |
|
88 endfunction |
|
89 command! -buffer FoldToggle call ToggleMarkdownFoldexpr() |
|
90 |
|
91 " Setup {{{1 |
|
92 if !exists('g:markdown_fold_style') |
|
93 let g:markdown_fold_style = 'stacked' |
|
94 endif |
|
95 |
|
96 if !exists('g:markdown_fold_override_foldtext') |
|
97 let g:markdown_fold_override_foldtext = 1 |
|
98 endif |
|
99 |
|
100 setlocal foldmethod=expr |
|
101 |
|
102 if g:markdown_fold_override_foldtext |
|
103 let &l:foldtext = s:SID() . 'FoldText()' |
|
104 endif |
|
105 |
|
106 let &l:foldexpr = |
|
107 \ g:markdown_fold_style ==# 'nested' |
|
108 \ ? 'NestedMarkdownFolds()' |
|
109 \ : 'StackedMarkdownFolds()' |
|
110 |
|
111 " Teardown {{{1 |
|
112 " To avoid errors when undo_ftplugin not defined yet |
|
113 if !exists('b:undo_ftplugin') |
|
114 let b:undo_ftplugin = '' |
|
115 endif |
|
116 |
|
117 let b:undo_ftplugin .= ' |
|
118 \ | setlocal foldmethod< foldtext< foldexpr< |
|
119 \ | delcommand FoldToggle |
|
120 \ ' |
|
121 |
|