閱讀872 返回首頁    go 阿裏雲 go 技術社區[雲棲]


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: 將上兩者聯係在一起,也可以鏈接到預定義的一些標準配色方案上

最後更新:2017-06-27 14:31:48

  上一篇:go  網站SEO優化:新網站如何篩選關鍵詞
  下一篇:go  股神是怎樣練成的?