neovim

Neovim text editor
git clone https://git.dasho.dev/neovim.git
Log | Files | Refs | README

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