I have a couple of autocmds in my vim config along the lines of this (the actual commands are quite long):

    au BufWritePost *.latex.md  silent! ...
    au BufWritePost *.md  silent! ...

where writing files with .md or .latex.md extensions runs pandoc to convert my markdown files into the corresponding format. The problem I have (which you have probably guessed by looking at the example above) is that globbing for *.md subsumes files with a .latex.md extension. This means that files with that extension produce both HTML and a PDF, which is unnecessary. Is there any way to make the two autocommands mutually exlusive, or do I need to create a command or function that runs the correct command instead?


There's more to the autocmd pattern than *. Using other wildcards should give more flexibility in crafting patterns that don't overlap.

The problem is that the pattern matching for autocmd is not standard/vim regex and it's not shell-like globbing. It's a modified version of vim regex. Example: . represents a period not "any character except newline". :h file-pattern gives the details. From there we can try to come up with appropriate translations from standard to modified regex.

At first I thought the translation rules were too restrictive to allow use of some of the more advanced regex atoms (e.g lookahead/lookbehind). But a comment from @user938271 made me rethink that and after some testing we come to:

autocmd BufWritePost *.latex.md ...
autocmd BufWritePost *{.latex}\@<!.md ...

The negative lookbehind should ensure that the two autocmds are mutually exclusive (only one will be triggered for a given filename).

So, all I had to do was replace \(...\) with {...}. Overthinking made this much harder than it should have been.

| improve this answer | |
  • 1
    @BLayer Honestly, your regexp is too dirty (e.g. "foo.md" does not match at all), but that is not me who voted it down. – Matt Dec 13 '19 at 16:59
  • 1
    @BLayer Alas, It is even worse, as even simple lemon.md will not match here either. – Matt Dec 13 '19 at 17:31
  • 1
    Not sure it helps but you can use a negative lookbehind inside an autocmd file pattern: It is possible to use |pattern| items, but they may not work as expected, because of the translation done for the above. So for example, you could try: au BufWritePost *\(.latex\)\@<!.md ... – user938271 Dec 14 '19 at 8:33
  • 1
    FWIW, it seems to work on my machine (0x0.st/zUnI.txt). For the file /tmp/foo.latex.md, only the first autocmd is triggered. And for the file /tmp/foo.bar.md, only the second autocmd is triggered. Then again, maybe I misunderstood something. As for the issue about the translation, I don't think \(.latex\)\@<! is affected. The only character which should be translated is the dot, which in a usual regex stands for any character except the newline, while here it stands for a literal dot. But it's true that in general you have to be careful about which characters you use. – user938271 Dec 14 '19 at 10:01
  • 1
    I checked your code and it works on my machine. – user938271 Dec 14 '19 at 10:15

You can examine a match and then decide what to do. Whether to use multiple autocommands or "bar-newline-backslash" is a matter of style.

augroup mywritepost | au!
    autocmd BufWritePost *.md if expand("<afile>") =~? '\.latex\.md$'
    autocmd BufWritePost *.md     call s:makepdf()
    autocmd BufWritePost *.md else
    autocmd BufWritePost *.md     call s:makehtml()
    autocmd BufWritePost *.md endif
augroup end
| improve this answer | |

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

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