From: Hiroshi Shirosaki Date: Thu, 14 Jan 2016 04:35:10 +0000 (+0900) Subject: Merge pull request #241 from alexconst/fix/hash_comments X-Git-Url: https://git.madduck.net/etc/vim.git/commitdiff_plain/63aabf4b47fc944afc210b974574d158eb7a08d0?hp=a33085a2edda53143d89c028ba67dfa46ffa8833 Merge pull request #241 from alexconst/fix/hash_comments Fix bug related to folding and hash comments --- diff --git a/README.md b/README.md index e9fac38..1a6fd1d 100644 --- a/README.md +++ b/README.md @@ -79,6 +79,21 @@ the following to your `.vimrc`: let g:vim_markdown_folding_style_pythonic = 1 ``` +### Set header folding level + +Folding level is a number between 1 and 6. By default, if not specified, it is set to 1. + +```vim +let g:vim_markdown_folding_level = 6 +``` + +Tip: it can be changed on the fly with: + +```vim +:let g:vim_markdown_folding_level = 1 +:edit +``` + ### Disable Default Key Mappings Add the following line to your `.vimrc` to disable default key mappings: @@ -109,6 +124,7 @@ Highlight YAML frontmatter as used by Jekyll: let g:vim_markdown_frontmatter = 1 ``` + ## Mappings The following work on normal and visual modes: diff --git a/after/ftplugin/markdown.vim b/after/ftplugin/markdown.vim index 3603485..84b6a4f 100644 --- a/after/ftplugin/markdown.vim +++ b/after/ftplugin/markdown.vim @@ -48,36 +48,63 @@ if get(g:, "vim_markdown_folding_style_pythonic", 0) endfunction else function! Foldexpr_markdown(lnum) + if (a:lnum == 1) + let l0 = '' + else + let l0 = getline(a:lnum-1) + endif + " keep track of fenced code blocks + if l0 =~ '````*' || l0 =~ '~~~~*' + if b:fenced_block == 0 + let b:fenced_block = 1 + elseif b:fenced_block == 1 + let b:fenced_block = 0 + endif + endif + let l2 = getline(a:lnum+1) if l2 =~ '^==\+\s*' && !s:is_mkdCode(a:lnum+1) " next line is underlined (level 1) return '>1' elseif l2 =~ '^--\+\s*' && !s:is_mkdCode(a:lnum+1) " next line is underlined (level 2) - return '>2' + if g:vim_markdown_folding_level == 2 + return '>1' + else + return '>2' + endif endif let l1 = getline(a:lnum) if l1 =~ '^#' && !s:is_mkdCode(a:lnum) - " don't include the section title in the fold - return '-1' + " fold level according to option + let l:level = matchend(l1, '^#\+') + if g:vim_markdown_folding_level == 1 || l:level > g:vim_markdown_folding_level + return -1 + else + " code blocks are always folded + return b:fenced_block + endif endif - if (a:lnum == 1) - let l0 = '' - else - let l0 = getline(a:lnum-1) - endif if l0 =~ '^#' && !s:is_mkdCode(a:lnum-1) + " collapse comments in fenced code blocks into a single fold + if b:fenced_block == 1 + return 1 + endif " current line starts with hashes return '>'.matchend(l0, '^#\+') else - " keep previous foldlevel + " fold here because of setext headers return '=' endif endfunction endif + +let b:fenced_block = 0 +let g:vim_markdown_folding_level = get(g:, "vim_markdown_folding_level", 1) + if !get(g:, "vim_markdown_folding_disabled", 0) setlocal foldexpr=Foldexpr_markdown(v:lnum) setlocal foldmethod=expr diff --git a/ftplugin/markdown.vim b/ftplugin/markdown.vim index 9e4db2d..7e2b35e 100644 --- a/ftplugin/markdown.vim +++ b/ftplugin/markdown.vim @@ -302,12 +302,38 @@ function! s:Toc(...) let l:window_type = 'vertical' endif - try - silent lvimgrep /\(^\S.*\(\n[=-]\+\n\)\@=\|^#\+\)/ % - catch /E480/ + + let b:bufnr = bufnr('%') + let b:fenced_block = 0 + let b:header_list = [] + let l:header_max_len = 0 + for i in range(1, line('$')) + let l:lineraw = getline(i) + let l:l1 = getline(i+1) + let l:line = substitute(l:lineraw, "#", "\\\#", "g") + if l:line =~ '````*' || l:line =~ '\~\~\~\~*' + if b:fenced_block == 0 + let b:fenced_block = 1 + elseif b:fenced_block == 1 + let b:fenced_block = 0 + endif + endif + if l:line =~ '^#\+' || l:l1 =~ '^==\+\s*' || l:l1 =~ '^--\+\s*' + let b:is_header = 1 + else + let b:is_header = 0 + endif + if b:is_header == 1 && b:fenced_block == 0 + " append line to location list + let b:item = {'lnum': i, 'text': l:line, 'valid': 1, 'bufnr': b:bufnr, 'col': 1} + let b:header_list = b:header_list + [b:item] + endif + endfor + if len(b:header_list) == 0 echom "Toc: No headers." return - endtry + endif + call setloclist(0, b:header_list) if l:window_type ==# 'horizontal' lopen diff --git a/test/folding-toc.vader b/test/folding-toc.vader new file mode 100644 index 0000000..e15ed73 --- /dev/null +++ b/test/folding-toc.vader @@ -0,0 +1,124 @@ +" Tests atx and setext folding, and :Toc. + +Before: + source ../after/ftplugin/markdown.vim + +After: + setlocal foldexpr=0 + setlocal foldmethod=manual + +Given markdown; +# chap 1 + +hello +world + +```bash +# some bash scripting +pwd + +# this is another comment +# other +echo "foo" +``` + +## chap 1.1 + +- dog +- cat + +~~~~bash +mkdir foo +cd foo +~~~~ + +### chap 1.1.1 + +- dragons +- fenixs + +# chap 2 + +another + +## chap 2.1 + +- uk +- japan +- china + + +# chap 3 + +nothing here + +chap 4 +====== + +setext are evil + +chap 4.1 +-------- + +evil indeed + +````bash +# get system info +uname -a +```` + +Execute (fold level): + AssertEqual foldlevel(1), 0, '# chap 1' + AssertEqual foldlevel(3), 1, 'hello' + AssertEqual foldlevel(6), 1, '```bash' + AssertEqual foldlevel(7), 1, '# some bash scripting' + AssertEqual foldlevel(15), 1, '## chap 1.1' + AssertEqual foldlevel(21), 2, 'mkdir foo' + AssertEqual foldlevel(25), 2, '### chap 1.1.1' + AssertEqual foldlevel(27), 3, '- dragons' + AssertEqual foldlevel(30), 1, '# chap 2' + AssertEqual foldlevel(32), 1, 'another' + AssertEqual foldlevel(34), 1, '# chap 2.1' + AssertEqual foldlevel(37), 2, '- japan' + AssertEqual foldlevel(41), 1, '# chap 3' + AssertEqual foldlevel(45), 1, 'chap 4\n======' + AssertEqual foldlevel(48), 1, 'setext are evil' + AssertEqual foldlevel(50), 2, 'chap 4.1\n------' +" BUG: for lines 30, 41, 45, the foldlevel should be 0. +" The folding behavior itself is correct, but the level number isn't. + +Execute (fold text result): + AssertEqual foldtextresult(2), '+-- 28 lines: hello' + AssertEqual foldtextresult(31), '+-- 10 lines: another' + AssertEqual foldtextresult(42), '+-- 3 lines: nothing here' + AssertEqual foldtextresult(45), '+-- 14 lines: chap 4' +" BUG: for line 45, vim shows and calling foldtextresult even echoes 15 lines. + +Execute (check TOC): + :Toc + let res = getloclist(0) + let elem = res[0] + AssertEqual elem.lnum, 1 + AssertEqual elem.text, '# chap 1' + let elem = res[1] + AssertEqual elem.lnum, 15 + AssertEqual elem.text, '## chap 1.1' + let elem = res[2] + AssertEqual elem.lnum, 25 + AssertEqual elem.text, '### chap 1.1.1' + let elem = res[3] + AssertEqual elem.lnum, 30 + AssertEqual elem.text, '# chap 2' + let elem = res[4] + AssertEqual elem.lnum, 34 + AssertEqual elem.text, '## chap 2.1' + let elem = res[5] + AssertEqual elem.lnum, 41 + AssertEqual elem.text, '# chap 3' + let elem = res[6] + AssertEqual elem.lnum, 45 + AssertEqual elem.text, 'chap 4' + let elem = res[7] + AssertEqual elem.lnum, 50 + AssertEqual elem.text, 'chap 4.1' +