blob: 4b4db1e783c3205c1e3901518a3f252feef7ffb0 [file] [log] [blame]
Bram Moolenaardd60c362023-02-27 15:49:53 +00001" Language: Markdown with chunks of R, Python and other languages
Christian Brabandtf9ca1392024-02-19 20:37:11 +01002" 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 Moolenaarcd5c8f82017-04-09 20:11:58 +02007"
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 Moolenaarfc65cab2018-08-28 22:58:02 +020012
Bram Moolenaardb6ea062014-07-10 22:01:47 +020013
Bram Moolenaar77cdfd12016-03-12 12:57:59 +010014if exists("b:current_syntax")
Bram Moolenaardb6ea062014-07-10 22:01:47 +020015 finish
16endif
17
Bram Moolenaardd60c362023-02-27 15:49:53 +000018let s:cpo_save = &cpo
19set cpo&vim
20
Jakson Alves de Aquino9042bd82023-12-25 09:22:27 +000021let g:rmd_include_latex = get(g:, 'rmd_include_latex', 1)
22if g:rmd_include_latex == 0 || g:rmd_include_latex == 1
23 let b:rmd_has_LaTeX = v:false
24elseif g:rmd_include_latex == 2
25 let b:rmd_has_LaTeX = v:true
26endif
27
Bram Moolenaar11e3c5b2021-04-21 18:09:37 +020028" Highlight the header of the chunks as R code
29let g:rmd_syn_hl_chunk = get(g:, 'rmd_syn_hl_chunk', 0)
Bram Moolenaarfc65cab2018-08-28 22:58:02 +020030
31" Pandoc-syntax has more features, but it is slower.
Bram Moolenaarcd5c8f82017-04-09 20:11:58 +020032" https://github.com/vim-pandoc/vim-pandoc-syntax
Bram Moolenaardd60c362023-02-27 15:49:53 +000033
34" Don't waste time loading syntax that will be discarded:
35let s:save_pandoc_lngs = get(g:, 'pandoc#syntax#codeblocks#embeds#langs', [])
36let g:pandoc#syntax#codeblocks#embeds#langs = []
37
Jakson Alves de Aquino34745942023-09-27 13:56:02 -030038let g:rmd_dynamic_fenced_languages = get(g:, 'rmd_dynamic_fenced_languages', v:true)
39
Bram Moolenaardd60c362023-02-27 15:49:53 +000040" Step_1: Source pandoc.vim if it is installed:
Bram Moolenaardb6ea062014-07-10 22:01:47 +020041runtime syntax/pandoc.vim
42if exists("b:current_syntax")
Bram Moolenaardd60c362023-02-27 15:49:53 +000043 if hlexists('pandocDelimitedCodeBlock')
44 syn clear pandocDelimitedCodeBlock
Bram Moolenaarcd5c8f82017-04-09 20:11:58 +020045 endif
Bram Moolenaardd60c362023-02-27 15:49:53 +000046
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 Moolenaarfc65cab2018-08-28 22:58:02 +020053else
Bram Moolenaardd60c362023-02-27 15:49:53 +000054 " 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épe3fc7a7e2023-08-23 21:20:00 +020095 " A second colon is a syntax error, unless within a string or following !expr
Bram Moolenaardd60c362023-02-27 15:49:53 +000096 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 Aquino34745942023-09-27 13:56:02 -0300109 " Conceal char for manual line break
110 if &encoding ==# 'utf-8'
111 syn match rmdNewLine ' $' conceal cchar=↵
112 endif
113
Bram Moolenaardd60c362023-02-27 15:49:53 +0000114 " 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 Moolenaardb6ea062014-07-10 22:01:47 +0200132endif
Bram Moolenaarcd5c8f82017-04-09 20:11:58 +0200133
Bram Moolenaardd60c362023-02-27 15:49:53 +0000134" Step_3: Highlight code blocks.
135
136syn region rmdCodeBlock matchgroup=rmdCodeDelim start="^\s*```\s*{.*}$" matchgroup=rmdCodeDelim end="^\s*```\ze\s*$" keepend
137syn region rmdCodeBlock matchgroup=rmdCodeDelim start="^\s*```.+$" matchgroup=rmdCodeDelim end="^```$" keepend
138hi link rmdCodeBlock Special
Bram Moolenaarcd5c8f82017-04-09 20:11:58 +0200139
Bram Moolenaarfc65cab2018-08-28 22:58:02 +0200140" Now highlight chunks:
Bram Moolenaardd60c362023-02-27 15:49:53 +0000141syn region knitrBodyOptions start='^#| ' end='$' contained containedin=rComment,pythonComment contains=knitrBodyVar,knitrBodyValue transparent
142syn match knitrBodyValue ': \zs.*\ze$' keepend contained containedin=knitrBodyOptions
143syn match knitrBodyVar '| \zs\S\{-}\ze:' contained containedin=knitrBodyOptions
144
145let g:rmd_fenced_languages = get(g:, 'rmd_fenced_languages', ['r'])
Bram Moolenaardd60c362023-02-27 15:49:53 +0000146
Jakson Alves de Aquino34745942023-09-27 13:56:02 -0300147let s:no_syntax_vim = []
Jakson Alves de Aquino9042bd82023-12-25 09:22:27 +0000148function s:IncludeLanguage(lng)
Jakson Alves de Aquino34745942023-09-27 13:56:02 -0300149 if a:lng =~ '='
150 let ftpy = substitute(a:lng, '.*=', '', '')
151 let lnm = substitute(a:lng, '=.*', '', '')
Bram Moolenaarfc65cab2018-08-28 22:58:02 +0200152 else
Jakson Alves de Aquino34745942023-09-27 13:56:02 -0300153 let ftpy = a:lng
154 let lnm = a:lng
Bram Moolenaarfc65cab2018-08-28 22:58:02 +0200155 endif
Jakson Alves de Aquino34745942023-09-27 13:56:02 -0300156 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
180endfunction
181
182for s:type in g:rmd_fenced_languages
Jakson Alves de Aquino9042bd82023-12-25 09:22:27 +0000183 call s:IncludeLanguage(s:type)
Bram Moolenaarcd5c8f82017-04-09 20:11:58 +0200184endfor
Bram Moolenaarfc65cab2018-08-28 22:58:02 +0200185unlet! s:type
Bram Moolenaarcd5c8f82017-04-09 20:11:58 +0200186
Jakson Alves de Aquino9042bd82023-12-25 09:22:27 +0000187let s:LaTeX_included = v:false
188function 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
197endfunction
198
199function s:CheckRmdFencedLanguages()
Jakson Alves de Aquino34745942023-09-27 13:56:02 -0300200 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 Aquino9042bd82023-12-25 09:22:27 +0000217 call s:IncludeLanguage(tpy)
Jakson Alves de Aquino34745942023-09-27 13:56:02 -0300218 endif
219 endfor
Jakson Alves de Aquino9042bd82023-12-25 09:22:27 +0000220
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 Aquino34745942023-09-27 13:56:02 -0300235endfunction
236
237if g:rmd_dynamic_fenced_languages
Jakson Alves de Aquino9042bd82023-12-25 09:22:27 +0000238 call s:CheckRmdFencedLanguages()
Jakson Alves de Aquino34745942023-09-27 13:56:02 -0300239 augroup RmdSyntax
240 autocmd!
Jakson Alves de Aquino9042bd82023-12-25 09:22:27 +0000241 autocmd BufWritePost <buffer> call s:CheckRmdFencedLanguages()
Jakson Alves de Aquino34745942023-09-27 13:56:02 -0300242 augroup END
243endif
244
Bram Moolenaardd60c362023-02-27 15:49:53 +0000245" Step_4: Highlight code recognized by pandoc but not defined in pandoc.vim yet:
246syn match pandocDivBegin '^:::\+ {.\{-}}' contains=pandocHeaderAttr
247syn match pandocDivEnd '^:::\+$'
Bram Moolenaar11e3c5b2021-04-21 18:09:37 +0200248
Bram Moolenaardd60c362023-02-27 15:49:53 +0000249hi def link knitrBodyVar PreProc
250hi def link knitrBodyValue Constant
251hi def link knitrBodyOptions rComment
252hi def link pandocDivBegin Delimiter
253hi def link pandocDivEnd Delimiter
Bram Moolenaarfc65cab2018-08-28 22:58:02 +0200254hi def link rmdInlineDelim Delimiter
255hi def link rmdCodeDelim Delimiter
Bram Moolenaardb6ea062014-07-10 22:01:47 +0200256
Bram Moolenaardd60c362023-02-27 15:49:53 +0000257if len(s:save_pandoc_lngs)
258 let g:pandoc#syntax#codeblocks#embeds#langs = s:save_pandoc_lngs
Bram Moolenaardb6ea062014-07-10 22:01:47 +0200259endif
Bram Moolenaardd60c362023-02-27 15:49:53 +0000260unlet s:save_pandoc_lngs
Bram Moolenaarfc65cab2018-08-28 22:58:02 +0200261let &cpo = s:cpo_save
262unlet s:cpo_save
263
Jakson Alves de Aquino9042bd82023-12-25 09:22:27 +0000264syntax iskeyword clear
265
Bram Moolenaardd60c362023-02-27 15:49:53 +0000266let b:current_syntax = "rmd"
267
Bram Moolenaardb6ea062014-07-10 22:01:47 +0200268" vim: ts=8 sw=2