The culprit appears to be the WinEnter autocmd, which is apparently being triggered with the buffer you left and not the one you entered. To demonstrate, you can set up an autocmd like this to print the name of the buffer the WinEnter command was run on, or 'unnamed buffer' if it has no name.
augroup Testingautocmd!
autocmd WinEnter * echom (empty(expand('<amatch>'))? 'unnamed buffer' : expand('<amatch>'))
augroup END
To see the output when running :tabnew
, :new
, and :vnew
, you'll need to run :messages
, as vim annoyingly overwrites the commandline with a blank line for those commands (that's why I used :echom[sg]
).
By checking the messages you can see that when :tabnew
, :new
or :vnew
is run we get the name of the last buffer (in your case a terminal code) instead of 'unnamed buffer' like you'd expect, so it appears that vim still thinks it's in the old buffer when it runs the WinEnter command, and so erronously triggers :startinsert
on the new file.
As for how to fix it, triggering the autocmd on BufEnter will work most of the time (as you already know), except for the case of switching between two windows both containing the same terminal.
Vim's buffers are it's abstraction of files. Windows are simply areas of the screen that offer a view onto a buffer. All windows showing the same file are views of parts of the same buffer - this includes windows in different tabs, as vim tabs are just collections of windows. So WinLeave and WinEnter completely ignore what's in any buffer and are fired everytime you move between two different windows. The BufLeave and BufEnter completely ignore whether you move windows and are fired only when vim changes the buffer you're currently editing (it calls this the current file and it's the one who's name you can use as %
on the commandline, see :h current-file
). So typically when switching between two windows which have different files open, both BufLeave/Enter and WinLeave/Enter get called (both of their conditions are satisfied). BufWinLeave/BufWinEnter gets triggered when a window changes the buffer it's viewing. Commands like :e
and :b
usually trigger this. :e
and :b
also usually trigger BufLeave/Enter, but not WinLeave/Enter; although the current window hasn't changed, the current file has (BufLeave/Enter) and the file displayed in the current window has (BufWinLeave/Enter). You can look at these commands being executed by getting them to echo messages everytime they are fired (like my example above), to see what happens whereever you're unsure.
Hence by triggering startinsert on BufEnter you get into insert mode whenever the current buffer switches to a terminal, which I assume is almost always what you want. As I mentioned, it breaks when you have to windows both viewing the same terminal buffer and you switch between those; the current file does not change and so BufEnter is never triggered.
<cr>
after startinsert is unnecessary and, in Vim at least, causes an error when the autocommand fires.<cr>
.:h WinEnter
. See the Note section. That also applies to:tab
commands.BufEnter
does the trick. PerhapsWinEnter
autocommands just can't be linked to buffers? It's not really clear from the documentation what the differences betweenBufEnter
,WinEnter
andBufWinEnter
are.