oeasy教您玩转vim - 90 - # 语法定义syntax
内容查找 grep
回忆
我们这次研究了一下配色方案
murphy虽然配色好看
但是对于java的支持并不好
我们对于murphy进行了修改
增加了
String
、StorageClass
颜色的定义整体思路是在syntax中定义组
然后在配色方案中对于组进行颜色设置
可是syntax中如何定义组的呢?🤔
语法文件
vi /usr/share/vim/vim81/syntax/java.vim
先把配色方案设置为murphy
:colorscheme murphy

我们可以看见这个java语法文件的:
作者
github地址
修改时间
然后就是大量的syn定义

什么是
syn
呢?
syntax语法
h syn

syntax
就是语法:syntax list
可以列出syntax item 语法项
syntax group 语法组
syntax cluster 集群
我们来试试
syntax list 语法列表
:syntax list

语法项目都是用help打头的
为什么呢?
先q跳出去
:set filetype?
可以知道目前的文件是help文件
所以语法项目都是用help开头的
:q
跳出help文件回到java.vim
java.vim
在打开java.vim的情况下运行
:syntax list

因为当前打开的是.vim文件
所以得到的语法项都是和vim有关
如果我们打开一个java文件呢?
oeasy.java
:e oeasy.java
:syntax list

为什么打开不同的文件就会有不同的语法项列表呢?
语法文件
语法列表是由语法文件来决定的
语法文件位于语法文件夹中
/usr/share/vim/vim81/syntax/

help的语法文件
/usr/share/vim/vim81/syntax/help.vim
vim的语法文件
/usr/share/vim/vim81/syntax/vim.vim
java的语法文件
/usr/share/vim/vim81/syntax/java
我们继续来看java的语法文件
关键字keyword
/\<public\>

syntax keyword javaScopeDecl public protected private abstract
java的
Scope可见性
Declaration描述
syntax 语法
keyword 关键字
javaScopeDecl
public protected private abstract 具体的关键字
vi oeasy.java
:colorscheme murphy
:hi javaScopeDecl ctermfg=brown

这样设置了public protected private abstract 这些关键字的颜色了
试验成功
我们可以自定义的一个属于自己的关键字么?
自定义关键字
:h syntax

这里是定义syntax语法项的地方
第一种语法项就是keyword
我们去定义一个自己的关键字
sudo vi /usr/share/vim/vim81/syntax/java.vim
自己的关键字keyword
syn keyword oeasy System
把System定义为oeasy这个类型的关键字
然后保存退出

重新打开
oeasy.java
:syntax list

可以发现在oeasy.java文件打开后
已经有了一个叫做oeasy的关键字类别
里面包含着System这个词
那如何给oeasy这个类别上色呢?
给oeasy列别上色
颜色模式设置为murphy
:hi oeasy ctermfg=yellow

试验成功
但是public对应的这个javaScope
又是如何与StorageClass挂上关系的呢?
层层关联
回到syntax中的
java.vim
/\<javaScopeDecl\>
9个匹配

这里有个
hi def link

就是对于高亮hilight组的链接

把javaScopeDecl、javaClassDecl、javaMethodDecl链接到了javaStorageClass上
这样,
:hi javaStorageClass cterm=white
就可以用到三组上面但是上图最上的一句话又是什么意思呢?
hi def link javaStorageClass StorageClass
组名通用化
:e /usr/share/vim/vim81/syntax/c.vim

我们可以看到不同语言有不同的语言的StorageClass
java的叫做javaStorageClass
c的叫做cStorageClass
rust叫做rustStorageClass
不管他们原来的名字如何,都映射到StorageClass
这样murphy、morning、blue等颜色方案只要设置StorageClass的高亮
就可以映射到不同语言的不同组里面了
像StorageClass这样的通用组名还有很多

如果我们做一门叫做oeasy的语言
就需要把关键字定义到oeasyStorageClass中
然后把oeasyStorageClass映射到StorageClass上
只要颜色方案中有关于StorageClass的定义
我们相关关键字就可以显示出来
除了keyword之外,还有什么样的高亮item的定义呢?
match 匹配模式

match顾名思义就是匹配模式
比如
syntax match javaComment /#.*/
/
是模式匹配的开始和结束#
代表#
如果是#开头的行,^#
如果是#开头的单词,\<#
.
任意字符*
代表任意字符.
的数量是0到任意多个javaComment
是高亮项名称/#.*/
/match

javaBraces 对应的是左右大括号
"[{}]"
""里面是pattern
[]里面是或的关系
{}是左或右大括号
匹配import 或者 import static
这里怎么引号外面还有东西呢?
偏移量 offset
"\.\s*\<class\>"
\.
开头有任意字符\s*
然后有0到任意多个空格或tab然后是独立单词class
ms的意思是Match Start匹配头
ms=s+1是什么意思
s是start
ms=s+1
就是把
\s*
前面的\.
去掉开始定义匹配的开始我们再看一个
javaCommentStar
match 的思路是匹配一个模式
^\s* 行开头有空格或者tab
然后后面有一个不是/的字符
这个时候要把结尾的位置me
设置为e-1
也就是不包含这个非/的字符
:hi javaCommentStar ctermbg=red
红色的就是对应的javaCommentStart的区域
匹配了就进入组
除了match直接匹配之外
还有什么定义高亮组的方法么?
region 区域
最重要的有三个属性
start开头
end结尾
skip 跳过的
start=+"+
+是分隔符号相当于/
pattern是"
以"为开头
end=+"+"
同上
以"为结尾
skip=+\"+
分割符还是+
中间如果有\"就跳过
不作为结尾
echo "i say \"oeasy\"" #echo sth
匹配
"i say \"oeasy\""
region带偏移量
高亮开始
hs highlight start 高亮开始位置
e 是end 指的是start开始模式
/\*
的结束位置e+1指的是
/*
后面一个字符的位置hs=e+1 高亮开始于开始模式末尾后一个字符
高亮结束
he highlight end 高亮结束位置
s 是 start 指的是end结束模式
\*/
的开始位置s-1 指的是
*/
前面一个字符的位置he=s-1 高亮结束于结束模式开头前一个字符

匹配模式match的是
mmm...mmm
的位置匹配高亮的region是
rrr
对应的位置除了region之外,还有什么高亮组的定义方法么?
嵌入的高亮组

xComment
x语言的注释
%开始的都是注释
注释里面可以包含TODO
xTODO
x语言的TODO
TODO高亮组只能存在于注释里面
不在注释里面的不是TODO高亮组
递归嵌入

xBlock
x语言的Block块
大括号包起来的都是Block
Block可以自身递归嵌套
统一截行 keepend

xComment
x语言的注释,从%到结尾$
xPreProc
x语言的预处理,从#到结尾$
可以包含xComment
蓝色部分把第二行也认为是预处理
因为第一行的结尾回车给了xComment
xPreProc就把第二行的结尾回车当作自己的了
为了避免这个情况
keepend

排除元素ALLBUT

contains里面可以放具体的高亮组
也可以放所有东西
如果要排除某些东西怎么办呢?

下一组nextgroup

这三个东西必须挨着
在一起
各自才能成立
匹配组 matchgroup

第一种模式定义了一个组
包括括号和括号里面的内容
第二种模式生成了两个组
xInside
xParen
可以分别上色
透明transparent
如果你想要while和for循环的条件有不同颜色
可以这样试试

for、while各有一套
cCondNest本身是透明的
跟着上一层高亮组走
行内oneline

oneline就是一行
保证这个匹配的模式必须在一行以内
有一行那有没有多行呢?
多行

多行里面包含了xLineContinue
xLineContinue包含了
\\$
换行符被包含在了高亮组里
于是高亮组可以换行了
集群cluster

contains里面的东西是重复的
可以定一个集群cluster

然后contains里面就用集群

集群本质上是高亮组的列表
这个列表可以添加和删除

更多语法
比如你打开一个cpp文件
文件缓冲被解析为cpp的高亮组
但是我同时想用c的高亮组
怎么办?

什么是runtime呢?
运行时环境
syntax/c.vim
在运行时环境里面找syntax/c.vim
运行时环境是什么?
:echo $VIMRUNTIME
/usr/share/vim/vim81
这是一切的来源
语法文件的来源
高亮颜色模式的来源
缩进的来源
如果出现了问题
可以去看看这里是不是正确
总结
这次我们彻底研究了vim高亮的原理
各种语法项syntax item
关键字keyword
匹配模式match
区域region
定义好了之后还可以设置链接成组
hi def link javaComment Comment
然后就可以在颜色文件中具体配色了
比如murphy中对于Comment的定义
hi Comment ctermfg=yellow
不同的语言可以有不同的语法定义
其实,vim也是门语言
vimscript也是可以编程的
怎么玩呢?🤔
下次再说!