diff options
Diffstat (limited to 'autoload/vimtex/syntax/p/minted.vim')
-rw-r--r-- | autoload/vimtex/syntax/p/minted.vim | 256 |
1 files changed, 256 insertions, 0 deletions
diff --git a/autoload/vimtex/syntax/p/minted.vim b/autoload/vimtex/syntax/p/minted.vim new file mode 100644 index 00000000..02793c34 --- /dev/null +++ b/autoload/vimtex/syntax/p/minted.vim @@ -0,0 +1,256 @@ +if !exists('g:polyglot_disabled') || index(g:polyglot_disabled, 'latex') == -1 + +" vimtex - LaTeX plugin for Vim +" +" Maintainer: Karl Yngve LervÄg +" Email: karl.yngve@gmail.com +" + +function! vimtex#syntax#p#minted#load() abort " {{{1 + if has_key(b:vimtex_syntax, 'minted') | return | endif + let b:vimtex_syntax.minted = 1 + + " Parse minted macros in the current project + call s:parse_minted_constructs() + + " Match minted language names + syntax region texMintedName matchgroup=Delimiter start="{" end="}" contained + syntax region texMintedNameOpt matchgroup=Delimiter start="\[" end="\]" contained + + " Match boundaries of minted environments + syntax match texMintedBounds '\\end{minted}' + \ contained + \ contains=texBeginEnd + syntax match texMintedBounds '\\begin{minted}' + \ contained + \ contains=texBeginEnd + \ nextgroup=texMintedBoundsOpts,texMintedName + syntax region texMintedBoundsOpts matchgroup=Delimiter + \ start="\[" end="\]" + \ contained + \ nextgroup=texMintedName + + " Match starred custom minted environments with options + syntax match texMintedStarred "\\begin{\w\+\*}" + \ contained + \ contains=texBeginEnd + \ nextgroup=texMintedStarredOpts + syntax region texMintedStarredOpts matchgroup=Delimiter + \ start='{' + \ end='}' + \ contained + \ containedin=texMintedStarred + + " Match \newminted type macros + syntax match texStatement '\\newmint\%(ed\|inline\)\?' nextgroup=texMintedName,texMintedNameOpt + + " Match "unknown" environments + call vimtex#syntax#misc#add_to_section_clusters('texZoneMinted') + syntax region texZoneMinted + \ start="\\begin{minted}\%(\_s*\[\_[^\]]\{-}\]\)\?\_s*{\w\+}"rs=s + \ end="\\end{minted}"re=e + \ keepend + \ contains=texMintedBounds.* + + " Match "unknown" commands + syntax match texArgMinted "{\w\+}" + \ contained + \ contains=texMintedName + \ nextgroup=texZoneMintedCmd + syntax region texZoneMintedCmd matchgroup=Delimiter + \ start='\z([|+/]\)' + \ end='\z1' + \ contained + syntax region texZoneMintedCmd matchgroup=Delimiter + \ start='{' + \ end='}' + \ contained + + " Next add nested syntax support for desired languages + for [l:nested, l:config] in items(b:vimtex.syntax.minted) + let l:cluster = vimtex#syntax#misc#include(l:nested) + + let l:name = 'Minted' . toupper(l:nested[0]) . l:nested[1:] + let l:group_main = 'texZone' . l:name + let l:group_arg = 'texArg' . l:name + let l:group_arg_zone = 'texArgZone' . l:name + call vimtex#syntax#misc#add_to_section_clusters(l:group_main) + + if empty(l:cluster) + let l:transparent = '' + let l:contains_env = '' + let l:contains_macro = '' + execute 'highlight link' l:group_main 'texZoneMinted' + execute 'highlight link' l:group_arg_zone 'texZoneMinted' + else + let l:transparent = 'transparent' + let l:contains_env = ',@' . l:cluster + let l:contains_macro = 'contains=@' . l:cluster + endif + + " Match minted environment + execute 'syntax region' l:group_main + \ 'start="\\begin{minted}\%(\_s*\[\_[^\]]\{-}\]\)\?\_s*{' . l:nested . '}"rs=s' + \ 'end="\\end{minted}"re=e' + \ 'keepend' + \ l:transparent + \ 'contains=texMintedBounds.*' . l:contains_env + + " Match custom environment names + for l:env in get(l:config, 'environments', []) + execute 'syntax region' l:group_main + \ 'start="\\begin{\z(' . l:env . '\*\?\)}"rs=s' + \ 'end="\\end{\z1}"re=e' + \ 'keepend' + \ l:transparent + \ 'contains=texMintedStarred,texBeginEnd' . l:contains_env + endfor + + " Match minted macros + " - \mint[]{lang}|...| + " - \mint[]{lang}{...} + " - \mintinline[]{lang}|...| + " - \mintinline[]{lang}{...} + execute 'syntax match' l:group_arg '''{' . l:nested . '}''' + \ 'contained' + \ 'contains=texMintedName' + \ 'nextgroup=' . l:group_arg_zone + execute 'syntax region' l:group_arg_zone + \ 'matchgroup=Delimiter' + \ 'start=''\z([|+/]\)''' + \ 'end=''\z1''' + \ 'contained' + \ l:contains_macro + execute 'syntax region' l:group_arg_zone + \ 'matchgroup=Delimiter' + \ 'start=''{''' + \ 'end=''}''' + \ 'contained' + \ l:contains_macro + + " Match minted custom macros + for l:cmd in sort(get(l:config, 'commands', [])) + execute printf('syntax match texStatement ''\\%s'' nextgroup=%s', + \ l:cmd, l:group_arg_zone) + endfor + endfor + + " Main matcher for the minted statements/commands + " - Note: This comes last to allow the nextgroup pattern + syntax match texStatement '\\mint\(inline\)\?' nextgroup=texArgOptMinted,texArgMinted.* + syntax region texArgOptMinted matchgroup=Delimiter + \ start='\[' + \ end='\]' + \ contained + \ nextgroup=texArgMinted.* + + highlight link texZoneMinted texZone + highlight link texZoneMintedCmd texZone + highlight link texMintedName texInputFileOpt + highlight link texMintedNameOpt texMintedName +endfunction + +" }}}1 + +function! s:parse_minted_constructs() abort " {{{1 + if has_key(b:vimtex.syntax, 'minted') | return | endif + + let l:db = deepcopy(s:db) + let b:vimtex.syntax.minted = l:db.data + + let l:in_multi = 0 + for l:line in vimtex#parser#tex(b:vimtex.tex, {'detailed': 0}) + " Multiline minted environments + if l:in_multi + let l:lang = matchstr(l:line, '\]\s*{\zs\w\+\ze}') + if !empty(l:lang) + call l:db.register(l:lang) + let l:in_multi = 0 + endif + continue + endif + if l:line =~# '\\begin{minted}\s*\[[^\]]*$' + let l:in_multi = 1 + continue + endif + + " Single line minted environments + let l:lang = matchstr(l:line, '\\begin{minted}\%(\s*\[\[^\]]*\]\)\?\s*{\zs\w\+\ze}') + if !empty(l:lang) + call l:db.register(l:lang) + continue + endif + + " Simple minted commands + let l:lang = matchstr(l:line, '\\mint\%(\s*\[[^\]]*\]\)\?\s*{\zs\w\+\ze}') + if !empty(l:lang) + call l:db.register(l:lang) + continue + endif + + " Custom environments: + " - \newminted{lang}{opts} -> langcode + " - \newminted[envname]{lang}{opts} -> envname + let l:matches = matchlist(l:line, + \ '\\newminted\%(\s*\[\([^\]]*\)\]\)\?\s*{\([a-zA-Z-]\+\)}') + if !empty(l:matches) + call l:db.register(l:matches[2]) + call l:db.add_environment(!empty(l:matches[1]) + \ ? l:matches[1] + \ : l:matches[2] . 'code') + continue + endif + + " Custom macros: + " - \newmint(inline){lang}{opts} -> \lang(inline) + " - \newmint(inline)[macroname]{lang}{opts} -> \macroname + let l:matches = matchlist(l:line, + \ '\\newmint\(inline\)\?\%(\s*\[\([^\]]*\)\]\)\?\s*{\([a-zA-Z-]\+\)}') + if !empty(l:matches) + call l:db.register(l:matches[3]) + call l:db.add_macro(!empty(l:matches[2]) + \ ? l:matches[2] + \ : l:matches[3] . l:matches[1]) + continue + endif + endfor +endfunction + +" }}}1 + + +let s:db = { + \ 'data' : {}, + \} + +function! s:db.register(lang) abort dict " {{{1 + " Avoid dashes in langnames + let l:lang = substitute(a:lang, '-', '', 'g') + + if !has_key(self.data, l:lang) + let self.data[l:lang] = { + \ 'environments' : [], + \ 'commands' : [], + \} + endif + + let self.cur = self.data[l:lang] +endfunction + +" }}}1 +function! s:db.add_environment(envname) abort dict " {{{1 + if index(self.cur.environments, a:envname) < 0 + let self.cur.environments += [a:envname] + endif +endfunction + +" }}}1 +function! s:db.add_macro(macroname) abort dict " {{{1 + if index(self.cur.commands, a:macroname) < 0 + let self.cur.commands += [a:macroname] + endif +endfunction + +" }}}1 + +endif |