vim/ftplugin/lisp/lispfolding.vim @ 774253fee5f6
Updates
author |
Steve Losh <steve@stevelosh.com> |
date |
Thu, 30 Jun 2016 11:41:51 +0000 |
parents |
86bde83af492 |
children |
54633d8bf6d8 |
" if exists('loaded_lispfolding') || &cp
" finish
" endif
let loaded_lispfolding=1
let s:lispfold_flet_re = '\vlabels|flet'
function! LispFoldingFormIsFlet()
" Return whether the form the cursor is on is a fletlike.
let old_z = @z
" Yank the next word.
normal! l
silent normal! "zyiw
let word = @z
let @z = old_z
" See if that next word is a fletlike thing.
if word =~ s:lispfold_flet_re
return 1
else
return 0
endif
endfunction
function! LispFoldingStartFlet(lnum)
" Return 1 when the given line is the start of a multi-line flet'ed
" function definition. We want to fold those. Return -1 if it's
" a single-line fletted definition. Return 0 if it's neither.
"
" Relies on things being indented correctly to help the speed.
"
" Basically this thing is a total shitshow, turn back now.
"
" TODO: the function definitions have to be indented, fix that
let l = getline(a:lnum)
let save_cursor = getpos('.')
try
" A foldable flet looks like this:
"
" (flet
" ((foo ()
" ...)
" (bar ()
" ...))
" body)
"
" Make sure the cursor's on the current line.
call setpos('.', [0, a:lnum, 1, 1])
" Check if the line starts with ( or ((, and move to the appropriate
" "start of the function form" character.
if l =~ '\v^\s\s\s\s+\(\(\k+( \(|$)'
normal! ^l
elseif l =~ '\v^\s\s\s\s\s+\(\k+( \(|$)'
normal! ^
else
return 0
endif
let save_start = getpos('.')
" Pop up two levels in the paren stack.
" TODO: make sure we actually do, not that it matters in practice
call searchpair('(', '', ')', 'b')
call searchpair('(', '', ')', 'b')
if !LispFoldingFormIsFlet()
return 0
endif
" We know this is a fletthing, but if it only spans one line, bail.
call setpos('.', save_start)
if searchpairpos('(', '', ')')[0] == a:lnum
return -1
end
" congrats, u made it
return 1
finally
call setpos('.', save_cursor)
endtry
endfunction
function! LispFoldingEndFlet(lnum)
" Return whether we're at the last line of a multi-line fletted function.
let l = getline(a:lnum)
let save_cursor = getpos('.')
try
if l =~ '\v\)\)$'
call setpos('.', [0, a:lnum, len(l) - 1, 1])
let start_line = searchpairpos('(', '', ')', 'b')[0]
let r = LispFoldingStartFlet(start_line)
if r == 1
return 1
elseif r == -1
return 0
endif
endif
if l =~ '\v\)$'
call setpos('.', [0, a:lnum, len(l), 1])
let start_line = searchpairpos('(', '', ')', 'b')[0]
if LispFoldingStartFlet(start_line) == 1
return 1
endif
endif
return 0
finally
call setpos('.', save_cursor)
endtry
endfunction
function! GetLispFold(lnum)
let save_cursor = getpos('.')
let save_search = @/
let inline_fn_comment_re = '\v^ *;;( .*)?$'
try
if getline(a:lnum) =~ '^;;;; '
" Never fold top-level header comments
return "0"
elseif getline(a:lnum) =~ '^;;; '
" Subheader top level comments should get folded together in level 1
return "1"
elseif getline(a:lnum) =~ inline_fn_comment_re
" Inline function comments should increment the fold level
let prev = getline(a:lnum - 1) =~ inline_fn_comment_re
let next = getline(a:lnum + 1) =~ inline_fn_comment_re
if (!prev) && next
return "a1"
elseif prev && (!next)
return "s1"
else
return "="
endif
elseif getline(a:lnum) =~ '^; '
" don't include commentary-commented lines in deeper folds than necessary
return "-1"
elseif getline(a:lnum) =~ '^(test '
" (test ...) folds at the top level
return ">1"
elseif getline(a:lnum) =~ '^(declaim\( \|$\)'
" fold top level declaims
return ">1"
elseif getline(a:lnum) =~ '^(def'
" fuck it just fold everything that looks kinda deffy
return ">1"
elseif getline(a:lnum) =~ '^$' && getline(a:lnum - 1) =~ '^$'
return "0"
elseif getline(a:lnum) =~ '^$'
" Single blank lines fold along with the previous line, so that the
" blank line after a defun gets folded into the defun.
return "="
" elseif LispFoldingStartFlet(a:lnum) == 1
" " if this is a function definition in a labels/flet/etc, we want to
" " start a new deeper fold
" return ">2"
" elseif LispFoldingEndFlet(a:lnum)
" " if this is the END of a flet definition, we should pop a foldlevel
" return "<2"
else
return "="
endif
finally
call setpos('.', save_cursor)
let @/ = save_search
endtry
endfunction
function! TurnOnLispFolding()
setlocal foldexpr=GetLispFold(v:lnum)
setlocal foldmethod=expr
" nnoremap <buffer> qq :echo GetLispFold(getpos('.')[1])<cr>
endfunction