Bram Moolenaar | dd60c36 | 2023-02-27 15:49:53 +0000 | [diff] [blame] | 1 | " Language: Markdown with chunks of R, Python and other languages |
Christian Brabandt | f9ca139 | 2024-02-19 20:37:11 +0100 | [diff] [blame] | 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) |
Bram Moolenaar | cd5c8f8 | 2017-04-09 20:11:58 +0200 | [diff] [blame] | 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. |
Bram Moolenaar | fc65cab | 2018-08-28 22:58:02 +0200 | [diff] [blame] | 12 | |
Bram Moolenaar | db6ea06 | 2014-07-10 22:01:47 +0200 | [diff] [blame] | 13 | |
Bram Moolenaar | 77cdfd1 | 2016-03-12 12:57:59 +0100 | [diff] [blame] | 14 | if exists("b:current_syntax") |
Bram Moolenaar | db6ea06 | 2014-07-10 22:01:47 +0200 | [diff] [blame] | 15 | finish |
| 16 | endif |
| 17 | |
Bram Moolenaar | dd60c36 | 2023-02-27 15:49:53 +0000 | [diff] [blame] | 18 | let s:cpo_save = &cpo |
| 19 | set cpo&vim |
| 20 | |
Jakson Alves de Aquino | 9042bd8 | 2023-12-25 09:22:27 +0000 | [diff] [blame] | 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 | |
Bram Moolenaar | 11e3c5b | 2021-04-21 18:09:37 +0200 | [diff] [blame] | 28 | " Highlight the header of the chunks as R code |
| 29 | let g:rmd_syn_hl_chunk = get(g:, 'rmd_syn_hl_chunk', 0) |
Bram Moolenaar | fc65cab | 2018-08-28 22:58:02 +0200 | [diff] [blame] | 30 | |
| 31 | " Pandoc-syntax has more features, but it is slower. |
Bram Moolenaar | cd5c8f8 | 2017-04-09 20:11:58 +0200 | [diff] [blame] | 32 | " https://github.com/vim-pandoc/vim-pandoc-syntax |
Bram Moolenaar | dd60c36 | 2023-02-27 15:49:53 +0000 | [diff] [blame] | 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 | |
Jakson Alves de Aquino | 3474594 | 2023-09-27 13:56:02 -0300 | [diff] [blame] | 38 | let g:rmd_dynamic_fenced_languages = get(g:, 'rmd_dynamic_fenced_languages', v:true) |
| 39 | |
Bram Moolenaar | dd60c36 | 2023-02-27 15:49:53 +0000 | [diff] [blame] | 40 | " Step_1: Source pandoc.vim if it is installed: |
Bram Moolenaar | db6ea06 | 2014-07-10 22:01:47 +0200 | [diff] [blame] | 41 | runtime syntax/pandoc.vim |
| 42 | if exists("b:current_syntax") |
Bram Moolenaar | dd60c36 | 2023-02-27 15:49:53 +0000 | [diff] [blame] | 43 | if hlexists('pandocDelimitedCodeBlock') |
| 44 | syn clear pandocDelimitedCodeBlock |
Bram Moolenaar | cd5c8f8 | 2017-04-09 20:11:58 +0200 | [diff] [blame] | 45 | endif |
Bram Moolenaar | dd60c36 | 2023-02-27 15:49:53 +0000 | [diff] [blame] | 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 |
Bram Moolenaar | fc65cab | 2018-08-28 22:58:02 +0200 | [diff] [blame] | 53 | else |
Bram Moolenaar | dd60c36 | 2023-02-27 15:49:53 +0000 | [diff] [blame] | 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 |
Viktor Szépe | 3fc7a7e | 2023-08-23 21:20:00 +0200 | [diff] [blame] | 95 | " A second colon is a syntax error, unless within a string or following !expr |
Bram Moolenaar | dd60c36 | 2023-02-27 15:49:53 +0000 | [diff] [blame] | 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 | |
Jakson Alves de Aquino | 3474594 | 2023-09-27 13:56:02 -0300 | [diff] [blame] | 109 | " Conceal char for manual line break |
| 110 | if &encoding ==# 'utf-8' |
| 111 | syn match rmdNewLine ' $' conceal cchar=↵ |
| 112 | endif |
| 113 | |
Bram Moolenaar | dd60c36 | 2023-02-27 15:49:53 +0000 | [diff] [blame] | 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 |
Bram Moolenaar | db6ea06 | 2014-07-10 22:01:47 +0200 | [diff] [blame] | 132 | endif |
Bram Moolenaar | cd5c8f8 | 2017-04-09 20:11:58 +0200 | [diff] [blame] | 133 | |
Bram Moolenaar | dd60c36 | 2023-02-27 15:49:53 +0000 | [diff] [blame] | 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 |
Bram Moolenaar | cd5c8f8 | 2017-04-09 20:11:58 +0200 | [diff] [blame] | 139 | |
Bram Moolenaar | fc65cab | 2018-08-28 22:58:02 +0200 | [diff] [blame] | 140 | " Now highlight chunks: |
Bram Moolenaar | dd60c36 | 2023-02-27 15:49:53 +0000 | [diff] [blame] | 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']) |
Bram Moolenaar | dd60c36 | 2023-02-27 15:49:53 +0000 | [diff] [blame] | 146 | |
Jakson Alves de Aquino | 3474594 | 2023-09-27 13:56:02 -0300 | [diff] [blame] | 147 | let s:no_syntax_vim = [] |
Jakson Alves de Aquino | 9042bd8 | 2023-12-25 09:22:27 +0000 | [diff] [blame] | 148 | function s:IncludeLanguage(lng) |
Jakson Alves de Aquino | 3474594 | 2023-09-27 13:56:02 -0300 | [diff] [blame] | 149 | if a:lng =~ '=' |
| 150 | let ftpy = substitute(a:lng, '.*=', '', '') |
| 151 | let lnm = substitute(a:lng, '=.*', '', '') |
Bram Moolenaar | fc65cab | 2018-08-28 22:58:02 +0200 | [diff] [blame] | 152 | else |
Jakson Alves de Aquino | 3474594 | 2023-09-27 13:56:02 -0300 | [diff] [blame] | 153 | let ftpy = a:lng |
| 154 | let lnm = a:lng |
Bram Moolenaar | fc65cab | 2018-08-28 22:58:02 +0200 | [diff] [blame] | 155 | endif |
Jakson Alves de Aquino | 3474594 | 2023-09-27 13:56:02 -0300 | [diff] [blame] | 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 |
Jakson Alves de Aquino | 9042bd8 | 2023-12-25 09:22:27 +0000 | [diff] [blame] | 183 | call s:IncludeLanguage(s:type) |
Bram Moolenaar | cd5c8f8 | 2017-04-09 20:11:58 +0200 | [diff] [blame] | 184 | endfor |
Bram Moolenaar | fc65cab | 2018-08-28 22:58:02 +0200 | [diff] [blame] | 185 | unlet! s:type |
Bram Moolenaar | cd5c8f8 | 2017-04-09 20:11:58 +0200 | [diff] [blame] | 186 | |
Jakson Alves de Aquino | 9042bd8 | 2023-12-25 09:22:27 +0000 | [diff] [blame] | 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() |
Jakson Alves de Aquino | 3474594 | 2023-09-27 13:56:02 -0300 | [diff] [blame] | 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] |
Jakson Alves de Aquino | 9042bd8 | 2023-12-25 09:22:27 +0000 | [diff] [blame] | 217 | call s:IncludeLanguage(tpy) |
Jakson Alves de Aquino | 3474594 | 2023-09-27 13:56:02 -0300 | [diff] [blame] | 218 | endif |
| 219 | endfor |
Jakson Alves de Aquino | 9042bd8 | 2023-12-25 09:22:27 +0000 | [diff] [blame] | 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 |
Jakson Alves de Aquino | 3474594 | 2023-09-27 13:56:02 -0300 | [diff] [blame] | 235 | endfunction |
| 236 | |
| 237 | if g:rmd_dynamic_fenced_languages |
Jakson Alves de Aquino | 9042bd8 | 2023-12-25 09:22:27 +0000 | [diff] [blame] | 238 | call s:CheckRmdFencedLanguages() |
Jakson Alves de Aquino | 3474594 | 2023-09-27 13:56:02 -0300 | [diff] [blame] | 239 | augroup RmdSyntax |
| 240 | autocmd! |
Jakson Alves de Aquino | 9042bd8 | 2023-12-25 09:22:27 +0000 | [diff] [blame] | 241 | autocmd BufWritePost <buffer> call s:CheckRmdFencedLanguages() |
Jakson Alves de Aquino | 3474594 | 2023-09-27 13:56:02 -0300 | [diff] [blame] | 242 | augroup END |
| 243 | endif |
| 244 | |
Bram Moolenaar | dd60c36 | 2023-02-27 15:49:53 +0000 | [diff] [blame] | 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 '^:::\+$' |
Bram Moolenaar | 11e3c5b | 2021-04-21 18:09:37 +0200 | [diff] [blame] | 248 | |
Bram Moolenaar | dd60c36 | 2023-02-27 15:49:53 +0000 | [diff] [blame] | 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 |
Bram Moolenaar | fc65cab | 2018-08-28 22:58:02 +0200 | [diff] [blame] | 254 | hi def link rmdInlineDelim Delimiter |
| 255 | hi def link rmdCodeDelim Delimiter |
Bram Moolenaar | db6ea06 | 2014-07-10 22:01:47 +0200 | [diff] [blame] | 256 | |
Bram Moolenaar | dd60c36 | 2023-02-27 15:49:53 +0000 | [diff] [blame] | 257 | if len(s:save_pandoc_lngs) |
| 258 | let g:pandoc#syntax#codeblocks#embeds#langs = s:save_pandoc_lngs |
Bram Moolenaar | db6ea06 | 2014-07-10 22:01:47 +0200 | [diff] [blame] | 259 | endif |
Bram Moolenaar | dd60c36 | 2023-02-27 15:49:53 +0000 | [diff] [blame] | 260 | unlet s:save_pandoc_lngs |
Bram Moolenaar | fc65cab | 2018-08-28 22:58:02 +0200 | [diff] [blame] | 261 | let &cpo = s:cpo_save |
| 262 | unlet s:cpo_save |
| 263 | |
Jakson Alves de Aquino | 9042bd8 | 2023-12-25 09:22:27 +0000 | [diff] [blame] | 264 | syntax iskeyword clear |
| 265 | |
Bram Moolenaar | dd60c36 | 2023-02-27 15:49:53 +0000 | [diff] [blame] | 266 | let b:current_syntax = "rmd" |
| 267 | |
Bram Moolenaar | db6ea06 | 2014-07-10 22:01:47 +0200 | [diff] [blame] | 268 | " vim: ts=8 sw=2 |