I am a recent and very happy Vim User. I write Mathematics and Computer Science Lecture Notes in Markdown Files, organized in a Vimwiki. I use the UltiSnips Snippet Plugin.

This plugin provides me with the possibility of defining snippets which only expand in a TexMathZone ("UltiSnips-context-snippets"). This happens through a Python function (see [1] below) returning true if the cursor is in a TexMathZone. That means that snippet expands when within $ or $$ delimiters (TexMathZoneX, TexMathZoneY).

This works perfectly in .tex Files, but not in .md Files. Setting the syntax to Tex by :set syntax=tex makes it work, but breaks markdown preview and syntax highlighting, which is unwanted.

I suspect this is because the syntax file for the markdown filetype does not define TexMathZone

How can I define or extend a markdown syntax file, such that the function in [1] delivers the same behaviour in markdown files as in Tex files? It should not inherit the other Tex syntax, and it should keep markdown syntax.

[1] Minimal markdown.snippets file, as seen on Gilles Castel's Snippet Configuration File :

global !p
texMathZones = ['texMathZone' + x for x in ['A', 'AS', 'B', 'BS', 'C', 'CS', 'D', 'DS', 'E', 'ES', 'F', 'FS', 'G', 'GS', 'H', 'HS', 'I', 'IS', 'J', 'JS', 'K', 'KS', 'L', 'LS', 'DS', 'V', 'W', 'X', 'Y', 'Z', 'AmsA', 'AmsB', 'AmsC', 'AmsD', 'AmsE', 'AmsF', 'AmsG', 'AmsAS', 'AmsBS', 'AmsCS', 'AmsDS', 'AmsES', 'AmsFS', 'AmsGS' ]]
texIgnoreMathZones = ['texMathText']
texMathZoneIds = vim.eval('map('+str(texMathZones)+", 'hlID(v:val)')")
texIgnoreMathZoneIds = vim.eval('map('+str(texIgnoreMathZones)+", 'hlID(v:val)')")
ignore = texIgnoreMathZoneIds[0]
def math():
    synstackids = vim.eval("synstack(line('.'), col('.') - (col('.')>=2 ? 1 : 0))")
        first = next(i for i in reversed(synstackids) if i in texIgnoreMathZoneIds or i in texMathZoneIds)
        return first != ignore
    except StopIteration:
        return False

context "math()"
snippet t "test" iAe

2 Answers 2


This works for markdown files with the vimwiki filetype. The only change needed is the addition ["VimwikiMath", "VimwikiEqIn"] to texMathZones.

texMathZones = ['texMathZone' + x for x in ['A', 'AS', 'B', 'BS', 'C', 'CS',
'D', 'DS', 'E', 'ES', 'F', 'FS', 'G', 'GS', 'H', 'HS', 'I', 'IS', 'J', 'JS',
'K', 'KS', 'L', 'LS', 'DS', 'V', 'W', 'X', 'Y', 'Z', 'AmsA', 'AmsB', 'AmsC',
'AmsD', 'AmsE', 'AmsF', 'AmsG', 'AmsAS', 'AmsBS', 'AmsCS', 'AmsDS', 'AmsES',
'AmsFS', 'AmsGS' ]] + ["VimwikiMath", "VimwikiEqIn"]

I found those by inspecting a file with this vimscript. It prints all the syntax tags at the cursor location.

for id in synstack(line('.'), line('.'))
   echo synIDattr(id, "name")

Note that text in equation mode escapes the math context. ($$\text{Lorem} $$)


I use the following math() context definition in vimwiki.snippet.
This only works if your cursor is in a fully paired $ math delimiter. But putting a fully paired $ and letting the cursor be between them is handy when using a snippet.
This is a rather limited implementation, but it does the job for me.

def math():
    synstackids = vim.eval("synstack(line('.'), col('.') - (col('.')>=2 ? 1 : 0))") # I don't understand this but it works
        return vim.eval(f"synIDattr({synstackids[0]},'name')") ==  'textSnipTEX'
        return False

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.