I have a file in my ~/.vim/ftdetect directory, which includes configuration such as:

autocmd BufRead,BufNewFile,BufWritePost .envrc.template set filetype=sh

However, I also have the vim-polyglot plugin installed (in ~/.vim/pack/packager/start/vim-polyglot/ftdetect/polyglot.vim, which includes the (less specific) instruction:

autocmd BufNewFile,BufRead *.template setlocal filetype=json

The loading order appears to ensure that the latter autocmd takes priority, which means that files called .envrc.template are incorrectly detected as JSON files.

How can I elegantly fix this? Ideally I'd like to keep the vim-polyglot plugin installed; and use the ~/.vim/ftdetect directory as I think it's intended. Is there a way to change the order in which the autocmds are applied?

An extract of the output of :scriptnames (edited for privacy and with large sections of files in similar/identical paths removed for length) below. Note the relative positions of lines 5 and 96.

  1: /etc/xdg/nvim/sysinit.vim
  2: /usr/share/nvim/archlinux.vim
  3: ~/.vim/init.vim
  4: /usr/share/nvim/runtime/filetype.vim
  5: ~/.vim/after/ftdetect/all.vim
  6: /usr/share/vim/vimfiles/ftdetect/dockerfile.vim
  8: /usr/share/nvim/runtime/ftplugin.vim
  9: /usr/share/nvim/runtime/indent.vim
 10: /usr/share/nvim/runtime/syntax/syntax.vim
 11: /usr/share/nvim/runtime/syntax/synload.vim
 12: /usr/share/nvim/runtime/syntax/syncolor.vim
 17: ~/.vim/plugin/completion.vim
 18: ~/.vim/plugin/diff.vim
 36: /usr/share/nvim/runtime/plugin/gzip.vim
 37: /usr/share/nvim/runtime/plugin/health.vim
 96: ~/.vim/pack/packager/start/vim-polyglot/ftdetect/polyglot.vim
127: ~/.vim/after/plugin/vim-pencil.vim
128: ~/.vim/after/plugin/vim-polyglot.vim

'runtimepath' as per Ben Knoble's question (again, edited for length) is:


You're in luck: the after directory exists for exactly this reason. ~/.vim/after is usually the last entry of 'runtimepath', so that whatever a user puts there overrides anything before it. Since it can house a full runtime, you can put anything you would put in ~/.vim in ~/.vim/after! I use this commonly for ~/.vim/after/ftplugin to override previous settings (but still allow them to execute).

Long story short, put your custom detector in ~/.vim/after/ftdetect/... and it should take precedence over polyglot because its autocommand will fire later—thereby overwriting the filetype set in polyglot. Now, this will have some bizarre effects if whatever is happening in polyglot doesn't set b:undo_ftplugin properly, because the actual sequence of events will be

  1. setlocal filetype=json
  2. setlocal filetype=sh

And if b:undo_ftplugin doesn't work right, you might have some stuff leftover from your json filetype scripts.

(Plus, I checked, and filetype.vim just does runtime! ftdetect/*.vim, which searches in order of 'runtimepath'.)

All of this said, this is why setfiletype exists (and plugins should use it).

For those in the comments struggling with this approach, please make sure your runtimepath has ~/.vim/after near the end (certainly after anything you want to override). Packages are automatically added in the correct place (i.e., before ~/.vim/after), but some plugin managers may not know they need to do this (and set runtimepath+=foo will put foo at the end, potentially overriding ~/.vim/after).

  • 2
    Thanks. I just tried this, and unfortunately, I don't think it works how you describe, although you did lead me to another workaround. filetype.vim does indeed find all ftdetect/*.vim files in runtimepath, but it seems that includes ~/.vim/after/ftdetect, and those get read directly after filetype.vim, and long before it gets to plugins in ~/.vim/pack (verified with :scriptnames). Moving my autocmds into ~/.vim/after/plugin, on the other hand, does work. It's a bit of a shame I cannot use the "standard" ftdetect directory name, but there you go. Mar 21 '20 at 8:33
  • 1
    @AndrewFerrier can you put scriptnames in your Q? It’s odd to me that after isnt last no matter what. Ill check my own later
    – D. Ben Knoble
    Mar 21 '20 at 11:38
  • 1
    OK, so for what it's worth, it turns out this is definitely a NeoVim vs Vim thing. It seems that for whatever reason "real" Vim works as expected here. NeoVim instead inserts the path ~/.vim/after/ftdetect far earlier into the runtimepath than it should. May 4 '20 at 16:21
  • 2
    @AndrewFerrier glad you figured that out; might be worth filing with their devs
    – D. Ben Knoble
    May 4 '20 at 19:56
  • 1
    For what it's worth, I think there is something fishy going on with after/ftdetect generally in Neovim, have observed some other strange behaviour. For reference, I've opened a bug. May 9 '20 at 21:27

I did find an alternative approach, which is to put my autocmds instead in ~/.vim/filetype.vim. They seem to be evaluated first over autocmds in plugins.

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.