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