From c012f55efda29f09179e921cf148d79deb57616e Mon Sep 17 00:00:00 2001 From: Nick Shipp Date: Sun, 7 May 2017 09:04:01 -0400 Subject: Much maturering of vim configs --- vim/bundle/vim-racer/.gitignore | 1 + vim/bundle/vim-racer/README.md | 60 +++++ vim/bundle/vim-racer/autoload/racer.vim | 265 +++++++++++++++++++++ vim/bundle/vim-racer/ftplugin/rust_racer.vim | 44 ++++ .../rplugin/python3/deoplete/sources/racer.py | 111 +++++++++ vim/bundle/vim-racer/syntax/rustdoc.vim | 178 ++++++++++++++ 6 files changed, 659 insertions(+) create mode 100644 vim/bundle/vim-racer/.gitignore create mode 100644 vim/bundle/vim-racer/README.md create mode 100644 vim/bundle/vim-racer/autoload/racer.vim create mode 100644 vim/bundle/vim-racer/ftplugin/rust_racer.vim create mode 100644 vim/bundle/vim-racer/rplugin/python3/deoplete/sources/racer.py create mode 100644 vim/bundle/vim-racer/syntax/rustdoc.vim (limited to 'vim/bundle/vim-racer') diff --git a/vim/bundle/vim-racer/.gitignore b/vim/bundle/vim-racer/.gitignore new file mode 100644 index 0000000..0d20b64 --- /dev/null +++ b/vim/bundle/vim-racer/.gitignore @@ -0,0 +1 @@ +*.pyc diff --git a/vim/bundle/vim-racer/README.md b/vim/bundle/vim-racer/README.md new file mode 100644 index 0000000..b56655d --- /dev/null +++ b/vim/bundle/vim-racer/README.md @@ -0,0 +1,60 @@ +# Vim Racer Plugin + +This plugin allows vim to use [Racer](http://github.com/phildawes/racer) for Rust code completion and navigation. + +## Installation + +1. Build / Install [Racer](http://github.com/phildawes/racer) + +2. Install using Pathogen, Vundle or NeoBundle. Or, copy `plugin/racer.vim` into your `~/.vim/plugin` directory. + + Vundle users: + ``` + Plugin 'racer-rust/vim-racer' + ``` + + NeoBundle users: + ``` + NeoBundle 'racer-rust/vim-racer' + ``` + + vim-plug users: + ``` + Plug 'racer-rust/vim-racer' + ``` + + Pathogen users: + ``` + git clone --depth=1 https://github.com/racer-rust/vim-racer.git ~/.vim/bundle/vim-racer + ``` + +3. Add `g:racer_cmd` to your `.vimrc`. Also it's worth turning on 'hidden' mode for buffers otherwise you need to save the current buffer every time you do a goto-definition. E.g.: + + ``` + set hidden + let g:racer_cmd = "/path/to/racer/bin" + ``` + +4. If you want completions to show the complete function definition (e.g. its arguments and return type), enable the experimental completer: + + ``` + let g:racer_experimental_completer = 1 + ``` + +## Example Mappings + +vim-racer enables `C-x-C-o` to search for completions and provides several +`` mappings for source code navigation. These mappings are not enabled by +default but you can easily use them by adding the following lines to your +`.vimrc` (Or `init.vim` in case of Neovim). + +For example, with the following mappings you can navigate to the identifier under +the cursor and open it on the current buffer, on an horizontal or vertical split, +or go straight to the documentation: + +``` +au FileType rust nmap gd (rust-def) +au FileType rust nmap gs (rust-def-split) +au FileType rust nmap gx (rust-def-vertical) +au FileType rust nmap gd (rust-doc) +``` diff --git a/vim/bundle/vim-racer/autoload/racer.vim b/vim/bundle/vim-racer/autoload/racer.vim new file mode 100644 index 0000000..5cb80d7 --- /dev/null +++ b/vim/bundle/vim-racer/autoload/racer.vim @@ -0,0 +1,265 @@ +function! s:RacerGetPrefixCol(base) + let col = col('.') - 1 + let b:racer_col = col + let b:tmpfname = tempname() + call writefile(s:RacerGetBufferContents(a:base), b:tmpfname) + let cmd = g:racer_cmd . ' prefix ' . line('.') . ' ' . col . ' ' . b:tmpfname + let res = system(cmd) + let prefixline = split(res, '\n')[0] + let startbyte = split(prefixline[7:], ',')[0] + return startbyte - line2byte(byte2line(startbyte)) + 1 +endfunction + +function! s:RacerGetExpCompletions(base) + let col = col('.')-1 + let b:tmpfname = tempname() + call writefile(s:RacerGetBufferContents(a:base), b:tmpfname) + let fname = expand('%:p') + let cmd = g:racer_cmd . ' complete ' . line('.') . ' ' . col . ' "' . fname . '" "' . b:tmpfname . '"' + let res = system(cmd) + + let typeMap = { + \ 'Struct' : 's', 'Module' : 'M', 'Function' : 'f', + \ 'Crate' : 'C', 'Let' : 'v', 'StructField' : 'm', + \ 'Impl' : 'i', 'Enum' : 'e', 'EnumVariant' : 'E', + \ 'Type' : 't', 'FnArg' : 'v', 'Trait' : 'T' + \ } + + let lines = split(res, '\n') + let out = [] + + for line in lines + if line !~# '^MATCH' + continue + endif + + let completions = split(line[6:], ',') + let kind = get(typeMap, completions[4]) + let completion = { 'kind' : kind, 'word' : completions[0], 'dup' : 1 } + let info = join(completions[5:], ',') + + if kind ==# 'f' + " function + let completion['menu'] = substitute( + \ substitute( + \ substitute(info, '\(pub\|fn\) ', '', 'g'), + \ '{*$', '', '' + \ ), + \ ' where\s\?.*$', '', '' + \ ) + if g:racer_insert_paren == 1 + let completion['abbr'] = completions[0] + let completion['word'] .= '(' + endif + let completion['info'] = info + elseif kind ==# 's' " struct + let completion['menu'] = substitute( + \ substitute(info, '\(pub\|struct\) ', '', 'g'), + \ '{*$', '', '' + \ ) + endif + + if stridx(tolower(completions[0]), tolower(a:base)) == 0 + let out = add(out, completion) + endif + endfor + call delete(b:tmpfname) + return out +endfunction + +function! s:RacerSplitLine(line) + let separator = ';' + let placeholder = '{PLACEHOLDER}' + let line = substitute(a:line, '\\;', placeholder, 'g') + let parts = split(line, separator) + let docs = substitute( + \ substitute( + \ substitute( + \ substitute(get(parts, 7, ''), '^\"\(.*\)\"$', '\1', ''), + \ '\\\"', '\"', 'g' + \ ), + \ '\\''', '''', 'g' + \ ), + \ '\\n', '\n', 'g' + \ ) + let parts = add(parts[:6], docs) + let parts = map(copy(parts), 'substitute(v:val, ''{PLACEHOLDER}'', '';'', ''g'')') + + return parts +endfunction + +function! racer#ShowDocumentation() + let winview = winsaveview() " Save the current cursor position + " Move to the end of the word for the entire token to search. + " Move one char back to avoid moving to the end of the *next* word. + execute 'normal he' + let col = col('.') + let b:tmpfname = tempname() + " Create temporary file with the buffer's current state + call writefile(getline(1, '$'), b:tmpfname) + let fname = expand('%:p') + let cmd = g:racer_cmd . ' complete-with-snippet ' . line('.') . ' ' . col . ' ' . fname . ' ' . b:tmpfname + let res = system(cmd) + " Restore de cursor position + call winrestview(winview) + " Delete the temporary file + call delete(b:tmpfname) + let lines = split(res, '\n') + for line in lines + if line !~# '^MATCH' + continue + endif + + let docs = s:RacerSplitLine(line[6:])[7] + if len(docs) == 0 + break + endif + + " Only open doc buffer if there're docs to show + let bn = bufnr('__doc__') + if bn > 0 + let wi = index(tabpagebuflist(tabpagenr()), bn) + if wi >= 0 + " If the __doc__ buffer is open in the current tab, jump to it + silent execute (wi+1) . 'wincmd w' + else + silent execute 'sbuffer ' . bn + endif + else + split '__doc__' + endif + + setlocal nobuflisted + setlocal modifiable + setlocal noswapfile + setlocal buftype=nofile + silent normal! ggdG + silent $put=docs + silent normal! 1Gdd + setlocal nomodifiable + setlocal nomodified + setlocal filetype=rustdoc + break + endfor +endfunction + +function! s:RacerGetCompletions(base) + let col = col('.') - 1 + let b:tmpfname = tempname() + " HACK: Special case to offer autocompletion on a string literal + if getline('.')[:col-1] =~# '".*"\.$' + call writefile(['fn main() {', ' let x: &str = "";', ' x.', '}'], b:tmpfname) + let fname = expand('%:p') + let cmd = g:racer_cmd . ' complete 3 6 "' . fname . '" "' . b:tmpfname . '"' + else + call writefile(s:RacerGetBufferContents(a:base), b:tmpfname) + let fname = expand('%:p') + let cmd = g:racer_cmd . ' complete ' . line('.') . ' ' . col . ' "' . fname . '" "' . b:tmpfname . '"' + endif + let res = system(cmd) + let lines = split(res, '\n') + let out = [] + for line in lines + if line !~# '^MATCH' + continue + endif + let completion = split(line[6:], ',')[0] + if stridx(tolower(completion), tolower(a:base)) == 0 + let out = add(out, completion) + endif + endfor + call delete(b:tmpfname) + + return out +endfunction + +function! racer#GoToDefinition() + if s:ErrorCheck() + return + endif + + let col = col('.') - 1 + let b:racer_col = col + let fname = expand('%:p') + let tmpfname = tempname() + call writefile(getline(1, '$'), tmpfname) + let cmd = g:racer_cmd . ' find-definition ' . line('.') . ' ' . col . ' ' . fname . ' ' . tmpfname + let res = system(cmd) + let lines = split(res, '\n') + for line in lines + if res =~# ' error: ' && line !=# 'END' + call s:Warn(line) + elseif line =~# '^MATCH' + let linenum = split(line[6:], ',')[1] + let colnum = split(line[6:], ',')[2] + let fname = split(line[6:], ',')[3] + call s:RacerJumpToLocation(fname, linenum, colnum) + break + endif + endfor + call delete(tmpfname) +endfunction + +function! s:RacerGetBufferContents(base) + " Re-combine the completion base word from omnicomplete with the current + " line contents. Since the base word gets remove from the buffer before + " this function is invoked we have to put it back in to out tmpfile. + let col = col('.') - 1 + let buf_lines = getline(1, '$') + let line_contents = getline('.') + let buf_lines[line('.') - 1] = + \ strpart(line_contents, 0, col) . + \ a:base . + \ strpart(line_contents, col, len(line_contents)) + return buf_lines +endfunction + +function! s:RacerJumpToLocation(filename, linenum, colnum) + if a:filename == '' + return + endif + + " Record jump mark + normal! m` + if a:filename != bufname('%') + try + exec 'keepjumps e ' . fnameescape(a:filename) + catch /^Vim\%((\a\+)\)\=:E37/ + " When the buffer is not saved, E37 is thrown. We can ignore it. + endtry + endif + call cursor(a:linenum, a:colnum + 1) + " Center definition on screen + normal! zz +endfunction + +function! racer#RacerComplete(findstart, base) + if a:findstart + if s:ErrorCheck() + return -1 + endif + + return s:RacerGetPrefixCol(a:base) + else + if s:ErrorCheck() + return [] + endif + + if g:racer_experimental_completer == 1 + return s:RacerGetExpCompletions(a:base) + else + return s:RacerGetCompletions(a:base) + endif + endif +endfunction + +function! s:Warn(msg) + echohl WarningMsg | echomsg a:msg | echohl NONE +endfunction + +function! s:ErrorCheck() + if !executable(g:racer_cmd) + call s:Warn('No racer executable found in $PATH (' . $PATH . ')') + return 1 + endif +endfunction diff --git a/vim/bundle/vim-racer/ftplugin/rust_racer.vim b/vim/bundle/vim-racer/ftplugin/rust_racer.vim new file mode 100644 index 0000000..a76fc3b --- /dev/null +++ b/vim/bundle/vim-racer/ftplugin/rust_racer.vim @@ -0,0 +1,44 @@ +let s:save_cpo = &cpo +set cpo&vim + +let s:is_win = has('win32') || has('win64') + +if !exists('g:racer_cmd') + let s:sep = s:is_win ? '\' : '/' + let s:path = join([ + \ escape(expand(':p:h'), '\'), + \ '..', + \ 'target', + \ 'release', + \ ], s:sep) + if isdirectory(s:path) + let s:pathsep = s:is_win ? ';' : ':' + let $PATH .= s:pathsep . s:path + endif + let g:racer_cmd = 'racer' +endif + +" Expand '~' and environment variables +let g:racer_cmd = expand(g:racer_cmd) + +if !exists('g:racer_experimental_completer') + let g:racer_experimental_completer = 0 +endif + +if !exists('g:racer_insert_paren') + let g:racer_insert_paren = 1 +endif + +nnoremap (rust-def) + \ :call racer#GoToDefinition() +nnoremap (rust-def-split) + \ :split:call racer#GoToDefinition() +nnoremap (rust-def-vertical) + \ :vsplit:call racer#GoToDefinition() +nnoremap (rust-doc) + \ :call racer#ShowDocumentation() + +setlocal omnifunc=racer#RacerComplete + +let &cpo = s:save_cpo +unlet s:save_cpo diff --git a/vim/bundle/vim-racer/rplugin/python3/deoplete/sources/racer.py b/vim/bundle/vim-racer/rplugin/python3/deoplete/sources/racer.py new file mode 100644 index 0000000..f041530 --- /dev/null +++ b/vim/bundle/vim-racer/rplugin/python3/deoplete/sources/racer.py @@ -0,0 +1,111 @@ +#============================================================================= +# FILE: racer.py +# AUTHOR: Shougo Matsushita +# License: MIT license {{{ +# Permission is hereby granted, free of charge, to any person obtaining +# a copy of this software and associated documentation files (the +# "Software"), to deal in the Software without restriction, including +# without limitation the rights to use, copy, modify, merge, publish, +# distribute, sublicense, and/or sell copies of the Software, and to +# permit persons to whom the Software is furnished to do so, subject to +# the following conditions: +# +# The above copyright notice and this permission notice shall be included +# in all copies or substantial portions of the Software. +# +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS +# OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +# MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. +# IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY +# CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, +# TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE +# SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +# }}} +#============================================================================= + +import re +import os +import subprocess +import tempfile +from .base import Base + +class Source(Base): + def __init__(self, vim): + Base.__init__(self, vim) + + self.name = 'racer' + self.mark = '[racer]' + self.filetypes = ['rust'] + self.input_pattern = r'(\.|::)\w*' + self.rank = 500 + + def on_init(self, context): + self.__executable_racer = self.vim.funcs.executable( + self.vim.eval('g:racer_cmd')) + self.__racer = self.vim.eval('g:racer_cmd') + + def get_complete_position(self, context): + if not self.__executable_racer: + return -1 + + m = re.search('\w*$', context['input']) + return m.start() if m else -1 + + + def gather_candidates(self, context): + typeMap = { + 'Struct': 's', 'Module': 'M', 'Function': 'f', + 'Crate': 'C', 'Let': 'v', 'StructField': 'm', + 'Impl': 'i', 'Enum': 'e', 'EnumVariant': 'E', + 'Type': 't', 'FnArg': 'v', 'Trait': 'T', + 'Const': 'c' + } + + candidates = [] + insert_paren = int(self.vim.eval('g:racer_insert_paren')) + for line in [l[6:] for l + in self.get_results(context, 'complete', + context['complete_position'] + 1) + if l.startswith('MATCH')]: + completions = line.split(',') + kind = typeMap.get(completions[4], '') + completion = { 'kind': kind, 'word': completions[0], 'dup': 1 } + if kind == 'f': # function + completion['menu'] = ','.join(completions[5:]).replace( + 'pub ', '').replace('fn ', '').rstrip('{') + if ' where ' in completion['menu'] or completion[ + 'menu'].endswith(' where') : + where = completion['menu'].rindex(' where') + completion['menu'] = completion['menu'][: where] + if insert_paren: + completion['abbr'] = completions[0] + completion['word'] += '(' + elif kind == 's' : # struct + completion['menu'] = ','.join(completions[5:]).replace( + 'pub ', '').replace( 'struct ', '').rstrip('{') + candidates.append(completion) + return candidates + + def get_results(self, context, command, col): + with tempfile.NamedTemporaryFile(mode='w') as tf: + tf.write("\n".join(self.vim.current.buffer)) + tf.flush() + + args = [ + self.__racer, command, + str(self.vim.funcs.line('.')), + str(col - 1), + tf.name + ] if command == 'prefix' else [ + self.__racer, command, + str(self.vim.funcs.line('.')), + str(col - 1), + self.vim.current.buffer.name, + tf.name + ] + try: + results = subprocess.check_output(args).decode( + context['encoding']).splitlines() + except subprocess.CalledProcessError: + return [] + return results diff --git a/vim/bundle/vim-racer/syntax/rustdoc.vim b/vim/bundle/vim-racer/syntax/rustdoc.vim new file mode 100644 index 0000000..d527c9b --- /dev/null +++ b/vim/bundle/vim-racer/syntax/rustdoc.vim @@ -0,0 +1,178 @@ +" Vim syntax file +" Language: Rust Documentation (Markdown) +" Maintainer: Esteban Kuber +" Remark: Uses HTML and Rust syntax files. +" Based off plasticboy's Markdown Vim Mode: +" https://github.com/plasticboy/vim-markdown. +" TODO: Handle stuff contained within stuff (e.g. headings within blockquotes) + + +" Read the HTML syntax to start with +if version < 600 + so :p:h/html.vim +else + runtime! syntax/html.vim + + if exists('b:current_syntax') + unlet b:current_syntax + endif +endif + +if version < 600 + syntax clear +elseif exists("b:current_syntax") + finish +endif + +" don't use standard HiLink, it will not work with included syntax files +if version < 508 + command! -nargs=+ HtmlHiLink hi link +else + command! -nargs=+ HtmlHiLink hi def link +endif + +syn spell toplevel +syn case ignore +syn sync linebreaks=1 + +let s:conceal = '' +let s:concealends = '' +if has('conceal') && get(g:, 'vim_markdown_conceal', 1) + let s:conceal = ' conceal' + let s:concealends = ' concealends' +endif + +" additions to HTML groups +if get(g:, 'vim_markdown_emphasis_multiline', 1) + let s:oneline = '' +else + let s:oneline = ' oneline' +endif +execute 'syn region htmlItalic start="\%(^\|\s\)\zs\*\ze[^\\\*\t ]\%(\%([^*]\|\\\*\|\n\)*[^\\\*\t ]\)\?\*\_W" end="[^\\\*\t ]\zs\*\ze\_W" keepend' . s:oneline +execute 'syn region htmlItalic start="\%(^\|\s\)\zs_\ze[^\\_\t ]" end="[^\\_\t ]\zs_\ze\_W" keepend' . s:oneline +execute 'syn region htmlBold start="\%(^\|\s\)\*\*\ze\S" end="\S\zs\*\*" keepend' . s:oneline +execute 'syn region htmlBold start="\%(^\|\s\)\zs__\ze\S" end="\S\zs__" keepend' . s:oneline +execute 'syn region htmlBoldItalic start="\%(^\|\s\)\zs\*\*\*\ze\S" end="\S\zs\*\*\*" keepend' . s:oneline +execute 'syn region htmlBoldItalic start="\%(^\|\s\)\zs___\ze\S" end="\S\zs___" keepend' . s:oneline + +" [link](URL) | [link][id] | [link][] | ![image](URL) +syn region mkdFootnotes matchgroup=mkdDelimiter start="\[^" end="\]" +execute 'syn region mkdID matchgroup=mkdDelimiter start="\[" end="\]" contained oneline' . s:conceal +execute 'syn region mkdURL matchgroup=mkdDelimiter start="(" end=")" contained oneline' . s:conceal +execute 'syn region mkdLink matchgroup=mkdDelimiter start="\\\@ ]*>" end=">" + +" Link definitions: [id]: URL (Optional Title) +syn region mkdLinkDef matchgroup=mkdDelimiter start="^ \{,3}\zs\[" end="]:" oneline nextgroup=mkdLinkDefTarget skipwhite +syn region mkdLinkDefTarget start="<\?\zs\S" excludenl end="\ze[>[:space:]\n]" contained nextgroup=mkdLinkTitle,mkdLinkDef skipwhite skipnl oneline +syn region mkdLinkTitle matchgroup=mkdDelimiter start=+"+ end=+"+ contained +syn region mkdLinkTitle matchgroup=mkdDelimiter start=+'+ end=+'+ contained +syn region mkdLinkTitle matchgroup=mkdDelimiter start=+(+ end=+)+ contained + +"HTML headings +syn region htmlH1 start="^\s*#" end="$" contains=@Spell +syn region htmlH2 start="^\s*##" end="$" contains=@Spell +syn region htmlH3 start="^\s*###" end="$" contains=@Spell +syn region htmlH4 start="^\s*####" end="$" contains=@Spell +syn region htmlH5 start="^\s*#####" end="$" contains=@Spell +syn region htmlH6 start="^\s*######" end="$" contains=@Spell +syn match htmlH1 /^.\+\n=\+$/ contains=@Spell +syn match htmlH2 /^.\+\n-\+$/ contains=@Spell + +"define Markdown groups +syn match mkdLineBreak / \+$/ +syn region mkdBlockquote start=/^\s*>/ end=/$/ contains=mkdLineBreak,@Spell +syn region mkdCode start=/\(\([^\\]\|^\)\\\)\@]*\\\@" end="" +syn region mkdCode start="]*\\\@" end="" +syn region mkdFootnote start="\[^" end="\]" +syn match mkdCode /^\s*\n\(\(\s\{8,}[^ ]\|\t\t\+[^\t]\).*\n\)\+/ +syn match mkdCode /\%^\(\(\s\{4,}[^ ]\|\t\+[^\t]\).*\n\)\+/ +syn match mkdCode /^\s*\n\(\(\s\{4,}[^ ]\|\t\+[^\t]\).*\n\)\+/ contained +syn match mkdListItem /^\s*\%([-*+]\|\d\+\.\)\s\+/ contained +syn region mkdListItemLine start="^\s*\%([-*+]\|\d\+\.\)\s\+" end="$" oneline contains=@mkdNonListItem,mkdListItem,@Spell +syn region mkdNonListItemBlock start="\(\%^\(\s*\([-*+]\|\d\+\.\)\s\+\)\@!\|\n\(\_^\_$\|\s\{4,}[^ ]\|\t+[^\t]\)\@!\)" end="^\(\s*\([-*+]\|\d\+\.\)\s\+\)\@=" contains=@mkdNonListItem,@Spell +syn match mkdRule /^\s*\*\s\{0,1}\*\s\{0,1}\*$/ +syn match mkdRule /^\s*-\s\{0,1}-\s\{0,1}-$/ +syn match mkdRule /^\s*_\s\{0,1}_\s\{0,1}_$/ +syn match mkdRule /^\s*-\{3,}$/ +syn match mkdRule /^\s*\*\{3,5}$/ + +" YAML frontmatter +if get(g:, 'vim_markdown_frontmatter', 0) + syn include @yamlTop syntax/yaml.vim + syn region Comment matchgroup=mkdDelimiter start="\%^---$" end="^---$" contains=@yamlTop keepend + unlet! b:current_syntax +endif + +if get(g:, 'vim_markdown_toml_frontmatter', 0) + try + syn include @tomlTop syntax/toml.vim + syn region Comment matchgroup=mkdDelimiter start="\%^+++$" end="^+++$" transparent contains=@tomlTop keepend + unlet! b:current_syntax + catch /E484/ + syn region Comment matchgroup=mkdDelimiter start="\%^+++$" end="^+++$" + endtry +endif + +if get(g:, 'vim_markdown_json_frontmatter', 0) + try + syn include @jsonTop syntax/json.vim + syn region Comment matchgroup=mkdDelimiter start="\%^{$" end="^}$" contains=@jsonTop keepend + unlet! b:current_syntax + catch /E484/ + syn region Comment matchgroup=mkdDelimiter start="\%^{$" end="^}$" + endtry +endif + +if get(g:, 'vim_markdown_math', 0) + syn include @tex syntax/tex.vim + syn region mkdMath start="\\\@