I want some autocmd
s to run when I open a file without a filetype like nvim
(no file name) or nvim myfile
(no extension). I also want them to run when opening certain file types like text
and markdown
so I can't blacklist everything with a file type/extension. Is there a way to run certain autocmd
s when no file type is known?
3 Answers
The most accurate and compliant way is to extend filetypes with after/ftplugin/{text,markdown}.vim
. Your "no extension" files can probably be detected as "text" filetype as well (or create a completely new filetype if you like). Then the actual functionality should be shared by a common autoloaded script.
But if you don't care then a single ftdetect script can do all work. Sort of,
~/.vim/ftdetect/stuff.vim
autocmd BufNewFile,BufRead *
\ if !did_filetype() && empty(expand("<afile>:e")) || &ft is# "text" || &ft is# "markdown"
\ | " do some stuff...
\ | endif
Note: FileType for an empty unnamed buffer is not auto-detected. So if you really need to do something in this case you still have to catch VimEnter
(or BufNew
, or BufEnter
etc.).
-
That's probably a "cleaner" way to do it than my answer :+1: (Thought I'd still use a list to check the filetype rather than
&ft is# "text" || &ft is# "markdown"
)– statoxCommented May 4, 2021 at 12:08 -
1@statox If there could be more than two of them then I would do it also.– MattCommented May 4, 2021 at 12:10
-
Can you provided a short script to automatically set
filetype
totext
if typeless? Commented May 5, 2021 at 6:23 -
@JohnZhau Typeless vs noext vs both... You should probably decide what you need exactly and then you'll be able to change condition in the example above yourself.– MattCommented May 5, 2021 at 6:48
-
@Matt, This works for existing files, such as README or TODO, but not if you open Vim with a new empty buffer or if you create a new empty buffer by using
:enew
. Could you improve the current version? Commented Aug 24, 2022 at 12:12
You can use the value of &filetype
to determine if you are in a buffer without a filetype or with one of the filetype you want to target. One example could be like this:
function! DoStuff()
if (exists('b:StuffDone') || index(['', 'text', 'markdown'], &ft) < 0)
return
endif
let b:StuffDone = 1
echo "Doing stuff for" &ft
endfunction
augroup Test
autocmd!
autocmd BufEnter * call DoStuff()
augroup END
Here your autocommand will call the function DoStuff()
for all of your buffers, however the function itself will check the current filetype and stop its execution if the filetype is not empty and if it's not in the list of filetypes you want to handle.
As @Matt pointed out in the comments BufEnter
is triggered each time you enter the buffer so that might be an issue. However reading :h autocmd-events
I don't find an event which would trigger for all buffers after we have their filetype. To prevent running your code several time in the same buffer I set a variable b:StuffDone
which is local to the buffer (:h b:
) and test for its existence before running the code.
-
1
BufEnter
is triggered every time a buffer becomes active. So it feels very wrong to use it for such task.– MattCommented May 4, 2021 at 8:39 -
@Matt that's a good point, the issue is that the other event might not be triggered for unnamed buffers. So I updated the code with a guard to avoid running the code twice.– statoxCommented May 4, 2021 at 8:59
-
This should work, though personally I'd rather create
ftdetect/stuff.vim
with something likeif !did_filetype() || &ft is# 'text' || ...
.– MattCommented May 4, 2021 at 9:33 -
1I agree that using the built-in mechanism
ftdetect
has advantages. Maybe it would be worth it that you post a separate answer with this solution? It's always good to have diversity in the solutions offered to a problem.– statoxCommented May 4, 2021 at 10:22
I'm assuming you don't want these autocmds to run on every file without a filetype and that there's some condition for when it should execute.
The built-in way to detect extensionless files is described in RECOGNIZING BY CONTENTS in :help filetype-plugin
. It's down at the bottom:
If your file cannot be recognized by its file name, you might be able to recognize it by its contents. For example, many script files start with a line like:
#!/bin/xyz ~
To recognize this script create a file "scripts.vim" in your runtime directory (same place where filetype.vim goes). It might look like this:
if did_filetype() finish endif if getline(1) =~ '^#!.*[/\\]xyz\>' setf xyz endif
You can even have multiple scripts.vim files in different runtimepath folders (so plugins can use scripts.vim).
Using scripts.vim
would let you inspect the content to determine what filetype the file should have and then you can use the FileType autocmd
to trigger.