4

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:

/Users/user/.config/nvim
...
/Users/user/.config/nvim/pack/packager/start/vim-polyglot
...
/Users/user/.config/nvim/pack/packager/start/ale
/etc/xdg/nvim
/Users/user/.local/share/nvim/site
/usr/local/share/nvim/site
/usr/share/nvim/site
/usr/local/Cellar/neovim/0.4.3/share/nvim/runtime
/usr/local/Cellar/neovim/0.4.3/share/nvim/runtime/pack/dist/opt/matchit
/usr/share/nvim/site/after
/usr/local/share/nvim/site/after
/Users/user/.local/share/nvim/site/after
/etc/xdg/nvim/after
/Users/user/.config/nvim/after
0
4

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).

14
  • 3
    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
2

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.

1

vim-polyglot has addressed this issue.

In commit Use setf for ambiguous extensions from Aug 24, 2020, it started converting from set filetype=... to the setf command, then later commit Make loading faster for ambiguous extensions without heuristics from Sep 29, 2020 expanded the use of setf to other extensions such as .template for filetype json.

This makes it possible for you to override the vim-polyglot selection with an auto-command that uses set filetype=sh, such as the one in the question, since setf will not override the filetype if it's already set, even if the setf happens after your auto-command.

See :help new-filetype for more details on how the interactions between setf and set ft=... work together to allow you to override filetype detection rules installed by external plug-ins.

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.