Add the following line to your `.vimrc` to disable the folding configuration:
```vim
-let g:vim_markdown_folding_disabled=1
+let g:vim_markdown_folding_disabled = 1
```
This option only controls Vim Markdown specific folding configuration.
the following to your `.vimrc`:
```vim
-let g:vim_markdown_folding_style_pythonic=1
+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:
```vim
-let g:vim_markdown_no_default_key_mappings=1
+let g:vim_markdown_no_default_key_mappings = 1
```
You can also map them by yourself with `<Plug>` mappings.
Used as `$x^2$`, `$$x^2$$`, escapable as `\$x\$` and `\$\$x\$\$`.
```vim
-let g:vim_markdown_math=1
+let g:vim_markdown_math = 1
```
#### YAML frontmatter
Highlight YAML frontmatter as used by Jekyll:
```vim
-let g:vim_markdown_frontmatter=1
+let g:vim_markdown_frontmatter = 1
```
+
## Mappings
The following work on normal and visual modes:
" original version from Steve Losh's gist: https://gist.github.com/1038710
function! s:is_mkdCode(lnum)
- return synIDattr(synID(a:lnum, 1, 0), 'name') == 'mkdCode'
+ let name = synIDattr(synID(a:lnum, 1, 0), 'name')
+ return (name =~ '^mkd\%(Code$\|Snippet\)' || name != '' && name !~ '^\%(mkd\|html\)')
endfunction
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
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
let d.text = substitute(d.text, '\v[ ]*#*$', '', '')
" setex headers
else
- let l:next_line = getbufline(bufname(d.bufnr), d.lnum+1)
+ let l:next_line = getbufline(d.bufnr, d.lnum+1)
if match(l:next_line, "=") > -1
let l:level = 0
elseif match(l:next_line, "-") > -1
command! -buffer Toch call s:Toc('horizontal')
command! -buffer Tocv call s:Toc('vertical')
command! -buffer Toct call s:Toc('tab')
+
+" Heavily based on vim-notes - http://peterodding.com/code/vim/notes/
+let s:filetype_dict = {
+ \ 'c++': 'cpp',
+ \ 'viml': 'vim'
+\ }
+
+function! s:Markdown_highlight_sources(force)
+ " Syntax highlight source code embedded in notes.
+ " Look for code blocks in the current file
+ let filetypes = {}
+ for line in getline(1, '$')
+ let ft = matchstr(line, '```\zs[0-9A-Za-z_+-]*')
+ if !empty(ft) && ft !~ '^\d*$' | let filetypes[ft] = 1 | endif
+ endfor
+ if !exists('b:mkd_known_filetypes')
+ let b:mkd_known_filetypes = {}
+ endif
+ if !a:force && (b:mkd_known_filetypes == filetypes || empty(filetypes))
+ return
+ endif
+
+ " Now we're ready to actually highlight the code blocks.
+ let startgroup = 'mkdCodeStart'
+ let endgroup = 'mkdCodeEnd'
+ for ft in keys(filetypes)
+ if a:force || !has_key(b:mkd_known_filetypes, ft)
+ if has_key(s:filetype_dict, ft)
+ let filetype = s:filetype_dict[ft]
+ else
+ let filetype = ft
+ endif
+ let group = 'mkdSnippet' . toupper(substitute(filetype, "[+-]", "_", "g"))
+ let include = s:syntax_include(filetype)
+ let command = 'syntax region %s matchgroup=%s start="^\s*```%s$" matchgroup=%s end="\s*```$" keepend contains=%s%s'
+ execute printf(command, group, startgroup, ft, endgroup, include, has('conceal') ? ' concealends' : '')
+ execute printf('syntax cluster mkdNonListItem add=%s', group)
+
+ let b:mkd_known_filetypes[ft] = 1
+ endif
+ endfor
+endfunction
+
+function! s:syntax_include(filetype)
+ " Include the syntax highlighting of another {filetype}.
+ let grouplistname = '@' . toupper(a:filetype)
+ " Unset the name of the current syntax while including the other syntax
+ " because some syntax scripts do nothing when "b:current_syntax" is set
+ if exists('b:current_syntax')
+ let syntax_save = b:current_syntax
+ unlet b:current_syntax
+ endif
+ try
+ execute 'syntax include' grouplistname 'syntax/' . a:filetype . '.vim'
+ execute 'syntax include' grouplistname 'after/syntax/' . a:filetype . '.vim'
+ catch /E484/
+ " Ignore missing scripts
+ endtry
+ " Restore the name of the current syntax
+ if exists('syntax_save')
+ let b:current_syntax = syntax_save
+ elseif exists('b:current_syntax')
+ unlet b:current_syntax
+ endif
+ return grouplistname
+endfunction
+
+
+function! s:Markdown_refresh_syntax(force)
+ if &filetype == 'markdown' && line('$') > 1
+ call s:Markdown_highlight_sources(a:force)
+ endif
+endfunction
+
+augroup Mkd
+ autocmd!
+ au BufWinEnter * call s:Markdown_refresh_syntax(1)
+ au BufWritePost * call s:Markdown_refresh_syntax(0)
+ au InsertEnter,InsertLeave * call s:Markdown_refresh_syntax(0)
+ au CursorHold,CursorHoldI * call s:Markdown_refresh_syntax(0)
+augroup END