Vim技能修炼教程(2) - 语法高亮速成

语法高亮速成

我们继续在人间修行Vim技能之旅。上一次我们学习了如何通过vundle安装插件,这次我们迅速向写插件的方向挺进。

我们先学习一个最简单的语法高亮插件的写法。
语法高亮基本上是由三部分组成:

  • 配色方案
  • 正则表达式
  • 配色方案和正则表达式的规则对应关系

简单的三步法写语法高亮

第一步,写匹配的正则表达式

我们举个最简单的例子,以Android的log为例,Android的log格式如下:

--------- beginning of system
05-05 17:55:48.909 I/ActivityManager( 2454): Start proc 15530:com.ss.android.article.lite:pushservice/u0a69 for service com.ss.android.article.lite/com.xiaomi.push.service.XMPushService
05-05 17:55:48.920 V/Build   (15530): clr
05-05 17:55:48.933 D/CompatibilityInfo( 2454): mCompatibilityFlags - 0
05-05 17:55:48.933 D/CompatibilityInfo( 2454): applicationDensity - 640
05-05 17:55:48.933 D/CompatibilityInfo( 2454): applicationScale - 1.0

从中可以看到,前面先是一个时间戳,然后是log的类型,接着是Tag,进程号和具体内容。

最简单的做法,我们就只取log类型和后面的"/"这两个特征,正则表达式这样写:

syn match LogF '\<F/.*'
syn match LogE '\<E/.*'
syn match LogW '\<W/.*'
syn match LogI '\<I/.*'
syn match LogD '\<D/.*'
syn match LogV '\<V/.*'

其中,'<'表示匹配一个单词的词首。详细信息可以通过:help \<来查询,在帮助的pattern.txt中。

第二步,为场景配色

下面,我们需要为这些匹配的场景定义颜色:
有四种属性可以使用:

  • ctermfg: 在终端时运行的前景色
  • ctermbg: 终端时的背景色
  • guifg: 图形界面的前景色
  • guibg: 图形界面的背景色
    定义格式:hi def 配色名 {颜色列表}
    hi def是highlight default的缩写

例:

hi def LogF_color ctermfg=white guifg=white ctermbg=red guibg=red
hi def LogE_color ctermfg=red guifg=red
hi def LogW_color ctermfg=brown guifg=brown
hi def LogI_color ctermfg=grey guifg=grey
hi def LogD_color ctermfg=darkcyan guifg=darkcyan
hi def LogV_color ctermfg=grey guifg=grey

第三步,将配色和正则表达式映射在一起

使用hi def link命令,将第一步和第二步的成果链接在一起就好了。

hi def link LogF LogF_color
hi def link LogE LogE_color
hi def link LogW LogW_color
hi def link LogI LogI_color
hi def link LogD LogD_color
hi def link LogV LogV_color

注:上述代码引用自:https://github.com/serpent7776/vim-logcat/blob/master/syntax/logcat.vim
非作者原创,版权归原作者所有。

更复杂一点的例子

看了最简单的一个实现,我们当然还可以做得更复杂一些:
我们参考一个更复杂一些的例子:https://github.com/gburca/vim-logcat/blob/master/syntax/logcat.vim

" Vim syntax file
" Language:     Android LogCat and aplogd log file syntax
" Maintainer:   Gabriel Burca <gburca dash vim at ebixio dot com>
"
" adb logcat -v time *:V
" 06-09 14:36:00.000 V/AlarmManager( 1484): sending alarm {957ff72 type 3 *alarm*:android.intent.action.TIME_TICK}
" 06-09 10:42:06.729 I/chatty  ( 1484): uid=1000(system) Binder:1484_5 expire 1 line
"
" Or for aplogd logs (syntax group names end with '2'):
" 06-08 16:17:56.101   566   566 E NEW_BHD : Open /sys/class/power_supply/gb_battery
" 06-08 16:17:55.183 18677 20835 D ACDB-LOADER: ACDB -> ACDB_CMD_GET_AFE_COMMON_TABLE
" 06-08 16:17:55.183 18677 20835 D         : ACDBFILE_MGR:Read the devices count as zero, please check the acdb file

if exists("b:current_syntax")
  finish
endif

...

syn match   lcBegin       display '^' nextgroup=lcDate

" Example:
" 06-09 10:42:06.729 I/chatty  ( 1484): uid=1000(system) Binder:1484_5 expire 1 line
" ^^^^^^
syn match   lcDate        '[0-1]\d-[0-3]\d '
                                \ nextgroup=lcTime

" Example:
" 06-09 10:42:06.729 I/chatty  ( 1484): uid=1000(system) Binder:1484_5 expire 1 line
"       ^^^^^^^^^^^^^
syn match   lcTime        '[0-1]\d:[0-5]\d:[0-5]\d\.\d\d\d '
                                \ nextgroup=lcTag,lcThread2

" Example:
" 06-09 10:42:06.729 I/chatty  ( 1484): uid=1000(system) Binder:1484_5 expire 1 line
"                    ^
syn match   lcPriority    '\(V\|D\|I\|W\|E\|F\)[\/ ]'me=e-1
                                \ containedin=lcTag nextgroup=lcTag2

" Must come after lcPriority so it has higher match priority
syn match   lcTagError    'E\/[[:alnum:]_-]\+'
                                \ containedin=lcTag
" Example:
" 06-08 16:17:56.101   566   566 E NEW_BHD : Open /sys/class/power_supply/gb_battery
syn match   lcTagError2   'E [^:]\+:'
                                \ nextgroup=lcMsgBody

" The component may be empty in some cases
" Example:
" 06-09 10:42:06.729 I/chatty  ( 1484): uid=1000(system) Binder:1484_5 expire 1 line
"                      ^^^^^^
syn match   lcComponent   '\/[^[:space:](]\+'ms=s+1
                                \ containedin=lcTag


" Example:
" 06-09 10:42:06.729 I/chatty  ( 1484): uid=1000(system) Binder:1484_5 expire 1 line
"                    ^^^^^^^^^^
" 06-09 10:42:06.729 I/        ( 1484): Message with empty component
"                    ^^^^^^^^^^
syn match   lcTag         '\w\/[^(]*\s*'
                                \ nextgroup=lcThread contains=lcTagError,lcPriority,lcComponent,myTags

" Example:
" 06-08 16:17:55.183 18677 20835 D ACDB-LOADER: ACDB -> ACDB_CMD_GET_AFE_COMMON_TABLE
"                                 ^^^^^^^^^^^^
" 06-08 16:17:55.183 18677 20835 D         : ACDBFILE_MGR:Read the devices count as zero, please check the acdb file
"                                 ^^^^^^^^^
syn match   lcTag2        ' [^:]*\s*:'
                                \ nextgroup=lcMsgBody contains=myTags

" Example:
" 06-09 10:42:06.729 I/chatty  ( 1484): uid=1000(system) Binder:1484_5 expire 1 line
"                              ^^^^^^^^
syn match   lcThread      '(\s*\d\+):'he=e-1
                                \ nextgroup=lcMsgBody contains=lcNumber
" Example:
" 06-08 16:17:55.183 18677 20835 D ACDB-LOADER: ACDB -> ACDB_CMD_GET_AFE_COMMON_TABLE
"                    ^^^^^^^^^^^^
syn match   lcThread2     '\s*\d\+\s\+\d\+ '
                                \ nextgroup=lcPriority,lcTagError2 contains=lcNumber

" Example:
" 06-09 10:42:06.729 I/chatty  ( 1484): uid=1000(system) Binder:1484_5 expire 1 line
"                                      ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
syn match   lcMsgBody     contained ' .*'
                                \ contains=myKeywords

syn match   lcNumber      contained '0x[0-9a-fA-F]*\|\[<[0-9a-f]\+>\]\|\<\d[0-9a-fA-F]*'

hi def link lcDate        Comment
hi def link lcTime        SpecialComment

hi def link lcTag         Statement
hi def link lcTag2        Statement
hi def link lcPriority    Identifier
hi def link lcTagError    Error
hi def link lcTagError2   Error
hi def link lcComponent   Normal

hi def link lcThread      Special
hi def link lcThread2     Special

hi def link lcMsgBody     Normal
hi def link lcNumber      Number

hi def link myTags        Function
hi def link myKeywords    Function

与上一个完全自定义颜色不同,这位作者直接将正则表达式映射到语言的预定义配色方案中。比如Comment是注释,Statement是语句,Identifier是标识符等等。具体可以通过:help syntax来学习,我们后面晋阶上仙的教程里也会有详细介绍。
总而言之,这个的正则表达式更复杂了,但是基本原理还是一样的。

例三

下面我们再趁热打铁,来看一个更复杂,也更人性化的例子:https://github.com/thinca/vim-logcat/blob/master/syntax/logcat.vim

我们来看下面一段,根据背景是不是暗的配色而设计两套配色方案,非常贴心:

function! s:define_color()
  if &background is 'dark'
    highlight default logcatLevelVerbose guifg=Gray   ctermfg=Gray
    highlight default logcatLevelDebug   guifg=Cyan   ctermfg=Cyan
    highlight default logcatLevelInfo    guifg=Green  ctermfg=Green
    highlight default logcatLevelWarning guifg=Yellow ctermfg=Yellow
    highlight default logcatLevelError   guifg=Red    ctermfg=Red
  else
    highlight default logcatLevelVerbose guifg=DarkGray   ctermfg=DarkGray
    highlight default logcatLevelDebug   guifg=DarkCyan   ctermfg=DarkCyan
    highlight default logcatLevelInfo    guifg=DarkGreen  ctermfg=DarkGreen
    highlight default logcatLevelWarning guifg=DarkYellow ctermfg=DarkYellow
    highlight default logcatLevelError   guifg=DarkRed    ctermfg=DarkRed
  endif
  highlight default logcatLevelFatal guifg=White ctermfg=White guibg=Red ctermbg=Red
endfunction

小结

小结一下,我们这节只学习三个命令:

  • syntax match: 正则表达式和场景匹配
  • highlight default: 为场景定义配色
  • highlight link: 将上两者联系在一起,也可以链接到预定义的一些标准配色方案上
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 212,884评论 6 492
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 90,755评论 3 385
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 158,369评论 0 348
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 56,799评论 1 285
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 65,910评论 6 386
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 50,096评论 1 291
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 39,159评论 3 411
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 37,917评论 0 268
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,360评论 1 303
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 36,673评论 2 327
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 38,814评论 1 341
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 34,509评论 4 334
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 40,156评论 3 317
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,882评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,123评论 1 267
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 46,641评论 2 362
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 43,728评论 2 351

推荐阅读更多精彩内容