43Using filetypes
When you are editing a file of a certain type, for example a C program or a shell script, you often use the same option settings and mappings. You quickly get tired of manually setting these each time. This chapter explains how to do it automatically.
- Plugins for a filetype
- Adding a filetype
Table of contents
43.1Plugins for a filetype
How to start using filetype plugins has already been discussed here: add‑filetype‑plugin. But you probably are not satisfied with the default settings, because they have been kept minimal. Suppose that for C files you want to set the softtabstop option to 4 and define a mapping to insert a three-line comment. You do this with only two steps:
Create your own runtime directory. On Unix this usually is
~/.vim
. In this directory create theftplugin
directory:mkdir ~/.vim mkdir ~/.vim/ftplugin
When you are not on Unix, check the value of the runtimepath option to see where Vim will look for the
ftplugin
directory:set runtimepath
You would normally use the first directory name (before the first comma).
You might want to prepend a directory name to the runtimepath option in
your vimrc file if you don't like the default value.
Create the file
~/.vim/ftplugin/c.vim
, with the contents:setlocal softtabstop=4 noremap <buffer> <LocalLeader>c o/**************<CR><CR>/<Esc> let b:undo_ftplugin = "setl softtabstop< | unmap <buffer> <LocalLeader>c"
Try editing a C file. You should notice that the softtabstop option is set to 4. But when you edit another file it's reset to the default zero. That is because the :setlocal
command was used. This sets the softtabstop option only locally to the buffer. As soon as you edit another buffer, it will be set to the value set for that buffer. For a new buffer it will get the default value or the value from the last :set
command.
Likewise, the mapping for \c
will disappear when editing another buffer. The :map <buffer>
command creates a mapping that is local to the current buffer. This works with any mapping command: :map!
, :vmap
, etc. The <LocalLeader> in the mapping is replaced with the value of the maplocalleader
variable.
The line to set b:undo_ftplugin
is for when the filetype is set to another value. In that case you will want to undo your preferences. The b:undo_ftplugin
variable is executed as a command. Watch out for characters with a special meaning inside a string, such as a backslash.
You can find examples for filetype plugins in this directory:
$VIMRUNTIME/ftplugin/
More details about writing a filetype plugin can be found here: write‑plugin.
43.2Adding a filetype
If you are using a type of file that is not recognized by Vim, this is how to get it recognized. You need a runtime directory of your own. See your‑runtime‑dir above.
Create a file filetype.vim
which contains an autocommand for your filetype. (Autocommands were explained in section “Autocommands”.) Example:
augroup filetypedetect
au BufNewFile,BufRead *.xyz setf xyz
augroup END
This will recognize all files that end in .xyz
as the xyz
filetype. The :augroup
commands put this autocommand in the filetypedetect
group. This allows removing all autocommands for filetype detection when doing ":filetype off". The setf
command will set the filetype option to its argument, unless it was set already. This will make sure that filetype isn't set twice.
You can use many different patterns to match the name of your file. Directory names can also be included. See autocmd‑patterns. For example, the files under /usr/share/scripts/
are all ruby
files, but don't have the expected file name extension. Adding this to the example above:
augroup filetypedetect
au BufNewFile,BufRead *.xyz setf xyz
au BufNewFile,BufRead /usr/share/scripts/* setf ruby
augroup END
However, if you now edit a file /usr/share/scripts/README.txt, this is not a ruby file. The danger of a pattern ending in *
is that it quickly matches too many files. To avoid trouble with this, put the filetype.vim
file in another directory, one that is at the end of runtimepath. For Unix for example, you could use ~/.vim/after/filetype.vim
.
You now put the detection of text files in ~/.vim/filetype
.vim:
augroup filetypedetect
au BufNewFile,BufRead *.txt setf text
augroup END
That file is found in runtimepath first. Then use this in ~/.vim/after/filetype
.vim, which is found last:
augroup filetypedetect
au BufNewFile,BufRead /usr/share/scripts/* setf ruby
augroup END
What will happen now is that Vim searches for filetype.vim
files in each directory in runtimepath. First ~/.vim/filetype
.vim is found. The autocommand to catch *.txt files is defined there. Then Vim finds the filetype.vim
file in $VIMRUNTIME
, which is halfway runtimepath. Finally ~/.vim/after/filetype
.vim is found and the autocommand for detecting ruby files in /usr/share/scripts is added.
When you now edit /usr/share/scripts/README.txt, the autocommands are checked in the order in which they were defined. The *.txt pattern matches, thus "setf text" is executed to set the filetype to text
. The pattern for ruby matches too, and the "setf ruby" is executed. But since filetype was already set to text
, nothing happens here.
When you edit the file /usr/share/scripts/foobar the same autocommands are checked. Only the one for ruby matches and "setf ruby" sets filetype to ruby.
#Recognizing by contents
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
The first check with did_filetype() is to avoid that you will check the contents of files for which the filetype was already detected by the file name. That avoids wasting time on checking the file when the setf
command won't do anything.
The scripts.vim
file is sourced by an autocommand in the default filetype.vim
file. Therefore, the order of checks is:
filetype.vim
files before$VIMRUNTIME
in runtimepathfirst part of
$VIMRUNTIME/filetype
.vimall
scripts.vim
files in runtimepathremainder of
$VIMRUNTIME/filetype
.vimfiletype.vim
files after$VIMRUNTIME
in runtimepath
If this is not sufficient for you, add an autocommand that matches all files and sources a script or executes a function to check the contents of the file.