This works for all 3 of your cases for me:
function InsertIfEmpty()
if @% == ""
" No filename for current buffer
startinsert
elseif filereadable(@%) == 0
" File doesn't exist yet
startinsert
elseif line('$') == 1 && col('$') == 1
" File is empty
startinsert
endif
endfunction
au VimEnter * call InsertIfEmpty()
These could probably be condensed into just the last check for a file being empty, since no filename or a file that doesn't exist typically start as empty buffers. However, it is probably possible that some other plugin pre-fills some stuff in one of the first two cases (like some template plugins), so it is best to check all three.
The first test you already had.
The second test needs to check filereadable
against the value of zero (doesn't exist) to decide if it is new (opposite of what you had).
The last test checks that the number of the last line in the file is 1 (which is also the first line, meaning that there is only one line), and that the column number of the end of line (column after the last character in the line) is 1, which would mean there are 0 characters. If there is only 1 line with 0 characters in it, then the file must be empty.
One final note: The way you have your statements in the question can result in some surprising results. Namely, you are setting BufRead
and BufNewFile
only if conditions are met at startup, but then those autocommands exist for the rest of your session. So, if you were to start on an empty file, which sets these commands, every subsequent file opened (new or not, empty or not) would start in insert mode.
The autocommand VimEnter
is run at the end of Vim's startup and only once for the whole session. This way, your tests only run when you start Vim and not any other time.
normal
instead ofexec
.if
statement should not be around the autocmd, if should be inside the autocmd, so it will be run every time the autocmd is triggered.