If you want to introduce a file type and that file type can only be identified by examining the contents of such files then you'll need to add appropriate logic to a file named scripts.vim
.
But first, let's take a step back and look at the bigger picture. (Skip to the "Solution" section, below, if you're not interested in the technical details.)
Background
File type detection is enabled with the command :filetype on
. (This is typically in the user vimrc file or triggered by sourcing defaults.vim
.)
The command will cause Vim to source the script named filetype.vim
found in the directory named in the $VIMRUNTIME
environment variable. Doing so sets up a bunch of au BufNewFile,BufRead
autocommands. Since detection by filename is much more common than detection by content, the bulk of filetype.vim
is made up of lines like the following:
au BufNewFile,BufRead *.clj,*.cljs,*.cljx,*.cljc setf clojure
A couple thousand lines later we get to the part that kicks off detection by content:
au BufNewFile,BufRead *
\ if !did_filetype() && expand("<amatch>") !~ g:ft_ignore_pat
\ | runtime! scripts.vim | endif
The *
indicates that this autocommand will be triggered for all files so some logic is needed to filter out files that already matched a file extension specific autocommand (or otherwise had their type identified). !did_filetype()
guards against this as the function returns true if the FileType
event has been triggered at least once prior and we negate (!
) the result, thus halting further execution of the line. (We'll be using this same function in a guard block in our scripts.vim
.)
Following that is a check that the filename we're dealing with doesn't match certain extensions (e.g. .zip
)
If those two checks are passed, scripts.vim
will be executed. But which one? The :runtime
command means that ALL files named scripts.vim
appearing in one of the paths specified in 'runtimepath'
will be sourced/executed. There is always an instance of this file in the $VIMRUNTIME
directory. We're going to achieve our goal by creating our own instance of it.
Note that, by default, the first path in 'runtimepath'
is $HOME/.vim
(or non-Unix equivalent). That's where our script file is going to go which means our detection logic will take precedence over that in $VIMRUNTIME
or anywhere else.
(As an aside, a plugin-manager's main function is to update 'runtimepath'
and add a path for each installed plugin. While these typically get inserted before any system directories, as far as I know they always come after $HOME/.vim
.)
Solution
With the deep dive out of the way let's get down to business.
The standard place to put the local scripts.vim
file is in your personal Vim folder (usually in $HOME
) so run the following command (or your system equivalent): vim ~/.vim/scripts.vim
Assuming the file didn't exist before now, you'll want to add a guard block based on the function did_filetype()
which we covered above. Follow that with a conditional block with appropriate detection logic. For the OP's use case that would look like this:
if did_filetype() " filetype already set..
finish " ..don't do these checks
endif
if getline(1) =~ '^#!/usr/bin/awk -f'
setfiletype yourfiletype
endif
If the file already existed there's presumably something like the above already in it. In that case just append your detection logic as an elseif
.
" Existing two conditionals...
if {condition1}
setfiletype filetype1
elseif {condition2}
setfiletype filetype2
...etc...
" Add these two lines
elseif getline(1) =~ '^#!/usr/bin/awk -f'
setfiletype yourfiletype
endif
See also :h new-filetype-scripts
and :h filetypes