Created
April 4, 2021 15:41
-
-
Save Fmajor/f124b8223530da20c03cbd58c1063f10 to your computer and use it in GitHub Desktop.
custom vim folding
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
"#<== custom highlights | |
" highligh enpty end of each line | |
highlight WhitespaceEOL ctermbg=red guibg=red | |
match WhitespaceEOL /\s\+$/ | |
highlight NoneText ctermfg=8 | |
highlight SpecialKey ctermfg=8 | |
" highlight link name1 name2 | |
highlight foldStart ctermfg=7 ctermbg=23 | |
highlight foldStartStr ctermfg=11 ctermbg=23 | |
call matchadd("foldStart", '^\s*.\?#<==*\ \(.*\)$\|^\s*.\?.\?#region:\ \(.*\)$') | |
call matchadd("foldStartStr", '^\s*.\?#<==*\ \zs\(.*\)\ze$\|^\s*.\?.\?#region:\ \zs\(.*\)\ze$') | |
highlight foldEnd ctermfg=0 ctermbg=13 | |
highlight foldEndStr ctermfg=190 ctermbg=13 | |
call matchadd("foldEnd", '^\s*.\?#==\+>\ \(.*\)$\|^\s*.\?.\?#endregion:\ \(.*\)$') | |
call matchadd("foldEndStr", '^\s*.\?#==\+>\ \zs\(.*\)\ze$\|^\s*.\?.\?#endregion:\ \zs\(.*\)\ze$') | |
"syntax region foldKeys start=/^\s*.\{1}#<==* / end=/$/ oneline contains=vimLineComment | |
highlight myComment cterm=bold ctermfg=11 ctermbg=22 | |
call matchadd("myComment", '.\?!!\+\ \(.*\)$') | |
highlight Folded term=standout ctermfg=14 ctermbg=242 guifg=Cyan guibg=DarkGrey | |
"!! myComment hight | |
"#==> custom highlights | |
"#<== custom folding method | |
" reload vimrc | |
nnoremap ,re :source ~/.vimrc<CR> | |
" This costom functions enable using both the 'indent' folding | |
" and the custom '#<==' '#==>' 'Marker' folding | |
" To improve the performance, i (on purpose) simplify the algorithms | |
" sometimes you will get WRONG folding layout when you edit the | |
" first or last line of each block | |
" then use `,re` to reload vimrc, this will fix the WRONG folding layout | |
"nnoremap <space> @=((foldclosed(line('.')) < 0) ? 'zc' :'zo')<CR> | |
nnoremap <silent> <space> za:redraw!<CR> | |
set foldenable | |
"set foldmethod=indent foldignore= | |
set foldmethod=expr | |
set foldexpr=MyFold(v:lnum) | |
"inBlock count the stack depth of my maker pair | |
let b:inBlock=0 | |
let b:lastLineNum=0 | |
let b:lastLevel=0 | |
let b:lastGoodLine=0 | |
let b:lastGoodBlock=0 | |
let b:startFoldingMark='^\s*.\?#<==*\|^.*#<==$\|^\s*.\?.\?#region' | |
let b:endFoldingMark='^\s*.\?#=*=>\|^.*#==>$\|^\s*.\?.\?#endregion' | |
" experiment function.. | |
let b:docStringGroupName='pythonDocstring' | |
function! DocStrStatus(linenum, linetext) | |
" to add additional fold level for docstring | |
let syntaxGroupName = map(synstack(a:linenum, 1), 'synIDattr(v:val, "name")') | |
let b:inDocStrFlag = index(syntaxGroupName, b:docStringGroupName) >= 0 | |
return b:inDocStrFlag | |
endfunction | |
function! MyFold(linenum) | |
let linetext = getline(a:linenum) | |
let level = indent(a:linenum) / &shiftwidth | |
"let l:inDocStr = DocStrStatus(a:linenum, linetext) | |
let l:inDocStr = 0 | |
"the first line have 0 fold level | |
if (a:linenum == 1) | |
let l:inDocStr = 0 | |
if linetext =~ b:startFoldingMark | |
let b:inBlock = 1 | |
let b:lastLineNum=a:linenum | |
let b:lastGoodLine=0 | |
let b:lastGoodBlock=0 | |
let b:lastLevel=level | |
return level + l:inDocStr | |
endif | |
let b:inBlock=0 | |
let b:lastInBlock=0 | |
let b:lastLineNum=a:linenum | |
let b:lastGoodLine=0 | |
let b:lastGoodBlock=b:inBlock | |
"echom a:linenum ':' level+b:inBlock '=' level '+' b:inBlock | |
let b:lastLevel=level + b:inBlock | |
return level + b:inBlock + l:inDocStr | |
endif | |
" not calculate line by line from last line, recovery good fold level from previous lines | |
if ((b:lastLineNum+1) != a:linenum) | |
"let l:inDocStr = 0 | |
let level = indent(a:linenum) / &shiftwidth | |
let lastGoodNum = a:linenum-1 | |
" skip black lines | |
silent echom 'recovery searching begin from: ' a:linenum ':' linetext ', lastLineNum:' b:lastLineNum | |
while (lastGoodNum>1 && getline(lastGoodNum) =~? '\v^\s*$' ) | |
silent echom 'recovery searching: lastGoodNum:' lastGoodNum ':' foldlevel(lastGoodNum) ": content:" getline(lastGoodNum) | |
silent echom 'recovery searching: lastGoodNum-1:' lastGoodNum-1 ':' foldlevel(lastGoodNum-1) ": content:" getline(lastGoodNum-1) ", go on" | |
let lastGoodNum -= 1 | |
endwhile | |
silent echom 'recovery search ok: lastGoodNum:' lastGoodNum ", content:" getline(lastGoodNum) ', infos: lastGoodLine' b:lastGoodLine 'lastGoodBlock:' b:lastGoodBlock | |
if (foldlevel(lastGoodNum)==-1) | |
let b:inBlock=b:lastGoodBlock | |
silent echom 'recovery inBlock with lastGoodBlock: ' b:inBlock | |
else | |
let lastlevel = indent(lastGoodNum) / &shiftwidth | |
let lastlinetext = getline(lastGoodNum) | |
let lastlinelevel = foldlevel(lastGoodNum) | |
if lastlinetext =~ b:startFoldingMark | |
let b:inBlock = lastlinelevel - lastlevel + 1 | |
silent echom 'recovery meet startFoldingMark ' b:inBlock | |
elseif lastlinetext =~ b:endFoldingMark | |
let b:inBlock = lastlinelevel - lastlevel - 1 | |
silent echom 'recovery meet endFoldingMark' b:inBlock | |
else | |
let b:inBlock = lastlinelevel - lastlevel | |
endif | |
silent echom 'recovery inBlock with line ' lastGoodNum 'to be: ' b:inBlock '=' lastlinelevel '-' lastlevel | |
endif | |
endif | |
"blank lines have undefined fold level | |
if getline(a:linenum) =~? '\v^\s*$' | |
"echom '(' b:lastLineNum ':' foldlevel(b:lastLineNum) ')' a:linenum ':' -1 | |
let b:lastLineNum=a:linenum | |
let b:lastLevel=-1 | |
return -1 | |
endif | |
" fold calculate line by line, lastnumber = linumber - 1 | |
" b:inBlock is the right value | |
"if next line is a start of new marker block, inBlock ++ | |
if linetext =~ b:startFoldingMark | |
let b:inBlock = b:inBlock + 1 | |
"echom '(' b:lastLineNum ':' foldlevel(b:lastLineNum) ')' a:linenum ':' level '|' b:inBlock '(+=1)' | |
let b:lastLineNum=a:linenum | |
if (b:lastLevel != -1) | |
let b:lastGoodLine=a:linenum | |
let b:lastGoodBlock=b:inBlock | |
endif | |
let b:lastLevel=level + b:inBlock - 1 | |
return level + b:inBlock - 1 " start fold in the next line | |
"if next line is an end of new marker block, inBlock - | |
elseif linetext =~ b:endFoldingMark | |
let b:inBlock = b:inBlock - 1 | |
"echom '(' b:lastLineNum ':' foldlevel(b:lastLineNum) ')' a:linenum ':' level+b:inBlock+1 "|" b:inBlock '(-=1)' | |
let b:lastLineNum=a:linenum | |
"if (b:lastLevel != -1) | |
let b:lastGoodLine=a:linenum | |
let b:lastGoodBlock=b:inBlock | |
"endif | |
let b:lastLevel=level + b:inBlock + 1 | |
return level + b:inBlock + 1 "the end is still folded | |
endif | |
"echom '(' b:lastLineNum ':' foldlevel(b:lastLineNum) ')' a:linenum ':' level+b:inBlock '=' level '+' b:inBlock | |
" for normal lines not in start and end folding mark list | |
let b:lastLineNum=a:linenum | |
"if (b:lastLevel != -1) | |
let b:lastGoodLine=a:linenum | |
let b:lastGoodBlock=b:inBlock | |
"endif | |
let b:lastLevel=level + b:inBlock | |
return level+b:inBlock + l:inDocStr | |
endfunction | |
" function for debug, leave it | |
nnoremap <F2> :call Do_debug_folding()<CR> | |
function! Do_debug_folding() | |
exec "echom foldlevel(line('.')) b:lastLineNum" | |
endfunction | |
set foldcolumn=0 | |
nnoremap ,fc :call Set_foldcolumn()<CR> | |
function! Set_foldcolumn() | |
if &foldcolumn=="0" | |
set foldcolumn=1 | |
echo "foldcolumn set to 3" | |
else | |
set foldcolumn=0 | |
echo "foldcolumn set to 0" | |
endif | |
endfunction | |
function! IndentLevel(lnum) | |
return indent(a:lnum) / &shiftwidth | |
endfunction | |
" ftplugin | |
" .vim/after/ftplugin/markdown/folding.vim | |
"!! fold text | |
function! MyFoldText() | |
let foldsize = (v:foldend-v:foldstart) | |
return getline(v:foldstart).' ('.foldsize.' lines)' | |
endfunction | |
set foldtext=MyFoldText() | |
"!! special folding method for some ft | |
" | |
"#<== Fold python docstring | |
" \| because map need a \, the origin exp not have that \ | |
" have problem for one line docstring with content after docstring | |
"nnoremap ,docf :%s/\v(\s*(class\|def).*)(#\<\=\=)@<!(\n\s*("""\|''').*)%(\5.*\5.*)@<!(\n\_.{-1,}\5)/\1 #<==\4\6 #==>/g<CR> | |
"nnoremap ,docuf :%s/\v(\s*(class\|def).*)( #\<\=\=)(\n\s*("""\|''').*)%(\5.*\5.*)@<!(\n\_.{-1,}\5)( #\=\=\>)/\1\4\6/g<CR> | |
"#==> | |
"#==> custom folding method |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment