rmd.vim (10899B)
1 " Language: Markdown with chunks of R, Python and other languages 2 " Maintainer: This runtime file is looking for a new maintainer. 3 " Former Maintainer: Jakson Alves de Aquino <jalvesaq@gmail.com> 4 " Former Repository: https://github.com/jalvesaq/R-Vim-runtime 5 " Last Change: 2023 Dec 24 07:21AM 6 " 2024 Feb 19 by Vim Project (announce adoption) 7 " 8 " For highlighting pandoc extensions to markdown like citations and TeX and 9 " many other advanced features like folding of markdown sections, it is 10 " recommended to install the vim-pandoc filetype plugin as well as the 11 " vim-pandoc-syntax filetype plugin from https://github.com/vim-pandoc. 12 13 14 if exists("b:current_syntax") 15 finish 16 endif 17 18 let s:cpo_save = &cpo 19 set cpo&vim 20 21 let g:rmd_include_latex = get(g:, 'rmd_include_latex', 1) 22 if g:rmd_include_latex == 0 || g:rmd_include_latex == 1 23 let b:rmd_has_LaTeX = v:false 24 elseif g:rmd_include_latex == 2 25 let b:rmd_has_LaTeX = v:true 26 endif 27 28 " Highlight the header of the chunks as R code 29 let g:rmd_syn_hl_chunk = get(g:, 'rmd_syn_hl_chunk', 0) 30 31 " Pandoc-syntax has more features, but it is slower. 32 " https://github.com/vim-pandoc/vim-pandoc-syntax 33 34 " Don't waste time loading syntax that will be discarded: 35 let s:save_pandoc_lngs = get(g:, 'pandoc#syntax#codeblocks#embeds#langs', []) 36 let g:pandoc#syntax#codeblocks#embeds#langs = [] 37 38 let g:rmd_dynamic_fenced_languages = get(g:, 'rmd_dynamic_fenced_languages', v:true) 39 40 " Step_1: Source pandoc.vim if it is installed: 41 runtime syntax/pandoc.vim 42 if exists("b:current_syntax") 43 if hlexists('pandocDelimitedCodeBlock') 44 syn clear pandocDelimitedCodeBlock 45 endif 46 47 if len(s:save_pandoc_lngs) > 0 && !exists('g:rmd_fenced_languages') 48 let g:rmd_fenced_languages = deepcopy(s:save_pandoc_lngs) 49 endif 50 51 " Recognize inline R code 52 syn region rmdrInline matchgroup=rmdInlineDelim start="`r " end="`" contains=@Rmdr containedin=pandocLaTeXRegion,yamlFlowString keepend 53 else 54 " Step_2: Source markdown.vim if pandoc.vim is not installed 55 56 " Configuration if not using pandoc syntax: 57 " Add syntax highlighting of YAML header 58 let g:rmd_syn_hl_yaml = get(g:, 'rmd_syn_hl_yaml', 1) 59 " Add syntax highlighting of citation keys 60 let g:rmd_syn_hl_citations = get(g:, 'rmd_syn_hl_citations', 1) 61 62 " R chunks will not be highlighted by syntax/markdown because their headers 63 " follow a non standard pattern: "```{lang" instead of "^```lang". 64 " Make a copy of g:markdown_fenced_languages to highlight the chunks later: 65 if exists('g:markdown_fenced_languages') && !exists('g:rmd_fenced_languages') 66 let g:rmd_fenced_languages = deepcopy(g:markdown_fenced_languages) 67 endif 68 69 if exists('g:markdown_fenced_languages') && len(g:markdown_fenced_languages) > 0 70 let s:save_mfl = deepcopy(g:markdown_fenced_languages) 71 endif 72 " Don't waste time loading syntax that will be discarded: 73 let g:markdown_fenced_languages = [] 74 runtime syntax/markdown.vim 75 if exists('s:save_mfl') > 0 76 let g:markdown_fenced_languages = deepcopy(s:save_mfl) 77 unlet s:save_mfl 78 endif 79 syn region rmdrInline matchgroup=rmdInlineDelim start="`r " end="`" contains=@Rmdr keepend 80 81 " Step_2a: Add highlighting for both YAML and citations which are pandoc 82 " specific, but also used in Rmd files 83 84 " You don't need this if either your markdown/syntax.vim already highlights 85 " the YAML header or you are writing standard markdown 86 if g:rmd_syn_hl_yaml 87 " Basic highlighting of YAML header 88 syn match rmdYamlFieldTtl /^\s*\zs\w\%(-\|\w\)*\ze:/ contained 89 syn match rmdYamlFieldTtl /^\s*-\s*\zs\w\%(-\|\w\)*\ze:/ contained 90 syn region yamlFlowString matchgroup=yamlFlowStringDelimiter start='"' skip='\\"' end='"' contains=yamlEscape,rmdrInline contained 91 syn region yamlFlowString matchgroup=yamlFlowStringDelimiter start="'" skip="''" end="'" contains=yamlSingleEscape,rmdrInline contained 92 syn match yamlEscape contained '\\\%([\\"abefnrtv\^0_ NLP\n]\|x\x\x\|u\x\{4}\|U\x\{8}\)' 93 syn match yamlSingleEscape contained "''" 94 syn match yamlComment /#.*/ contained 95 " A second colon is a syntax error, unless within a string or following !expr 96 syn match yamlColonError /:\s*[^'^"^!]*:/ contained 97 if &filetype == 'quarto' 98 syn region pandocYAMLHeader matchgroup=rmdYamlBlockDelim start=/\%(\%^\|\_^\s*\n\)\@<=\_^-\{3}\ze\n.\+/ end=/^---$/ keepend contains=rmdYamlFieldTtl,yamlFlowString,yamlComment,yamlColonError 99 else 100 syn region pandocYAMLHeader matchgroup=rmdYamlBlockDelim start=/\%(\%^\|\_^\s*\n\)\@<=\_^-\{3}\ze\n.\+/ end=/^\([-.]\)\1\{2}$/ keepend contains=rmdYamlFieldTtl,yamlFlowString,yamlComment,yamlColonError 101 endif 102 hi def link rmdYamlBlockDelim Delimiter 103 hi def link rmdYamlFieldTtl Identifier 104 hi def link yamlFlowString String 105 hi def link yamlComment Comment 106 hi def link yamlColonError Error 107 endif 108 109 " Conceal char for manual line break 110 if &encoding ==# 'utf-8' 111 syn match rmdNewLine ' $' conceal cchar=↵ 112 endif 113 114 " You don't need this if either your markdown/syntax.vim already highlights 115 " citations or you are writing standard markdown 116 if g:rmd_syn_hl_citations 117 " From vim-pandoc-syntax 118 " parenthetical citations 119 syn match pandocPCite /\^\@<!\[[^\[\]]\{-}-\{0,1}@[[:alnum:]_][[:alnum:]à-öø-ÿÀ-ÖØ-ß_:.#$%&\-+?<>~\/]*.\{-}\]/ contains=pandocEmphasis,pandocStrong,pandocLatex,pandocCiteKey,@Spell,pandocAmpersandEscape display 120 " in-text citations with location 121 syn match pandocICite /@[[:alnum:]_][[:alnum:]à-öø-ÿÀ-ÖØ-ß_:.#$%&\-+?<>~\/]*\s\[.\{-1,}\]/ contains=pandocCiteKey,@Spell display 122 " cite keys 123 syn match pandocCiteKey /\(-\=@[[:alnum:]_][[:alnum:]à-öø-ÿÀ-ÖØ-ß_:.#$%&\-+?<>~\/]*\)/ containedin=pandocPCite,pandocICite contains=@NoSpell display 124 syn match pandocCiteAnchor /[-@]/ contained containedin=pandocCiteKey display 125 syn match pandocCiteLocator /[\[\]]/ contained containedin=pandocPCite,pandocICite 126 hi def link pandocPCite Operator 127 hi def link pandocICite Operator 128 hi def link pandocCiteKey Label 129 hi def link pandocCiteAnchor Operator 130 hi def link pandocCiteLocator Operator 131 endif 132 endif 133 134 " Step_3: Highlight code blocks. 135 136 syn region rmdCodeBlock matchgroup=rmdCodeDelim start="^\s*```\s*{.*}$" matchgroup=rmdCodeDelim end="^\s*```\ze\s*$" keepend 137 syn region rmdCodeBlock matchgroup=rmdCodeDelim start="^\s*```.+$" matchgroup=rmdCodeDelim end="^```$" keepend 138 hi link rmdCodeBlock Special 139 140 " Now highlight chunks: 141 syn region knitrBodyOptions start='^#| ' end='$' contained containedin=rComment,pythonComment contains=knitrBodyVar,knitrBodyValue transparent 142 syn match knitrBodyValue ': \zs.*\ze$' keepend contained containedin=knitrBodyOptions 143 syn match knitrBodyVar '| \zs\S\{-}\ze:' contained containedin=knitrBodyOptions 144 145 let g:rmd_fenced_languages = get(g:, 'rmd_fenced_languages', ['r']) 146 147 let s:no_syntax_vim = [] 148 function s:IncludeLanguage(lng) 149 if a:lng =~ '=' 150 let ftpy = substitute(a:lng, '.*=', '', '') 151 let lnm = substitute(a:lng, '=.*', '', '') 152 else 153 let ftpy = a:lng 154 let lnm = a:lng 155 endif 156 if index(s:no_syntax_vim, ftpy) >= 0 157 return 158 endif 159 if len(globpath(&rtp, "syntax/" . ftpy . ".vim")) 160 unlet! b:current_syntax 161 exe 'syn include @Rmd'.lnm.' syntax/'.ftpy.'.vim' 162 let b:current_syntax = "rmd" 163 if g:rmd_syn_hl_chunk 164 exe 'syn match knitrChunkDelim /```\s*{\s*'.lnm.'/ contained containedin=knitrChunkBrace contains=knitrChunkLabel' 165 exe 'syn match knitrChunkLabelDelim /```\s*{\s*'.lnm.',\=\s*[-[:alnum:]]\{-1,}[,}]/ contained containedin=knitrChunkBrace' 166 syn match knitrChunkDelim /}\s*$/ contained containedin=knitrChunkBrace 167 exe 'syn match knitrChunkBrace /```\s*{\s*'.lnm.'.*$/ contained containedin=rmd'.lnm.'Chunk contains=knitrChunkDelim,knitrChunkLabelDelim,@Rmd'.lnm 168 exe 'syn region rmd'.lnm.'Chunk start="^\s*```\s*{\s*=\?'.lnm.'\>.*$" matchgroup=rmdCodeDelim end="^\s*```\ze\s*$" keepend contains=knitrChunkBrace,@Rmd'.lnm 169 170 hi link knitrChunkLabel Identifier 171 hi link knitrChunkDelim rmdCodeDelim 172 hi link knitrChunkLabelDelim rmdCodeDelim 173 else 174 exe 'syn region rmd'.lnm.'Chunk matchgroup=rmdCodeDelim start="^\s*```\s*{\s*=\?'.lnm.'\>.*$" matchgroup=rmdCodeDelim end="^\s*```\ze\s*$" keepend contains=@Rmd'.lnm 175 endif 176 else 177 " Avoid the cost of running globpath() whenever the buffer is saved 178 let s:no_syntax_vim += [ftpy] 179 endif 180 endfunction 181 182 for s:type in g:rmd_fenced_languages 183 call s:IncludeLanguage(s:type) 184 endfor 185 unlet! s:type 186 187 let s:LaTeX_included = v:false 188 function s:IncludeLaTeX() 189 let s:LaTeX_included = v:true 190 unlet! b:current_syntax 191 syn include @RmdLaTeX syntax/tex.vim 192 " From vim-pandoc-syntax 193 syn region rmdLaTeXInlineMath start=/\v\\@<!\$\S@=/ end=/\v\\@<!\$\d@!/ keepend contains=@RmdLaTeX 194 syn match rmdLaTeXCmd /\\[[:alpha:]]\+\(\({.\{-}}\)\=\(\[.\{-}\]\)\=\)*/ contains=@RmdLaTeX 195 syn region rmdLaTeX start='\$\$' end='\$\$' keepend contains=@RmdLaTeX 196 syn region rmdLaTeX start=/\\begin{\z(.\{-}\)}/ end=/\\end{\z1}/ keepend contains=@RmdLaTeX 197 endfunction 198 199 function s:CheckRmdFencedLanguages() 200 let alines = getline(1, '$') 201 call filter(alines, "v:val =~ '^```{'") 202 call map(alines, "substitute(v:val, '^```{', '', '')") 203 call map(alines, "substitute(v:val, '\\W.*', '', '')") 204 for tpy in alines 205 if len(tpy) == 0 206 continue 207 endif 208 let has_lng = 0 209 for lng in g:rmd_fenced_languages 210 if tpy == lng 211 let has_lng = 1 212 continue 213 endif 214 endfor 215 if has_lng == 0 216 let g:rmd_fenced_languages += [tpy] 217 call s:IncludeLanguage(tpy) 218 endif 219 endfor 220 221 if hlexists('pandocLaTeXCommand') 222 return 223 endif 224 if g:rmd_include_latex 225 if !b:rmd_has_LaTeX && (search('\$\$', 'wn') > 0 || 226 \ search('\\begin{', 'wn') > 0) || 227 \ search('\\[[:alpha:]]\+', 'wn') || 228 \ search('\$[^\$]\+\$', 'wn') 229 let b:rmd_has_LaTeX = v:true 230 endif 231 if b:rmd_has_LaTeX && !s:LaTeX_included 232 call s:IncludeLaTeX() 233 endif 234 endif 235 endfunction 236 237 if g:rmd_dynamic_fenced_languages 238 call s:CheckRmdFencedLanguages() 239 augroup RmdSyntax 240 autocmd! 241 autocmd BufWritePost <buffer> call s:CheckRmdFencedLanguages() 242 augroup END 243 endif 244 245 " Step_4: Highlight code recognized by pandoc but not defined in pandoc.vim yet: 246 syn match pandocDivBegin '^:::\+ {.\{-}}' contains=pandocHeaderAttr 247 syn match pandocDivEnd '^:::\+$' 248 249 hi def link knitrBodyVar PreProc 250 hi def link knitrBodyValue Constant 251 hi def link knitrBodyOptions rComment 252 hi def link pandocDivBegin Delimiter 253 hi def link pandocDivEnd Delimiter 254 hi def link rmdInlineDelim Delimiter 255 hi def link rmdCodeDelim Delimiter 256 257 if len(s:save_pandoc_lngs) 258 let g:pandoc#syntax#codeblocks#embeds#langs = s:save_pandoc_lngs 259 endif 260 unlet s:save_pandoc_lngs 261 let &cpo = s:cpo_save 262 unlet s:cpo_save 263 264 syntax iskeyword clear 265 266 let b:current_syntax = "rmd" 267 268 " vim: ts=8 sw=2