diff --git a/README.md b/README.md index a3197253..1f72cd92 100644 --- a/README.md +++ b/README.md @@ -176,14 +176,21 @@ Try `:help concealcursor` and `:help conceallevel` for details. let g:vim_markdown_conceal = 0 + To enable link concealment, add the following to your `.vimrc`: + + let g:vim_markdown_conceal_links = 1 + + To disable delimiter concealment with special chars, add the following to + your `.vimrc`: + + let g:vim_markdown_conceal_chars = 0 + To disable math conceal with LaTeX math syntax enabled, add the following to your `.vimrc`: let g:tex_conceal = "" let g:vim_markdown_math = 1 -- `g:vim_markdown_conceal_code_blocks` - - Disabling conceal for code fences requires an additional setting: + To disable code fences concealment, add the following to your `.vimrc`: let g:vim_markdown_conceal_code_blocks = 0 @@ -296,7 +303,9 @@ The following options control which syntax extensions will be turned on. They ar * item1 * item2 - vim-markdown automatically insert the indent. By default, the number of spaces of indent is 4. If you'd like to change the number as 2, just write: + vim-markdown automatically insert the indent. By default, the number of + spaces of indent is the value of `shiftwidth`. If you'd like to change the + number as 2, just write: let g:vim_markdown_new_list_item_indent = 2 @@ -447,6 +456,13 @@ The main contributors of vim-markdown are: If you feel that your name should be on this list, please make a pull request listing your contributions. +Includes code from: + +- Changes default new_list_item_indent from 4 to sw from skewerr/vim-markdown. +- Fixing single '<' syntax from VVVFO/vim-markdown. +- Fixing syntax refresh for hovering windows tomtomjhj/vim-markdown. +- InsertToc from cdelledonne/vim-markdown. + ## License The MIT License (MIT) diff --git a/after/ftplugin/markdown.vim b/after/ftplugin/markdown.vim index 8be6ff91..0c991d8a 100644 --- a/after/ftplugin/markdown.vim +++ b/after/ftplugin/markdown.vim @@ -17,43 +17,43 @@ if get(g:, "vim_markdown_folding_style_pythonic", 0) let l1 = getline(a:lnum) "~~~~~ keep track of fenced code blocks ~~~~~ "If we hit a code block fence - if l1 =~ '````*' || l1 =~ '\~\~\~\~*' - " toggle the variable that says if we're in a code block - if b:fenced_block == 0 - let b:fenced_block = 1 - elseif b:fenced_block == 1 - let b:fenced_block = 0 - endif - " else, if we're caring about front matter - elseif g:vim_markdown_frontmatter == 1 - " if we're in front matter and not on line 1 - if b:front_matter == 1 && a:lnum > 2 - let l0 = getline(a:lnum-1) - " if the previous line fenced front matter - if l0 == '---' - " we must not be in front matter - let b:front_matter = 0 - endif - " else, if we're on line one - elseif a:lnum == 1 - " if we hit a front matter fence - if l1 == '---' - " we're in the front matter - let b:front_matter = 1 - endif - endif - endif - - " if we're in a code block or front matter - if b:fenced_block == 1 || b:front_matter == 1 - if a:lnum == 1 - " fold any 'preamble' - return '>1' - else - " keep previous foldlevel - return '=' - endif - endif + " if l1 =~ '````*' || l1 =~ '\~\~\~\~*' + " " toggle the variable that says if we're in a code block + " if b:fenced_block == 0 + " let b:fenced_block = 1 + " elseif b:fenced_block == 1 + " let b:fenced_block = 0 + " endif + " " else, if we're caring about front matter + " elseif g:vim_markdown_frontmatter == 1 + " " if we're in front matter and not on line 1 + " if b:front_matter == 1 && a:lnum > 2 + " let l0 = getline(a:lnum-1) + " " if the previous line fenced front matter + " if l0 == '---' + " " we must not be in front matter + " let b:front_matter = 0 + " endif + " " else, if we're on line one + " elseif a:lnum == 1 + " " if we hit a front matter fence + " if l1 == '---' + " " we're in the front matter + " let b:front_matter = 1 + " endif + " endif + " endif + + " " if we're in a code block or front matter + " if b:fenced_block == 1 || b:front_matter == 1 + " if a:lnum == 1 + " " fold any 'preamble' + " return '>1' + " else + " " keep previous foldlevel + " return '=' + " endif + " endif let l2 = getline(a:lnum+1) " if the next line starts with two or more '=' diff --git a/doc/vim-markdown.txt b/doc/vim-markdown.txt index 4d731293..a8810471 100644 --- a/doc/vim-markdown.txt +++ b/doc/vim-markdown.txt @@ -252,6 +252,15 @@ Syntax Concealing ~ > let g:vim_markdown_conceal = 0 < + To enable link concealment, add the following to your '.vimrc': + + let g:vim_markdown_conceal_links = 1 + + To disable delimiter concealment with special chars, add the following to + your '.vimrc': + + let g:vim_markdown_conceal_chars = 0 + To disable math conceal with LaTeX math syntax enabled, add the following to your '.vimrc': > @@ -261,7 +270,7 @@ Syntax Concealing ~ *g:vim_markdown_conceal_code_blocks* - 'g:vim_markdown_conceal_code_blocks' - Disabling conceal for code fences requires an additional setting: + To disable code fences concealment, add the following to your '.vimrc': > let g:vim_markdown_conceal_code_blocks = 0 < @@ -408,7 +417,8 @@ Adjust new list item indent ~ * item2 < vim-markdown automatically insert the indent. By default, the number of - spaces of indent is 4. If you'd like to change the number as 2, just write: + spaces of indent is the value of 'shiftwidth'. If you'd like to change the + number as 2, just write: > let g:vim_markdown_new_list_item_indent = 2 < diff --git a/ftplugin/markdown.vim b/ftplugin/markdown.vim index d6e51c21..4c7b7a60 100644 --- a/ftplugin/markdown.vim +++ b/ftplugin/markdown.vim @@ -788,7 +788,7 @@ function! s:MarkdownHighlightSources(force) " Look for code blocks in the current file let filetypes = {} for line in getline(1, '$') - let ft = matchstr(line, '```\s*\zs[0-9A-Za-z_+-]*\ze.*') + let ft = matchstr(line, '\(`\{3,1}\|\~\{3,}\)\s*\zs[0-9A-Za-z_+-]*\ze.*') if !empty(ft) && ft !~ '^\d*$' | let filetypes[ft] = 1 | endif endfor if !exists('b:mkd_known_filetypes') @@ -819,8 +819,11 @@ function! s:MarkdownHighlightSources(force) else let include = '@' . toupper(filetype) endif - let command = 'syntax region %s matchgroup=%s start="^\s*```\s*%s.*$" matchgroup=%s end="\s*```$" keepend contains=%s%s' - execute printf(command, group, startgroup, ft, endgroup, include, has('conceal') && get(g:, 'vim_markdown_conceal', 1) && get(g:, 'vim_markdown_conceal_code_blocks', 1) ? ' concealends' : '') + let concealends = has('conceal') && get(g:, 'vim_markdown_conceal', 1) && get(g:, 'vim_markdown_conceal_code_blocks', 1) ? ' concealends' : '' + let command = 'syntax region %s start="^\s*\z(`\{3,}\)\s*%s.*$" end="\s*\z1`*\s*$" keepend contains=mkdCodeStart,mkdCodeEnd,%s%s' + execute printf(command, group, ft, include, concealends) + let command = 'syntax region %s start="^\s*\z(\~\{3,}\)\s*%s.*$" end="\s*\z1\~*\s*$" keepend contains=mkdCodeStart,mkdCodeEnd,%s%s' + execute printf(command, group, ft, include, concealends) execute printf('syntax cluster mkdNonListItem add=%s', group) let b:mkd_known_filetypes[ft] = 1 @@ -871,7 +874,7 @@ augroup Mkd autocmd! * autocmd BufWinEnter call s:MarkdownRefreshSyntax(1) autocmd BufUnload call s:MarkdownClearSyntaxVariables() - autocmd BufWritePost call s:MarkdownRefreshSyntax(0) + autocmd BufWritePost,WinLeave call s:MarkdownRefreshSyntax(0) autocmd InsertEnter,InsertLeave call s:MarkdownRefreshSyntax(0) autocmd CursorHold,CursorHoldI call s:MarkdownRefreshSyntax(0) augroup END diff --git a/indent/markdown.vim b/indent/markdown.vim index 2fa4cda8..8f0d3c1a 100755 --- a/indent/markdown.vim +++ b/indent/markdown.vim @@ -48,7 +48,7 @@ function GetMarkdownIndent() if v:lnum > 2 && s:IsBlankLine(getline(v:lnum - 1)) && s:IsBlankLine(getline(v:lnum - 2)) return 0 endif - let list_ind = get(g:, "vim_markdown_new_list_item_indent", 4) + let list_ind = get(g:, "vim_markdown_new_list_item_indent", &shiftwidth) " Find a non-blank line above the current line. let lnum = s:PrevNonBlank(v:lnum - 1) " At the start of the file use zero indent. diff --git a/syntax/markdown.vim b/syntax/markdown.vim index 0a028507..3e760bab 100644 --- a/syntax/markdown.vim +++ b/syntax/markdown.vim @@ -34,16 +34,67 @@ syn spell toplevel syn case ignore syn sync linebreaks=1 +let s:concealflag = 0 let s:conceal = '' let s:concealends = '' let s:concealcode = '' if has('conceal') && get(g:, 'vim_markdown_conceal', 1) + let s:concealflag = 1 let s:conceal = ' conceal' let s:concealends = ' concealends' endif -if has('conceal') && get(g:, 'vim_markdown_conceal_code_blocks', 1) +if s:concealflag == 1 && get(g:, 'vim_markdown_conceal_code_blocks', 1) let s:concealcode = ' concealends' endif +if s:concealflag == 1 && get(g:, 'vim_markdown_conceal_links', 0) + let s:conceallink = ' conceal' + let s:conceallinkends = ' concealends' +else + let s:conceallink = '' + let s:conceallinkends = '' +endif + +if &encoding ==# 'utf-8' + let s:cchars = { + \'newline': '↵', + \'image': '▨', + \'super': 'ⁿ', + \'sub': 'ₙ', + \'strike': 'x̶', + \'atx': '§', + \'codelang': 'λ', + \'codeend': '—', + \'abbrev': '→', + \'footnote': '†', + \'definition': ' ', + \'li': '•', + \'html_c_s': '‹', + \'html_c_e': '›'} +else + " ascii defaults + let s:cchars = { + \'newline': ' ', + \'image': 'i', + \'super': '^', + \'sub': '_', + \'strike': '~', + \'atx': '#', + \'codelang': 'l', + \'codeend': '-', + \'abbrev': 'a', + \'footnote': 'f', + \'definition': ' ', + \'li': '*', + \'html_c_s': '+', + \'html_c_e': '+'} +endif +function! s:ConcealChar(conceal_char) + if s:concealflag == 1 && get(g:, 'vim_markdown_conceal_chars', 1) + return ' conceal cchar='.s:cchars[a:conceal_char] + else + return '' + endif +endfunction " additions to HTML groups if get(g:, 'vim_markdown_emphasis_multiline', 1) @@ -51,21 +102,35 @@ if get(g:, 'vim_markdown_emphasis_multiline', 1) else let s:oneline = ' oneline' endif -syn region mkdItalic matchgroup=mkdItalic start="\%(\*\|_\)" end="\%(\*\|_\)" -syn region mkdBold matchgroup=mkdBold start="\%(\*\*\|__\)" end="\%(\*\*\|__\)" -syn region mkdBoldItalic matchgroup=mkdBoldItalic start="\%(\*\*\*\|___\)" end="\%(\*\*\*\|___\)" -execute 'syn region htmlItalic matchgroup=mkdItalic start="\%(^\|\s\)\zs\*\ze[^\\\*\t ]\%(\%([^*]\|\\\*\|\n\)*[^\\\*\t ]\)\?\*\_W" end="[^\\\*\t ]\zs\*\ze\_W" keepend contains=@Spell' . s:oneline . s:concealends -execute 'syn region htmlItalic matchgroup=mkdItalic start="\%(^\|\s\)\zs_\ze[^\\_\t ]" end="[^\\_\t ]\zs_\ze\_W" keepend contains=@Spell' . s:oneline . s:concealends -execute 'syn region htmlBold matchgroup=mkdBold start="\%(^\|\s\)\zs\*\*\ze\S" end="\S\zs\*\*" keepend contains=@Spell' . s:oneline . s:concealends -execute 'syn region htmlBold matchgroup=mkdBold start="\%(^\|\s\)\zs__\ze\S" end="\S\zs__" keepend contains=@Spell' . s:oneline . s:concealends -execute 'syn region htmlBoldItalic matchgroup=mkdBoldItalic start="\%(^\|\s\)\zs\*\*\*\ze\S" end="\S\zs\*\*\*" keepend contains=@Spell' . s:oneline . s:concealends -execute 'syn region htmlBoldItalic matchgroup=mkdBoldItalic start="\%(^\|\s\)\zs___\ze\S" end="\S\zs___" keepend contains=@Spell' . s:oneline . s:concealends +execute 'syn region htmlItalic matchgroup=mkdItalic ' + \ . 'start="\%(\s\|_\|^\)\@<=\*\%(\s\|\*\|$\)\@!" end="\%(\s\|\*\)\@/ keepend contains=mkdCommentStart,mkdCommentEnd,@Spell +execute 'syn match mkdCommentStart // contained' . s:ConcealChar('html_c_e') " [link](URL) | [link][id] | [link][] | ![image](URL) syn region mkdFootnotes matchgroup=mkdDelimiter start="\[^" end="\]" -execute 'syn region mkdID matchgroup=mkdDelimiter start="\[" end="\]" contained oneline' . s:conceal -execute 'syn region mkdURL matchgroup=mkdDelimiter start="(" end=")" contained oneline' . s:conceal -execute 'syn region mkdLink matchgroup=mkdDelimiter start="\\\@/ end=/$/ contains=mkdLink,mkdInlineURL,mkdLineBreak,@Spell execute 'syn region mkdCode matchgroup=mkdCodeDelimiter start=/\(\([^\\]\|^\)\\\)\@]*\)\\\@" end=""' . s:concealcode execute 'syn region mkdCode matchgroup=mkdCodeDelimiter start="]*\)\\\@" end=""' . s:concealcode +" TODO: use matchgroup for start and end when working with concealment of +" start/end groups +execute 'syn region mkdCode matchgroup=mkdCodeStart start=/^\s*\z(`\{3,}\)\s*[0-9A-Za-z_+-]*\s*$/ matchgroup=mkdCodeEnd end=/^\s*\z1`*\s*$/' . s:concealcode +execute 'syn region mkdCode start=/^\s*\z(\~\{3,}\)\s*[0-9A-Za-z_+-]*\s*$/ end=/^\s*\z1\~*\s*$/ keepend contains=mkdCodeStart,mkdCodeEnd' . s:concealcode +execute 'syn match mkdCodeStart /\(\_^\n\_^\(>\s\)\?\([ ]\{4,}\|\t\)\=\)\@<=\(\~\{3,}\~*\|`\{3,}`*\)/ nextgroup=mkdCodeLang contained' . s:ConcealChar('codelang') +execute 'syn match mkdCodeEnd /\(`\{3,}`*\|\~\{3,}\~*\)\(\_$\n\(>\s\)\?\_$\)\@=/ contained' . s:ConcealChar('codeend') +syn match mkdCodeLang /\(\s\?\)\@<=.\+\(\_$\)\@=/ contained syn region mkdFootnote start="\[^" end="\]" syn match mkdCode /^\s*\n\(\(\s\{8,}[^ ]\|\t\t\+[^\t]\).*\n\)\+/ syn match mkdCode /\%^\(\(\s\{4,}[^ ]\|\t\+[^\t]\).*\n\)\+/ @@ -155,14 +226,18 @@ if get(g:, 'vim_markdown_strikethrough', 0) HtmlHiLink mkdStrike htmlStrike endif -syn cluster mkdNonListItem contains=@htmlTop,htmlItalic,htmlBold,htmlBoldItalic,mkdFootnotes,mkdInlineURL,mkdLink,mkdLinkDef,mkdLineBreak,mkdBlockquote,mkdCode,mkdRule,htmlH1,htmlH2,htmlH3,htmlH4,htmlH5,htmlH6,mkdMath,mkdStrike +syn cluster mkdNonListItem contains=htmlItalic,htmlBold,htmlBoldItalic,mkdComment,mkdFootnotes,mkdInlineURL,mkdLink,mkdLinkDef,mkdLineBreak,mkdBlockquote,mkdCode,mkdRule,htmlH1,htmlH2,htmlH3,htmlH4,htmlH5,htmlH6,mkdMath,mkdStrike "highlighting for Markdown groups HtmlHiLink mkdString String +HtmlHiLink mkdComment Comment +HtmlHiLink mkdCommentStart Comment +HtmlHiLink mkdCommentEnd Comment HtmlHiLink mkdCode String HtmlHiLink mkdCodeDelimiter String HtmlHiLink mkdCodeStart String HtmlHiLink mkdCodeEnd String +HtmlHiLink mkdCodeLang Comment HtmlHiLink mkdFootnote Comment HtmlHiLink mkdBlockquote Comment HtmlHiLink mkdListItem Identifier @@ -177,6 +252,7 @@ HtmlHiLink mkdLinkDef mkdID HtmlHiLink mkdLinkDefTarget mkdURL HtmlHiLink mkdLinkTitle htmlString HtmlHiLink mkdDelimiter Delimiter +HtmlHiLink mkdAtx Statement let b:current_syntax = "mkd" diff --git a/test/indent-toc.vader b/test/indent-toc.vader new file mode 100644 index 00000000..b8d669bc --- /dev/null +++ b/test/indent-toc.vader @@ -0,0 +1,147 @@ +Given markdown; +# a + +## Foo Level 2 + +### Foo Level 3 + +#### Foo Level 4 + +Bar Level 2 +----------- + +### Bar Level 3 + +Execute (InsertToc format): + :2 + :call append('.', '') + :InsertToc + +Expect (format): + # a + + * [Foo Level 2](#foo-level-2) + * [Foo Level 3](#foo-level-3) + * [Foo Level 4](#foo-level-4) + * [Bar Level 2](#bar-level-2) + * [Bar Level 3](#bar-level-3) + + ## Foo Level 2 + + ### Foo Level 3 + + #### Foo Level 4 + + Bar Level 2 + ----------- + + ### Bar Level 3 + +Given markdown; +# a + +## Foo Level 2 + +### Foo Level 3 + +#### Foo Level 4 + +Bar Level 2 +----------- + +### Bar Level 3 + +Execute (InsertToc only h2 headers): + :2 + :call append('.', '') + :InsertToc 2 + +Expect (only h2 headers): + # a + + * [Foo Level 2](#foo-level-2) + * [Bar Level 2](#bar-level-2) + + ## Foo Level 2 + + ### Foo Level 3 + + #### Foo Level 4 + + Bar Level 2 + ----------- + + ### Bar Level 3 + +Given markdown; +# a + +## Foo Level 2 + +### Foo Level 3 + +#### Foo Level 4 + +Bar Level 2 +----------- + +## Baz Level 2 + +## Foobar Level 2 + +## Foobaz Level 2 + +## Barfoo Level 2 + +## Barbaz Level 2 + +## Bazfoo Level 2 + +## Bazbar Level 2 + +## Foobarbaz Level 2 + +Execute (InsertNToc format, and up to h3 headers): + :2 + :call append('.', '') + :InsertNToc 3 + +Expect (format, and up to h3 headers): + # a + + 1. [Foo Level 2](#foo-level-2) + * [Foo Level 3](#foo-level-3) + 2. [Bar Level 2](#bar-level-2) + 3. [Baz Level 2](#baz-level-2) + 4. [Foobar Level 2](#foobar-level-2) + 5. [Foobaz Level 2](#foobaz-level-2) + 6. [Barfoo Level 2](#barfoo-level-2) + 7. [Barbaz Level 2](#barbaz-level-2) + 8. [Bazfoo Level 2](#bazfoo-level-2) + 9. [Bazbar Level 2](#bazbar-level-2) + 10. [Foobarbaz Level 2](#foobarbaz-level-2) + + ## Foo Level 2 + + ### Foo Level 3 + + #### Foo Level 4 + + Bar Level 2 + ----------- + + ## Baz Level 2 + + ## Foobar Level 2 + + ## Foobaz Level 2 + + ## Barfoo Level 2 + + ## Barbaz Level 2 + + ## Bazfoo Level 2 + + ## Bazbar Level 2 + + ## Foobarbaz Level 2