summaryrefslogtreecommitdiffstats
path: root/foldtext.vim
diff options
context:
space:
mode:
Diffstat (limited to 'foldtext.vim')
-rw-r--r--foldtext.vim308
1 files changed, 308 insertions, 0 deletions
diff --git a/foldtext.vim b/foldtext.vim
new file mode 100644
index 0000000..a8f31b7
--- /dev/null
+++ b/foldtext.vim
@@ -0,0 +1,308 @@
+" Base {{{
+function Foldtext_base(...)
+ " use the argument for display if possible, otherwise the current line {{{
+ if a:0 > 0
+ let line = a:1
+ else
+ let line = getline(v:foldstart)
+ endif
+ " }}}
+ " remove the marker that caused this fold from the display {{{
+ let foldmarkers = split(&foldmarker, ',')
+ let line = substitute(line, '\V' . foldmarkers[0] . '\%(\d\+\)\?', ' ', '')
+ " }}}
+ " remove comments that vim knows about {{{
+ let comment = split(&commentstring, '%s')
+ if comment[0] != ''
+ let comment_begin = comment[0]
+ let comment_end = ''
+ if len(comment) > 1
+ let comment_end = comment[1]
+ end
+ let pattern = '\V' . comment_begin . '\s\*' . comment_end . '\s\*\$'
+ if line =~ pattern
+ let line = substitute(line, pattern, ' ', '')
+ else
+ let line = substitute(line, '.*\V' . comment_begin, ' ', '')
+ if comment_end != ''
+ let line = substitute(line, '\V' . comment_end, ' ', '')
+ endif
+ endif
+ endif
+ " }}}
+ " remove any remaining leading or trailing whitespace {{{
+ let line = substitute(line, '^\s*\(.\{-}\)\s*$', '\1', '')
+ " }}}
+ " align everything, and pad the end of the display with - {{{
+ let alignment = &columns - 18 - v:foldlevel
+ let line = strpart(printf('%-' . alignment . 's', line), 0, alignment)
+ let line = substitute(line, '\%( \)\@<= \%( *$\)\@=', '-', 'g')
+ " }}}
+ " format the line count {{{
+ let cnt = printf('%13s', '(' . (v:foldend - v:foldstart + 1) . ' lines) ')
+ " }}}
+ return '+-' . v:folddashes . ' ' . line . cnt
+endfunction
+" }}}
+" Latex {{{
+let s:latex_types = {'thm': 'Theorem', 'cor': 'Corollary',
+ \ 'lem': 'Lemma', 'defn': 'Definition'}
+function s:lower_letter(i) " {{{
+ return tolower(s:upper_letter(a:i))
+endfunction " }}}
+function s:roman_numeral(i) " {{{
+ let numeral = ''
+ let chars = 'ivxlcdm'
+ let i = a:i
+ for base in [0, 2, 4]
+ let c1 = strpart(chars, base, 1)
+ let c5 = strpart(chars, base + 1, 1)
+ let c10 = strpart(chars, base + 2, 1)
+ let digit = i % 10
+ if digit == 1
+ let numeral = c1 . numeral
+ elseif digit == 2
+ let numeral = c1 . c1 . numeral
+ elseif digit == 3
+ let numeral = c1 . c1 . c1 . numeral
+ elseif digit == 4
+ let numeral = c1 . c5 . numeral
+ elseif digit == 5
+ let numeral = c5 . numeral
+ elseif digit == 6
+ let numeral = c5 . c1 . numeral
+ elseif digit == 7
+ let numeral = c5 . c1 . c1 . numeral
+ elseif digit == 8
+ let numeral = c5 . c1 . c1 . c1 . numeral
+ elseif digit == 9
+ let numeral = c1 . c10 . numeral
+ endif
+ let i = i / 10
+ if i == 0
+ break
+ end
+ endfor
+
+ return repeat('m', i) . numeral
+endfunction " }}}
+function s:upper_letter(i) " {{{
+ if a:i <= 26
+ return nr2char(char2nr('A') + a:i - 1)
+ else
+ return 'ERROR'
+ endif
+endfunction " }}}
+function s:enumeration(depth, index) " {{{
+ if a:depth == 0
+ return a:index + 1
+ elseif a:depth == 1
+ return '(' . s:lower_letter(a:index + 1) . ')'
+ elseif a:depth == 2
+ return s:roman_numeral(a:index + 1)
+ elseif a:depth == 3
+ return s:upper_letter(a:index + 1)
+ else
+ return 'Error: invalid depth'
+ endif
+endfunction " }}}
+function Foldtext_latex() " {{{
+ let line = getline(v:foldstart)
+ " format theorems/etc nicely {{{
+ let matches = matchlist(line, '\\begin{\([^}]*\)}')
+ if !empty(matches) && has_key(s:latex_types, matches[1])
+ let type = s:latex_types[matches[1]]
+ let label = ''
+ let linenum = v:foldstart - 1
+ while linenum <= v:foldend
+ let linenum += 1
+ let line = getline(linenum)
+ let matches = matchlist(line, '\\label{\([^}]*\)}')
+ if !empty(matches)
+ let label = matches[1]
+ break
+ endif
+ endwhile
+ if label != ''
+ let label = ": " . label
+ endif
+ return Foldtext_base(type . label)
+ endif
+ " }}}
+ " format list items nicely {{{
+ " XXX: nesting different types of lists doesn't give quite the correct
+ " result - an enumerate inside an itemize inside an enumerate should use
+ " (a), but here it will go back to using 1.
+ if line =~ '\\item'
+ let item_name = []
+ let item_depth = 0
+ let nesting = 0
+ let type = ''
+ for linenum in range(v:foldstart, 0, -1)
+ let line = getline(linenum)
+ if line =~ '\\item'
+ if nesting == 0
+ let label = matchstr(line, '\\item\[\zs[^]]*\ze\]')
+ if len(item_name) == item_depth
+ if label != ''
+ let item_name += [label]
+ else
+ let item_name += [0]
+ endif
+ else
+ if type(item_name[item_depth]) == type(0) && label == ''
+ let item_name[item_depth] += 1
+ endif
+ endif
+ endif
+ elseif line =~ '\\begin{document}'
+ break
+ elseif line =~ '\\begin'
+ if nesting > 0
+ let nesting -= 1
+ else
+ let new_type = matchstr(line, '\\begin{\zs[^}]*\ze}')
+ if type == ''
+ let type = new_type
+ elseif type != new_type
+ let item_name = item_name[0:-2]
+ break
+ endif
+ let item_depth += 1
+ endif
+ elseif line =~ '\\end'
+ let nesting += 1
+ endif
+ endfor
+ " XXX: vim crashes if i just reverse the actual list
+ " should be fixed in patch 7.1.287
+ "let item_name = reverse(item_name)
+ let item_name = reverse(deepcopy(item_name))
+ for i in range(len(item_name))
+ if type(item_name[i]) != type('')
+ let item_name[i] = s:enumeration(i, item_name[i])
+ endif
+ endfor
+ let type = toupper(strpart(type, 0, 1)) . strpart(type, 1)
+ let line = type . ': ' . join(item_name, '.')
+ return Foldtext_base(line)
+ endif
+ " }}}
+ return Foldtext_base(line)
+endfunction " }}}
+" }}}
+" C++ {{{
+function Foldtext_cpp()
+ let line = getline(v:foldstart)
+ " strip out // comments {{{
+ let block_open = stridx(line, '/*')
+ let line_open = stridx(line, '//')
+ if block_open == -1 || line_open < block_open
+ return Foldtext_base(substitute(line, '//', ' ', ''))
+ endif
+ " }}}
+ return Foldtext_base(line)
+endfunction
+" }}}
+" Perl {{{
+function Foldtext_perl()
+ let line = getline(v:foldstart)
+ " format sub names with their arguments {{{
+ let matches = matchlist(line,
+ \ '^\s*\(sub\|around\|before\|after\|guard\)\s*\(\w\+\)')
+ if !empty(matches)
+ let linenum = v:foldstart - 1
+ let sub_type = matches[1]
+ let params = []
+ while linenum <= v:foldend
+ let linenum += 1
+ let next_line = getline(linenum)
+ " skip the opening brace and comment lines and blank lines
+ if next_line =~ '\s*{\s*' || next_line =~ '^\s*#' || next_line == ''
+ continue
+ endif
+
+ " handle 'my $var = shift;' type lines
+ let var = '\%(\$\|@\|%\|\*\)\w\+'
+ let shift_line = matchlist(next_line,
+ \ 'my\s*\(' . var . '\)\s*=\s*shift\%(\s*||\s*\(.\{-}\)\)\?;')
+ if !empty(shift_line)
+ if shift_line[1] == '$self' && empty(params)
+ if sub_type == 'sub'
+ let sub_type = ''
+ endif
+ let sub_type .= ' method'
+ elseif shift_line[1] == '$class' && empty(params)
+ if sub_type == 'sub'
+ let sub_type = ''
+ endif
+ let sub_type .= ' static method'
+ elseif shift_line[1] != '$orig'
+ let arg = shift_line[1]
+ " also catch default arguments
+ if shift_line[2] != ''
+ let arg .= ' = ' . shift_line[2]
+ endif
+ let params += [l:arg]
+ endif
+ continue
+ endif
+
+ " handle 'my ($a, $b) = @_;' type lines
+ let rest_line = matchlist(next_line, 'my\s*(\(.*\))\s*=\s*@_;')
+ if !empty(rest_line)
+ let rest_params = split(rest_line[1], ',\s*')
+ let params += rest_params
+ continue
+ endif
+
+ " handle 'my @args = @_;' type lines
+ let array_line = matchlist(next_line, 'my\s*\(@\w\+\)\s*=\s*@_;')
+ if !empty(array_line)
+ let params += [array_line[1]]
+ continue
+ endif
+
+ " handle 'my %args = @_;' type lines
+ let hash_line = matchlist(next_line, 'my\s*%\w\+\s*=\s*@_;')
+ if !empty(hash_line)
+ let params += ['paramhash']
+ continue
+ endif
+
+ " handle unknown uses of shift
+ if next_line =~ '\%(\<shift\>\%(\s*@\)\@!\)'
+ let params += ['$unknown']
+ continue
+ endif
+
+ " handle unknown uses of @_
+ if next_line =~ '@_\>'
+ let params += ['@unknown']
+ continue
+ endif
+ endwhile
+
+ let params = filter(params[0:-2], 'strpart(v:val, 0, 1) != "@"') +
+ \ [params[-1]]
+
+ return Foldtext_base(sub_type . ' ' . matches[2] .
+ \ '(' . join(params, ', ') . ')')
+ endif
+ " }}}
+ return Foldtext_base(line)
+endfunction
+" }}}
+
+if exists("g:Foldtext_enable") && g:Foldtext_enable
+ set foldtext=Foldtext_base()
+endif
+if exists("g:Foldtext_tex_enable") && g:Foldtext_tex_enable
+ autocmd FileType tex setlocal foldtext=Foldtext_latex()
+endif
+if exists("g:Foldtext_cpp_enable") && g:Foldtext_cpp_enable
+ autocmd FileType cpp setlocal foldtext=Foldtext_cpp()
+endif
+if exists("g:Foldtext_perl_enable") && g:Foldtext_perl_enable
+ autocmd FileType perl setlocal foldtext=Foldtext_perl()
+endif