vim中文件类型识别、语法高亮及缩进实现流程

摘要:
上面提到的突出显示和缩进需要首先识别文件类型,然后根据文件类型确定语法、突出显示和缩排。}其中使用的一些宏#ifndefFILETYPE_FILE#defineFILETYPE_FILE“filetype.vim”#endif#ifndef ftplugin_FILE#defineFTPLUGING_FILE“ftplugin.vim”#endif#ifndeffINDENT_FILE#defineINDENT_FILE“indent.vim”#endif III.filetype vim的主要内容在此文件中。它为文件打开和文件读取等事件注册自动处理功能。“Vim通常可以在开始时识别文件的脚本类型。
一、文件类型

在使用vim编辑一个文件的时候,如果能够识别出文件的类型,加上对应的高亮规则,可以使文件的查看更加醒目,这个功能几乎是使用vim浏览文件的一个核心诉求。
另外,在进行文件编辑的时候,特别是使用vim写代码的时候(典型的场景是通过vim写C/C++代码),如果能够智能缩进,还可以减少敲代码。例如,在每行的开头自动添加缩进与前一行对齐;或者是当在输入注释时(前一行是//或者/*),通常默认的缩进也会在当前行前面加上注释(//或者*),这也是很多开源软件中看到/**/风格注释中每行开头都有一个*的原因。
前面说的高亮和缩进,需要先识别出文件类型,然后根据文件类型确定语法、高亮、缩进。所以如何识别出这个文件的类型就是整个便利性的基础。不过话说回来,这些功能对vim这种编辑器来说都不是必须的,它们都是为了让使用更加便捷,所以这些功能的实现很多是通过插件来完成。

二、vim的filetype命令

在vim执行filetype命令时,vim执行的函数为ex_filetype,其中比较关键的时,它会找到filetype.vim脚本文件并执行,这个filetype.vim文件名是在代码中写死的。
/*
* ":filetype [plugin] [indent] {on,off,detect}"
* on: Load the filetype.vim file to install autocommands for file types.
* off: Load the ftoff.vim file to remove all autocommands for file types.
* plugin on: load filetype.vim and ftplugin.vim
* plugin off: load ftplugof.vim
* indent on: load filetype.vim and indent.vim
* indent off: load indoff.vim
*/
static void
ex_filetype(exarg_T *eap)
{
……
if (STRCMP(arg, "on") == 0 || STRCMP(arg, "detect") == 0)
{
if (*arg == 'o' || !filetype_detect)
{
source_runtime((char_u *)FILETYPE_FILE, DIP_ALL);
filetype_detect = TRUE;
if (plugin)
{
source_runtime((char_u *)FTPLUGIN_FILE, DIP_ALL);
filetype_plugin = TRUE;
}
if (indent)
{
source_runtime((char_u *)INDENT_FILE, DIP_ALL);
filetype_indent = TRUE;
}
}
if (*arg == 'd')
{
(void)do_doautocmd((char_u *)"filetypedetect BufRead", TRUE, NULL);
do_modelines(0);
}
}
……
}
其中用到的一些宏
#ifndef FILETYPE_FILE
# define FILETYPE_FILE "filetype.vim"
#endif
#ifndef FTPLUGIN_FILE
# define FTPLUGIN_FILE "ftplugin.vim"
#endif
#ifndef INDENT_FILE
# define INDENT_FILE "indent.vim"
#endif

三、filetype.vim的主要内容

在该文件中,注册了对于打开文件,读取文件之类事件的自动处理函数。它们主要通过文件名、文件后缀之类的信息来猜测文件格式。
runtimefiletype.vim
" Shell scripts (sh, ksh, bash, bash2, csh); Allow .profile_foo etc.
" Gentoo ebuilds and Arch Linux PKGBUILDs are actually bash scripts
au BufNewFile,BufRead .bashrc*,bashrc,bash.bashrc,.bash[_-]profile*,.bash[_-]logout*,.bash[_-]aliases*,*.bash,*/{,.}bash[_-]completion{,.d,.sh}{,/*},*.ebuild,*.eclass,PKGBUILD* call dist#ft#SetFileTypeSH("bash")
au BufNewFile,BufRead .kshrc*,*.ksh call dist#ft#SetFileTypeSH("ksh")
au BufNewFile,BufRead */etc/profile,.profile*,*.sh,*.env call dist#ft#SetFileTypeSH(getline(1))
当然也有一部分是通过文件的前几行来判断/确认
" Shell script (Arch Linux) or PHP file (Drupal)
au BufNewFile,BufRead *.install
if getline(1) =~ '<?php' |
setf php |
else |
call dist#ft#SetFileTypeSH("bash") |
endif

还有一些脚本类型文件的判断,通过第一行中的"#!"来判断脚本类型的。这也意味着可以对于"#!"开头的文件,vim通常能很好的识别出来脚本类型。
在脚本类型scripts.vim文件检测中
let s:line1 = getline(1)

if s:line1 =~# "^#!"
" A script that starts with "#!".

" Check for a line like "#!/usr/bin/env VAR=val bash". Turn it into
" "#!/usr/bin/bash" to make matching easier.
if s:line1 =~# '^#!s*S*<envs'
let s:line1 = substitute(s:line1, 'S+=S+', '', 'g')
let s:line1 = substitute(s:line1, '<envs+', '', '')
endif

四、syntax on指令的执行

vim-8.1srcsyntax.c
static void
syn_cmd_onoff(exarg_T *eap, char *name)
{
char_u buf[100];

eap->nextcmd = check_nextcmd(eap->arg);
if (!eap->skip)
{
STRCPY(buf, "so ");
vim_snprintf((char *)buf + 3, sizeof(buf) - 3, SYNTAX_FNAME, name);
do_cmdline_cmd(buf);
}
}

其中高亮文件夹
#ifndef SYNTAX_FNAME
# define SYNTAX_FNAME "$VIMRUNTIME/syntax/%s.vim"
#endif
在syntax.vim脚本中,注册了FileType事件,也就是当设置了文件类型之后会执行的命令,这个命令会触发set syntax=XXX命令的执行,而该命令进而触发颜色的高亮。
vim-8.1 untimesyntaxsyntax.vim
" Load the Syntax autocommands and set the default methods for highlighting.
runtime syntax/synload.vim
……
" Set up the connection between FileType and Syntax autocommands.
" This makes the syntax automatically set when the file type is detected.
augroup syntaxset
au! FileType * exe "set syntax=" . expand("<amatch>")
augroup END

if (save_ei != NULL)
{
au_event_restore(save_ei);
apply_autocmds(EVENT_SYNTAX, curbuf->b_p_syn,
curbuf->b_fname, TRUE, curbuf);
}

五、缩进(indent)

当执行filetype indent on时,执行的命令为:
static void
ex_filetype(exarg_T *eap)
{
……
if (*arg == 'o' || !filetype_detect)
{
source_runtime((char_u *)FILETYPE_FILE, DIP_ALL);
filetype_detect = TRUE;
if (plugin)
{
source_runtime((char_u *)FTPLUGIN_FILE, DIP_ALL);
filetype_plugin = TRUE;
}
if (indent)
{
source_runtime((char_u *)INDENT_FILE, DIP_ALL);
filetype_indent = TRUE;
}
}
……
}

在indent.vim脚本中,也注册了对于文件类型设置的侦听。
runtimeindent.vim
augroup filetypeindent
au FileType * call s:LoadIndent()
func! s:LoadIndent()

六、通过set ft=XXXX触发的事件流

从这个流程上看,该动作执行之后,触发的事件为EVENT_FILETYPE自动事件,如果希望处理这个事件,可以注册对于该事件的自动命令。由于indent和syntax都注册了对这里抛出的FileType事件的侦听,所以当设置了文件类型,语法和缩进开启的情况下,它们会自动生效。
vim-8.1srcoption.c
static char_u *
did_set_string_option(
int opt_idx, /* index in options[] table */
char_u **varp, /* pointer to the option variable */
int new_value_alloced, /* new value was allocated */
char_u *oldval, /* previous value of the option */
char_u *errbuf, /* buffer for errors, or NULL */
int opt_flags) /* OPT_LOCAL and/or OPT_GLOBAL */
{
……
else if (varp == &(curbuf->b_p_ft))
{
/* 'filetype' is set, trigger the FileType autocommand.
* Skip this when called from a modeline and the filetype was
* already set to this value. */
if (!(opt_flags & OPT_MODELINE) || value_changed)
{
static int ft_recursive = 0;

++ft_recursive;
did_filetype = TRUE;
// Only pass TRUE for "force" when the value changed or not
// used recursively, to avoid endless recurrence.
apply_autocmds(EVENT_FILETYPE, curbuf->b_p_ft, curbuf->b_fname,
value_changed || ft_recursive == 1, curbuf);
--ft_recursive;
/* Just in case the old "curbuf" is now invalid. */
if (varp != &(curbuf->b_p_ft))
varp = NULL;
}
}
……
}

免责声明:文章转载自《vim中文件类型识别、语法高亮及缩进实现流程》仅用于学习参考。如对内容有疑问,请及时联系本站处理。

上篇题解 CF1361B Johnny and GrandmasterMayaLearn0006: 多边形曲线曲面建模 高脚杯曲面建模 变形工具下篇

宿迁高防,2C2G15M,22元/月;香港BGP,2C5G5M,25元/月 雨云优惠码:MjYwNzM=

相关文章

Vim的字符编码设置

Vim编码方式的设置 和所有的流行文本编辑器一样,Vim 可以很好的编辑各种字符编码的文件,包括UCS-2、UTF-8 等流行的 Unicode 编码方式。但是,这需要用户自己动手设置。  Vim有四个跟字符编码方式有关的选项,分别是:encoding、fileencoding、fileencodings、termencoding (这些选项可能的取值请...

vim相关命令单独记载

1. 无敌的可扩展性 1.1 可扩展性给了软件强大的生命 曾几何时,Windows用户对软件的可扩展性没有概念,他们只能对他们使用的软件进行非常有限的定制。扩展软件的权利保留在软件开发者手中。软件的使用者如果想要新的功能和特性,只能等待软件的升级。有能力的用户等不及了,为了添加自己想要的功能,从0开始写了一款新的软件。就这样,新的功能意味着新的软件,Wi...

highlight.js 代码高亮插件

官网:https://highlightjs.org/ API:http://highlightjs.readthedocs.org/en/latest/api.html 1. 简单使用: <link rel="stylesheet" href="http://t.zoukankan.com/path/to/styles/default.css"&g...

Linux中的vim常见操作

Vim是Linux中一种重要的文本编辑工具,它有三种模式,有的分为命令模式、编辑模式和底行模式,也有分为一般模式,编辑模式和命令模式,其中后者的一般模式就相当于前者的命令模式,都是通过vim命令进入,后者的命令模式相当于前者的底行模式,都是通过: ? /三种方式进入的,下面按照后者划分方式整理下,以下基于centos版本。 一般模式 一般模式下可以做光标移...

pycharm的小问题之光标

一大早起来,突然发现pycharm的光变粗,按退格键会删除编写的内容,超级难受(如下图),百度一下,也不知道在百度框里输什么关键字好,但最后还是找到了,哈哈.... ​ 解决方法: 1、按键盘上Insert键; 2、如果是笔记本的话,就是按shift+0(我的笔记本上的0键上有个Insert单词) 被人问道新建py的时候也是有粗光标(俗称是插入模式)的怎么...

表示不同文件类型的魔术数字

这里所说的表示不同文件类型的魔术数字,指定是文件的最开头的几个用于唯一区别其它文件类型的字节,有了这些魔术数字,我们就可以很方便的区别不同的文件,这也使得编程变得更加容易,因为我减少了我们用于区别一个文件的文件类型所要花费的时间。 比如,一个JPEG文件,它开头的一些字节可能是类似这样的”ffd8 ffe0 0010 4a46 4946 0001 010...