3

Context

I have shortcuts to edit my vimrc and to source my vimrc. When I'm writing code I can quickly add a new mapping and then source vimrc. And all that would be good if I did not use autocmd FileType for most of my mappings.

Since most mappings are specific to one file type I keep my vimrc in a form similar to this:

function! FtPython()
  setlocal expandtab shiftwidth=4 softtabstop=4 autoindent
  nnoremap <buffer> <localleader>c I#<esc>

  " Let's say that this is a new mapping
  nnoremap <buffer> <localleader>cc ^wC:<esc><left>i

endfunction

if has("autocmd")
  augroup filetype_vimrc
    autocmd!
    autocmd FileType python call FtPython()
    ...
endif

Yet, when I add a new mapping to FtPython() and source my vimrc, the new mapping is not present in the python buffers because the FileType event happened long ago, when the file was read.

When I read a buffer back into a window FileType will be fired and the mapping will be added, but that does not happen when a window is already open and I just move into it (Ctrl+W). In essence, once I add a new mapping all currently open windows need to be "kicked" to get the new mapping.

I work around it by doing (I force the FileType event to fire):

set ft=python

But that is quite a lot of typing, sometimes I have 2-3 python files in different windows (split/vsplit) and I need to do it for each. argdo is not an option since it will close the windows (as far as I know).


Question

Is there a good way to fire the FileType event on all windows that Vim is currently showing?

Or, maybe, is there a better way to structure the mappings?

3
  • 4
    (1) autocmd FileType has its uses, but local setting are much better left to ftplugin files: then it's Vim's task to apply them at the right moment, not yours. (2) Contrary to the popular belief, vimrc is not really meant to be sourced multiple times. You can do it, but it takes a lot of careful backwards bending to avoid pitfalls. (3) How about bufdo for updating options. Jul 7, 2016 at 6:43
  • @SatoKatsura :bufdo is a good idea. I missed the part about different files.
    – Tommy A
    Jul 7, 2016 at 12:12
  • Btw. Some set commands works with :windo instead (when you've multiple files in split mode).
    – kenorb
    Oct 6, 2020 at 16:37

1 Answer 1

7

Is there a good way to fire the FileType event on all windows that Vim is currently showing?

Use :e instead of :set ft=python to reset the current buffer. It re-reads the file and triggers the relevant autocmds for the buffer.

Update: I missed the part about different files. You could re-set the filetype for all buffers with :bufdo

:bufdo doautocmd FileType

alternatively:

:bufdo let &ft=&ft

There is also doautoall which can re-trigger the FileType autocmd in all buffers:

:doautoall FileType

The methods above are a bit heavy handed and not without drawbacks. If you want to affect only python filetypes:

:bufdo if &ft == 'python' | doautocmd FileType | endif

as a command that accepts the filetype as an argument:

command! -complete=filetype -nargs=1 FiletypeReload bufdo if &ft =~# '\<<args>\>' | doautocmd FileType | endif

Or, maybe, is there a better way to structure the mappings?

You could use filetype scripts in ~/.vim/after/ftplugin/<filetype>.vim. Then you wouldn't need to source vimrc to pick up the changes. The methods above will cause the ftplugin scripts to be sourced for you. Since it's sourced after other filetype scripts, it will also guarantee that the mapped keys are actually yours and not something a plugin introduced.

If you're using this method, you can change the command above to use the filetypeplugin group:

command! -complete=filetype -nargs=1 FiletypeReload bufdo if &ft =~# '\<<args>\>' | doautocmd filetypeplugin FileType | endif

The filetypeplugin group is used to trigger only the FileType autocmd in $VIMRUNTIME/ftplugin.vim which is responsible for running ftplugin scripts. This would be preferred since the outcome is slightly more predictable than triggering FileType autocmds setup at runtime.

3
  • 1
    Wow, awesome answer! Actually I used python files as an example since it is the most common situation for me. But I just tested with two python files and one JS file and both bufdo and doautoall reload the autocmds (for all files) nicely. I need to admit I'm a little afraid of meddling with the ftpplugin (someday i'll get there).
    – grochmal
    Jul 7, 2016 at 15:18
  • 2
    @grochmal ftplugin scripts are simply loaded when the filetype is set. What's nice about them is that they aren't loaded when they aren't needed and you can have script-local variables and functions. You can read about how they're loaded with :h vimfiles. There's a link to my dotfiles in my profile if you want to see how I'm using them.
    – Tommy A
    Jul 7, 2016 at 16:10
  • @TommyA :bufdo if &ft == 'python' | doautocmd FileType | endif doesn't work... I am on Vim 8.2. It opens up an empty buffer with no &ft being an empty string in the current buffer
    – codepoet
    Feb 4, 2021 at 20:54

Your Answer

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

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