高亮::Vim進階索引[5]

helloxchen發表於2010-10-22

Vim進階索引[5]::高亮

與以前的教程相比,這一篇做了一些小改變:使用了縮寫而不是每次都給出完整的命令。提示使用文件時不同給出完整的命令而是給出“關鍵字”——你可以用“:h 關鍵字”的方式找到Vim文件中的相應內容。

hq00e

在語法高亮相信大家在使用Vim的文件時就已經見過了,Vim提供了一個測試用的指令碼。輸入下面的命令:

   :e $VIMRUNTIME/syntax/colortest.vim
   :so %

這個指令碼除了讓你知道Vim是可以顯示許多顏色的外,它還是一個實時定義顏色的指令碼例項。在本文的末尾我們會用同樣的技巧生成一個Web色表。

Vim中與色彩有關的設定大致可以分為兩部分:

  • Vim編輯環境配色。如Vim編輯區的前景背景顏色(文字的預設顏色)、狀態列顏色、錯誤提示顏色、游標、圈選區(可視區)、行號、摺疊的顏色等。這些都屬於編輯器的環境設定。
  • 檔案使用的所使用的色彩。即所謂的語法高亮/語法著色,如Vim文件中索引標籤使用粉紅色,示例使用藍色、連結使用青色。或是當你開啟C語言檔案時,註釋藍色、資料型別青色、字串粉紅、關鍵字赭色。都是Vim根據檔案型別啟用相應的語法檔案,對該應用顏色的部分進行識別並著色。

本文將透過對這些色彩進行設定的例項,讓使用者逐步瞭解與色彩相關的命令。

1 環境配色

Vim的環境配色決定了使用者編輯環境的基本風格。語法高亮可以關閉但環境配色是始終存在的,下面我們將逐步地改造並定義屬於自已的配色風格。

1.1 使用預置的配色風格

要改變Vim的編輯環境的配色很容易因為Vim提供了多種預置的配色風格(顏色主題)。比如要使用'evening'風格:在選單中選擇“編輯-調色盤-evening”。或者在命令列中使用:colorscheme命令1

:colors evening

可以看到編輯環境包括編輯區的前景背景的顏色都發生了變化。命令列下Vim預設是黑底白字,圖形下的Vim是白底黑字,在應用了上面的命令後都成了深灰的背景,銀灰的前景。

提示:在選單中選擇“default”或使用命令:colors default,換回預設的配色。關鍵字::colorscheme

1.2 修改環境配色

如果你不滿足於使用現成的顏色主題的話,那我們來看一下如何修改環境配色。首先要掌握的命令是:highlight。

" 使用預設的高亮(移除使用者定義的高亮,即根據'ft'重新載入語法檔案)
:hi clear 
	
" guifg表示圖型介面(gui)下的前景色(ForeGround)
" guibg表示圖型介面(gui)下的背景色(BackGround)
:hi {組} guifg={值} guibg={值}
	
" 進行顏色關聯。
" 這條命令使{組1}使用與{組2}一樣的顏色設定
:hi link {組1} {組2}

例如,要將“組”為“c_name”的組在圖形介面下的顏色設定為背景黑色,前景灰色可用如下命令:

:hi c_name guifg=gray guibg=black

讓組“c_blah”使用與“c_name”一樣的顏色設定:

:hi link c_blah c_name

注意:目前我們只涉及圖形介面下Vim(gVim)的色彩控制。所以本文接下來的例子,在我們講到命令列下的顏色設定之前,所有例子都是在gVim環境中完成的。

忘了解釋一下“組”(高亮組)是什麼?有什麼用?Vim中“組”被用來表示一組顏色設定(前景、背景、字型、風格)。當某個介面元素(或是編輯區中的文字)應用了特定的“組”後,它就根據“組”表示的顏色設定來顯示。應用了同樣“組”的介面元素或文字會有一樣的顏色顯示。有:hi為“組”分配顏色時,如果組已存在則覆蓋原有的設定,否則定義新組。

現在我們知道透過賦於guifg和guibg顏色值為組分配顏色。哪到底可以使用哪些顏色呢?圖形介面下的顏色有“名稱”或“數值”兩種表示方式。名稱如上面所用的gray、black還有大家熟悉的red、white、yellow,更多可以使用的顏色名稱見文件:gui-colors。顏色還可以用“數值”來表示,方法是用三個分別表示“紅、黃、藍”的十六進位制數值表示。如red還可以表示為#ff0000。記得數值前要加上#號。沒錯,這與html檔案中顏色的表示方法是一樣的。用這種方法我們可以表示更多的顏色:

" 將前景改為淡紫色
:hi c_name guifg=#E6E6FA

提示:此外guifg/guibg還支援三個特殊的值:none、fg、bg,分別表示無顏色、編輯區一般文字的前景色、一般文字的背景色。

要改變Vim的配色我們需要知道都有哪些組可以改。下面表中是Vim環境配色中介面元素所應用的“組”(組名在前):

Cursor
游標
ErrorMsg
命令列中的錯誤提示
Folded
摺疊行
LineNr
行號
NonText
非文字區(控制字元和一些特殊字元和編輯器空白區等)
Normal
編輯區一般文字的前景和背景色
Search
搜尋
StatusLine
狀態行
Visual
圈選區

提示:完整的列表見highlight-groups。非Windows使用者還可以設定選單、捲軸和提示框的顏色。見hl-menu。

現在做個實驗,開啟一個文件並依次輸入下面的命令,觀察變化:

:se ft= "關閉高亮
" 分別改變編輯區的前景色(guifg)和背景色(guibg)為灰色和紅色
:hi Normal guifg=gray guibg=red
" 修改背景色為暗灰色,上面設定的前景色將被保留
:hi Normal guibg=#333333
	
"顯示狀態行
:se laststatus=2
" 設定狀態行的顏色。
" 如果沒“gui=none”會發現狀態行的前/背景色顛倒了。
" 關於gui我們稍後再說
:hi Statusline guifg=green guibg=gray gui=None
" 狀態列的預設顏色
:hi statusline gui=bold,inverse guifg=fg guibg=bg
" 使錯誤提示使用與狀態列一樣的顏色設定(預設是紅色)
" 用hi link對已定義顏色的組重新定義顏色要加“!”
:hi! link ErrorMsg statusline
" 下面的命令會出錯,錯誤提示成了綠色的
:hi link
" 清除顏色。
:hi! link ErrorMsg none
" 無顏色的錯誤提示
:echoerr "abc"
" 恢復預設的顏色
:hi clear

注:“:hi link {組} NONE”是:hi link的一種用法,用來清除組的顏色關聯。

2 語法高亮

前面我們講了如何更改Vim環境配色,如游標,狀態行,錯誤提示的顏色。並沒有涉及到如何根據編輯的檔案來顯示不同顏色,即語法高亮。與更改配色相比設定語法高亮要更復雜一些:配色中更改的組是確定的,因為編輯器中的介面元素是固定的,而語法高亮中所開啟檔案中那些需要高亮那些不需要,以及對不同型別的檔案應用不同的語法高亮都要視具體的檔案而定。很多時候我們還需要“創造”(自定義)出一些組來。但與配色一樣在語法高亮中顏色的顯示依然是由:hi命令控制。

2.1 修改當前的高亮設定

這一節我們將對當前文字中的語法高亮進行修改,你會發現這與修改環境配色相似——所不同的只是“組”名。這是一組實驗:

:h syntax.txt "開啟Vim文件
:hi helpHyperTextJump guifg=darkblue "改變文件中連結的顏色
:hi clear
"清除自定義顏色——包括上面的顏色
:hi! link helpHyperTextJump Identifier "恢復顏色

所以要定義顏色只要對相應的組名的顏色進行設定就行了。那你要問了,這個helpHyperTextJump是從哪來的我怎麼會知道哪個的組名是哪個?如果我要定義自已的組名呢?
要檢視當前的語法檔案中定義了哪些組名可以用不帶引數的:hi檢視。此外,還可以用:

" 檢視當前的檔案型別(假設是texinfo檔案)。
:se ft
texinfo
" 知道是texinfo檔案後,使用以下命令開啟相應的語法檔案
" 在語法檔案中,:syn命令後跟的就是組名。
:e $vimruntime/syntax/texinfo.vim

那使用者該怎麼定義自已的組呢?繼續往下看吧……

2.2 定義新的高亮

在定義新的高亮組時我們要先回答這個問題:為什麼要定義新的組呢?有很多可能的原因:其中之一是我們想在不修改原來的高亮的情況下增加一種色彩,為些我們需要定義新的高亮組,並分配適當的顏色。
現在我們要定義自已的組了,首先要為我們自定義的組取個名字,組的命名與變數一樣只能由字元下劃線和數字組成(雖然我們前面的例子中使用了不同的大小寫,但組名是不區分大小寫的)。下面的命令中我們定義了一個組名為“mygroup”的組2
:hi mygroup guifg=#ff9999
這條命令告訴Vim將mygroup組的字串顏色定義為淡紅色(lightred)。但Vim現在還不知道哪些字串屬於mygroup,所以我們得告訴Vim——方法是使用:match命令:
:match mygroup /xxx/
這條命令告訴Vim凡匹配式樣的xxx的字串都屬於mygroup。這樣當前檔案中所有匹配“xxx”的字串都會變成淡紅色。定義自己的顏色是不是很容易呢?先用:hi命令定義組及其使用的顏色。再用:match告訴Vim編輯區文字中哪些部分是屬於自定義組的。最後,Vim會根據:match設定的規則將當前編輯區文字分為許多不同的組(如果有定義多個組的話),並對不同的組應用:hi為其分配的顏色

下面我們要用一個更實際的例子來加深對語法高亮的印象。

看一下這個簡單的表格:

王小明	數學	46
李阿月	數學	72
林小麗	數學	91

這是某個班主任手中的成績單。他/她的班級有25個學生,這是其中的三條資料。這個班級經常有考試,這個老師希望考試的結果更直接明瞭一點:不及格(少於60分)的成績顯示為紅色,90分以上的成績有顯示為青色,這樣他/她就可以很快知道哪些學生該補課3,而哪些學生該表揚。當科目為數學時將科目顯示為藍色,這個班主任教數學的!學生名字顯示為粉紅色——看來這個班主任是女的。最後全班最高分的顏色反白顯示。
我們先取幾個不同的組名4:“u_student、u_subject、u_mark_fail、u_mark_a”分別表示“學生、科目、不及格、優秀”等。將這個表格另存為文字檔案並用gVim開啟,使用下面的命令:

:hi u_student guifg=#ff9999 guibg=white
:hi u_subject guifg=lightblue guibg=white
:hi u_mark_fail guifg=red guibg=white
:hi u_mark_a guifg=darkcyan guibg=white
" 上面的命令定義了不同的組及其對應的顏色
" 現在我們要用match告訴Vim怎麼分辨不同的組,
" 我們要用到一些的正規表示式
	
"行頭開始至第一個空白字元
:syn match u_student /^S*/
:syn match u_subject /數學/
:syn match u_mark_fail /s[1-5]=.$/
:syn match u_mark_a /s100|s9.$/

你可能發現了每條match命令前面都多了:syn。這是因為使用match命令時前一個match定義的組的顏色會丟失。用match命令你沒辦法同時顯示多種顏色。在上面的match命令前加上syn就行了,就可以顯示所有自定義的顏色了。

提示:其實:syntax match與:match是不同的命令,不過“目前為止”它們的語法是一樣的,我們在下一篇會講到:syntax命令。

現在我們為成績單加上顏色了,但下一次呢?我們可不希望每次開啟都手動設定,我們可以將之放進單獨檔案中。將上面的命令複製到單獨的檔案中,然後用:so命令執行就可以了。

2.3 寫語法檔案

我們在前面寫的指令碼,儲存起來就成了一語法檔案。我們使用:so命令就可以執行了,不過你也許還希望它像其他語法檔案一樣能自動載入。要做到這一點也很簡單。

在我們繼續之前我簡單描述一下語法檔案載入的機制。Vim讀入/新建檔案時根據字尾名判斷檔案型別(或者根據模式行中設定的'filetype'設定項判斷檔案型別),然後在$VIMRUNTIME/syntax/和$VIM/vimfiles/syntax/中查詢以檔案型別為檔名,.vim為字尾的檔案。找到的話載入該檔案。

所以語法檔案我們已經有了,我們只需要再選擇合適的檔案型別名。假設我們使用的檔案型別名是'u_mark',將上面的指令碼命名為u_mark.vim放到這個目錄中:$VIM/vimfiles/syntax/。然後要讓Vim開啟成績單時知道自動應用語法檔案。在學習autocmd和filetype的內容之前,在這裡我們可以簡單地使用模式行,來達到這個目的。在成績單檔案的末尾加入模式行:

   vim:ft=u_mark

現在開啟成績單檔案時Vim就會自動載入語法檔案。如果開啟成績單時還是沒出現語法高亮請確定已經開啟了語法高亮。使用:syn on開啟高亮,必要的話將之放到.vimrc中。

3 :highlight命令詳解

現在是對:hi進一步挖掘的時候了。

3.1 命令列下的顏色設定

在前面的內容中,我們講:hi命令時一直都是以圖形介面(gui)為例設定前景和背景色。由於命令終端對顏色顯示的限制,Vim在命令列下可以使用的顏色相對gui要少得多,所以使用:hi命令時圖形介面和命令列介面的顏色是分開設定的。對於黑白終端來說就無所謂顏色了,而彩色終端用cterm來表示,前景色就是“ctermfg”,而背景色是“ctermbg”。下面是一個表格:

終端型別    前景色      背景色      註釋
term         -          -           黑白終端
cterm       ctermfg     ctermgb     彩色終端
gui         guifg       guibg       圖形介面

在前面我們對編輯區文字的顏色進行了定義:
:hi Normal guifg=gray guibg=red
現在我們對其命令列下的顏色進行定義
:hi Normal ctermfg=gray ctermbg=red
我們可以簡單地寫成一行:
:hi Normal guifg=gray guibg=red ctermfg=gray ctermbg=red

有哪些顏色可以使用?見cterm-colors。

3.2 顯示樣式

:hi命令除控制顏色外還可以控制文字的顯示樣式。term、cterm和gui分別控制三種不同終端下的字型式樣。這些字型樣式包括了粗體、下劃線、斜體、反顯。使用多種樣式時將樣式用逗號隔開。詳細樣式見attr-list。

" 設定錯誤提示在不同終端下的顯示樣式
:hi ErrorMsg term=bold,reverse cterm=bold,reverse gui=reverse 
	
" 將某項的值設為NONE,可清除該項的樣式設定
:hi ErrorMsg term=NONE

需要注意的是gui下不支援粗體的樣式,但gui下多了一個字型的設定項font,用以指定字型::hi tung_poem font=……

另外因為Normal組是做為Vim的基準設定,所以對Normal進行的字型樣式設定將被忽略。

3.3 關於link

在使用:hi link命令時有幾個細節要注意一下。文件中都有(hi-link),這裡簡單提一下。仍是以命令“:hi link {組1} {組2}”為例:

  • 如果在關聯之前{組1}組已經定義過了了,則要使用加!號的形式:hi! link否則提示錯誤。
  • 當{組1}關聯到{組2}後,{組1}組使用與{組2}一樣的顏色設定。如果此時再用:hi對{組1}定義顏色,則關聯被取消。{組1}回覆到設定關聯前的顏色設定(如果有的話),再應用新定義的顏色。
  • default開關項。由於Vim有多個配置檔案,又有語法檔案定義顏色。所以一組顏色可能被多次定義,為了讓某一組顏色只在未定義時關聯到其他組。可以使用開關項default:
         :hi default link {組1} {組2}
    

    一般而言,後定義(關聯)的顏色總是覆蓋先定義(關聯)的顏色。在使用了這個開關項時,設定了default開關的總是被覆蓋。僅當其他地方未定義{組1}時,才使用該關聯。這主要是用在語法檔案中,語法檔案的載入要晚於配置檔案。當在配置檔案中定義顏色時,由於語法檔案較晚載入自定義的顏色總是被覆蓋。如果在語法檔案中使用了default,則配置檔案中自定義的顏色就能被顯示出來。

使用:hi link還能節省大量的時間,減少重複的勞動。完整的顏色定義通常較長,因為要兼顧各種終端的顯示能力。這是Vim中對Comment組的顏色定義:

  :hi Comment	term=bold cterm=NONE ctermfg=Cyan ctermbg=NONE gui=NONE guifg=#80a0ff guibg=NONE

如果每定義一種顏色都要寫這麼長就太折騰人了。避免這種情況的最好方法是利用好預定義的顏色。這些是Vim預定義的組、所表示的意義及其使用的顏色與樣式:

Comment 註釋
Constant 常量
Identifier 變數名
Statement 語句
PreProc 前處理器
Type 資料型別
Special 特殊符號
Underlined 突出顯示的文字
Ignore 無設定
Error 語法錯誤
Todo 待做事項

Vim的語法檔案本身就大量地使用了:hi link命令,它們大部就是關聯到上面所列的組。在上面成績單的例子中我們定義了u_subject在gui下的顏色為藍色,但使用下面這條命令我們除了達到同樣的效果外,還定義在其他終端下的顏色:

:hi! link u_subject Comment

所以在定義新的顏色時,先在上面的列表中看一看有沒有你需要的顏色,如果有的話又可以節省很多時間了。

4 綜合

現在看一下與語法高亮相關的幾個例子。

4.1 高亮tags

見文件:tag-highlight

4.2 生成web色索引

使用:hi命令和:syn match命令就可以讓Vim顯示出斑斕的色彩。現在我們要更進一步結合上面的兩個命令與Vim指令碼寫出一個217色的Web安全色表。

" 生成Web色表
" 用法:so web_color_gen.vim
" 限制:只能在gui中使用
" 注意:這個指令碼在Vim6.3/6.4中有時會出現顏色渲染錯誤的情況。
"       在Vim7中則沒發現類似情況。
	
" 關閉搜尋高亮
se nohls
	
" 定義陣列
" 在Vim7中定義陣列就不會這麼累了
let c0="00"
let c1="33"
let c2="66"
let c3="99"
let c4="cc"
let c5="ff"
	
" 生成web色的數值表
let L1=0
while L1<6
  let L2=0
  while L2<6
    let L3=0
    while L3<6
       exec "norm o" . ':s/^/=c{L1}.c{L2}.c{L3}." "/' . ""
      let L3=L3+1
    endw
    let L2=L2+1
  endw
  let L1=L1+1
endw
	
g/./exec 'hi '.expand("").' guifg=grey guibg=#'.expand("") |
     exec 'syn match '.expand("").' /'.expand("").' /'
	

新建空文件,然後執行指令碼就可以看到web色表了。

這裡有幾個地方我解釋一下。
exec "norm o" . ':s/^/=c{L1}.c{L2}.c{L3}." "/' . ""
這條命令在文件中新起一行,並用:s命令插入顏色值。關於:s命令的rhs中使用=在“暫存器”篇中我們已經講過了(見:sub-replace-special)。當L1、L2、L3分別為1、2、3時,這條命令就成了:
exec "norm o" . ':s/^/=c1.c2.c3." "/' . ""
其結果就是在當前行下插入了“336699 ”。在這三組迴圈執行完後文件區將會有如下的web色數值表:

000000
000033
...
ffffff

還有就是expand()。這個函式的作用是將一些特殊的符號擴充套件為該符號所表示的字串。expand("")將返回當前游標所在位置的“詞”。常見的用法還有expand("%")、expand("")等。篇幅所限,關於這個函式的用法見*expand()*。

g/./exec 'hi '.expand("").' guifg=grey guibg=#'.expand("") ……

g/./表示對所有非空行執行命令。假設當前行在“336699 ”,對這行執行“exec 'hi…. .expand("")”命令時,expand("")將被擴充套件為“336699”,這樣命令就成了:

hi 336699 guifg=grey guibg=336699

同樣的後面的:syn命令就成了syn match 336699 /336699 /。在執行完這組命令後Vim就會重新整理螢幕上的顏色了。

提示:這段程式碼只有在圖形介面下能發揮功用,在指令碼開頭加入這段程式碼以檢測執行環境:

if !has("gui")
    finish
endif

另外,在指令碼末尾新增下面程式碼可以使用web色表更易讀一點:

1d " 刪除空行
" 格式化顏色表,每行六種顏色。
g/./norm 6gJ

這是執行結果(部分):

660000 660033 660066 660099 6600cc 6600ff
663300 663333 663366 663399 6633cc 6633ff
666600 666633 666666 666699 6666cc 6666ff
669900 669933 669966 669999 6699cc 6699ff
66cc00 66cc33 66cc66 66cc99 66cccc 66ccff

4.3 其他應用

Vim定義的高亮還可以用以生成彩色的html文件或列印彩色文件。

  • 要生成html文件,只要先開啟高亮然後簡單的輸入:TOhtml命令就可以生成使用與當前顏色設定一樣的html文件了。TOhtml其實是一個外掛,除了簡單的用法,它其實還支援許多高階的控制選項如編碼,CSS等。這是非常值得使用者花點時間瞭解的命令——關鍵字“:TOhtml”。
  • :hardcopy命令會根據當前的色彩設定列印文件。此外在Linux/Unix中這個命令還可以用來生成PostScript文件。關鍵字“:hardcopy”。

5 小結

至此對於給定的組我們已經能決定它顏色的顯示了。然而,依賴:syn match加正規表示式的方式定義組仍有侷限——它不能針對組與組之間的關係作出調整,註釋的巢狀便是一例。這解決這些問題或者說要定義有更復雜規則的組我們需要對:syntax命令有進一步的瞭解。下一篇我們將深入高亮的另一重要命令:syntax並,定義更復雜的語法檔案。




Footnotes

[1] 其實Vim中的顏色檔案,配色檔案,語法檔案,配置檔案和外掛本質上都是指令碼檔案都可以用ru或so執行。colors命令可以認為是預設了目錄的so命令。

[2] 這裡用的命令格式與上面修改高亮時的命令格式是一樣的,它們的唯一區別在於使用的是否是新的組名。如前所述,Vim並不知道它是修改已有組的顏色設定,還是定義了新的組。要檢查特定的組是否已存在可以用:hi mygroup,如出現錯誤提示則說明在“當前應用的語法檔案”中不存在組mygroup

[3] 在我讀書的會兒老師會要求我們把錯的題目抄800-1000遍

[4] 沒錯,你可以按自己的意願選擇組名

[@more@]

來自 “ ITPUB部落格 ” ,連結:http://blog.itpub.net/24790158/viewspace-1040221/,如需轉載,請註明出處,否則將追究法律責任。

相關文章