Vim filetype 文件类型检测怎么配置?自定义语法怎么写?
为什么你的 Vim 没有语法高亮
打开一个 .py 文件,满屏灰白;编辑 .js,缩进全靠手敲——大概率是 filetype 没开。Vim 的文件类型检测是语法高亮、缩进、文件类型插件这三套机制的地基,没它后面全白搭。
filetype 三件套:on / plugin / indent
在 vimrc 里加上这一行就够了:
vimfiletype plugin indent on
它实际等价于三条独立命令:
filetype on—— 启用文件类型检测,Vim 会根据文件名和内容自动设置&filetype选项filetype plugin on—— 检测到类型后,加载对应的 ftplugin 脚本($VIMRUNTIME/ftplugin/<type>.vim)filetype indent on—— 加载对应的缩进脚本($VIMRUNTIME/indent/<type>.vim)
想看当前状态,直接输入:
vim:filetype
输出类似 filetype detection:ON plugin:ON indent:OFF,一目了然。
很多人的 vimrc 里同时写了 syntax on 和 filetype on,其实 syntax on 会自动安装 filetype 检测,重复写不算错但多余。如果只需要语法高亮不需要插件和缩进,单独 syntax on 就行;需要完整功能就用 filetype plugin indent on 加 syntax enable(enable 不会覆盖已有配色方案,比 on 更温和)。
检测原理:文件名优先,内容兜底
Vim 检测文件类型分两步走:
-
文件名匹配 —— 读取
$VIMRUNTIME/filetype.vim(超过 2300 行),按扩展名和文件名模式匹配。.c是 c,Makefile是 make,.tsx是 typescriptreact,覆盖了绝大部分常见文件。 -
内容检测 —— 文件名没匹配上时,Vim 调用
$VIMRUNTIME/scripts.vim,检查文件头部的 shebang、DOCTYPE、特定关键词等。比如第一行是#!/usr/bin/env python3,即使文件没有.py后缀也能识别为 Python。
如果两步都失败了,&filetype 保持空值。这时候可以手动设置:
vim:set filetype=python
或者在文件里加 modeline(写在文件末尾的注释中):
vim# vim: set filetype=python:
ftplugin 目录:给特定文件类型加配置
ftplugin 是 filetype 和编辑器设置之间的桥梁。当你打开一个 Python 文件且 filetype plugin on 已启用,Vim 自动加载 ftplugin/python.vim。
系统自带的 ftplugin 在 $VIMRUNTIME/ftplugin/ 下,但你应该把自定义的放在用户目录:
shell~/.vim/ftplugin/python.vim " Linux/macOS ~/vimfiles/ftplugin/python.vim " Windows
一个典型的 ftplugin 长这样:
vim" ftplugin/python.vim setlocal expandtab setlocal shiftwidth=4 setlocal softtabstop=4 setlocal textwidth=88 setlocal commentstring=#\ %s
注意用 setlocal 而非 set,这样设置只作用于当前 buffer,不会污染其他文件类型。
如果你想覆盖系统 ftplugin 的某些设置而非完全替换,用 after/ 目录:
shell~/.vim/after/ftplugin/python.vim
Vim 加载顺序是:系统 ftplugin → 用户 ftplugin → after/ftplugin,后面可以覆盖前面的设置。
syntax 目录:自定义语法高亮
语法高亮文件放在 ~/.vim/syntax/ 下,文件名就是 filetype 值。比如为一种叫 mylang 的自定义语言写高亮:
vim" syntax/mylang.vim syntax keyword mylangKeywords if else while for return syntax keyword mylangTodos TODO FIXME XXX syntax match mylangNumber "\<\d\+\>" syntax region mylangString start=+"+ end=+"+ highlight default link mylangKeywords Statement highlight default link mylangTodos Todo highlight default link mylangNumber Constant highlight default link mylangString String
几个要点:
- 用
highlight default link而非highlight link,前者不会覆盖用户配色方案里的定义,后者会强制覆盖 - 语法组按语义命名(Statement、Constant、Todo),不要按颜色命名,这样换配色方案时不会出问题
- 如果不想从零写,可以用
syn include把现有语法定义嵌入进来,比如在模板文件里同时高亮 HTML 和 JavaScript
indent 目录:控制缩进行为
缩进文件放在 ~/.vim/indent/ 下,同样以 filetype 命名。系统自带的缩进脚本已经覆盖了主流语言,你通常不需要自己写。
但如果你想微调,可以在 ftplugin 里用 setlocal 调整:
vim" ftplugin/go.vim setlocal noexpandtab setlocal shiftwidth=4 setlocal tabstop=4
或者写一个完整的 indent 脚本放在 ~/.vim/indent/ 下,利用 indentexpr 实现复杂的缩进逻辑。Vim 自带的 indent/python.vim 就是很好的参考。
自定义文件类型检测:ftdetect 目录
如果你在写一种 Vim 不认识的文件类型,需要告诉 Vim 怎么识别它。创建 ~/.vim/ftdetect/ 目录,在里面放检测脚本:
vim" ftdetect/mylang.vim autocmd BufNewFile,BufRead *.mylang setfiletype mylang
用 setfiletype 而不是 set filetype=,区别在于 setfiletype 只在 filetype 尚未设置时生效,不会覆盖已有的检测结果。
更复杂的检测可以检查文件内容:
vim" ftdetect/mylang.vim autocmd BufNewFile,BufRead * if getline(1) =~# '^#!.*/mylang' \ | setfiletype mylang \ | endif
推荐用 augroup 包裹以避免重复注册:
vimaugroup filetypedetect_mylang autocmd! autocmd BufNewFile,BufRead *.mylang setfiletype mylang augroup END
目录结构速查
把自定义的文件类型相关文件整理到一起,标准目录结构如下:
shell~/.vim/ ├── ftdetect/ │ └── mylang.vim " 文件类型检测规则 ├── ftplugin/ │ └── mylang.vim " 文件类型专属设置 ├── indent/ │ └── mylang.vim " 缩进规则 ├── syntax/ │ └── mylang.vim " 语法高亮定义 └── after/ └── ftplugin/ └── python.vim " 覆盖/补充系统 ftplugin
检测到 filetype → 加载 syntax → 加载 ftplugin → 加载 indent,这是 Vim 处理一个文件时自动执行的完整链路。
常见问题
检测对了但没高亮? 检查 :syntax 是否开启,以及配色方案是否支持你用的语法组。
改了 ftdetect 不生效? 改完重启 Vim,或者对当前 buffer 执行 :filetype detect 强制重新检测。
想临时禁用某个 ftplugin? 在 vimrc 里设 let g:did_load_filetypes = 1 可以阻止系统 ftplugin 加载,但更精准的做法是针对单个类型设 let b:did_ftplugin = 1 阻止加载,然后自己写替代脚本。
Vim 的文件类型系统看起来层级多,但拆开看每层职责清晰:ftdetect 负责识别,syntax 负责着色,ftplugin 负责行为,indent 负责格式。把它们配齐了,编辑体验和现代 IDE 比也不差什么。