2009/08/19

Vim tip: 使用快速鍵編譯C程式

上一篇,c9s大在COSCUP的投影片提供了一個編譯C/C++程式的快速鍵,如下:

nmap <C-c><C-c> :!gcc -Wall % -o %:r.exe<CR>

試用了一下覺得還不錯,唯一的缺點是錯誤訊息不會輸出到QuickFix視窗。所以我稍微的給他改了一下,如下,將以下寫入_vimrc,以後編譯改成輸入:make,即會用gcc編譯,且訊息會導至QuickFix視窗。

set mp=gcc\ -Wall\ %\ -o\ %:r.exe

COSCUP: Vim Hack

今年CUSCOP有一場talk在討論Vim Hack,投影片可以參考[這裡],這份投影片簡單易懂又能讓初次碰到Vim人的快速上手且了解Vim的美,非常推薦想要入門Vim能花些時間將[這份投影片]看過。

2009/08/10

Vim tip: 搜尋高亮度(search highlight)

VIM在搜尋時有個耳熟能詳的快速鍵*,它能搜尋游標所在字,同時若有設定高亮度搜尋字串(:set hls),搜尋到的字會反白,如下圖是在aaa按下*的截圖:



有時我們會希望將目前搜尋到的目標(如上的aaa)再增加新的游標所在字(如bbb),如下圖:



我們可藉由正規表示式的|來達到,但其實命令有點複雜,所以這裡我提供一個快速鍵sa,來完成此目的,請將下圖的script加入你的.vimrc。

map sa :exec "/\\(".getreg('/')."\\)\\\\|".expand("<cword>")<CR>

Git for Windows

最近將原先的Code base由SVN換到Git,基本上轉過去的路還算順利,Git用起來也是十分順手,而且也迅速的感受到Git的優點,像是快、分散式(本地端可commit)、分支容易。以下提供一些載點及入手時參考的文章。

2009/07/31

VIM script: Header and Source file Switching

在寫C/C++時常要在header及source file之間做切換,因此我寫了一個小script來做此事。

請將以下script加入_vimrc,以後做切換隻需輸入fh
map fh <esc>:call FileHeaderSource()<cr>

function! FileHeaderSource()
let fextname=expand("%:e")
let fname=expand("%:r")
if fextname=="h"
if filereadable(fname.".cpp")
exec ':e '.fname.".cpp"
return
endif
if filereadable(fname.".c")
exec ':e '.fname.".c"
return
endif
else
if filereadable(fname.".h")
exec ':e '.fname.".h"
return
endif
endif
echo "file not found"
endfunction

2009/04/02

輕輕鬆鬆寫VIM plugin: 流程控制 condition

IF
跟一般常見的語法一樣,請看下例:
:if &term == "xterm"
: " Do stuff for xterm
:elseif &term == "vt100"
: " Do stuff for a vt100 terminal
:else
: " Do something for other terminals
:endif


VIM最基本的判別式有以下這幾種:
a == b equal to
a != b not equal to
a > b greater than
a >= b greater than or equal to
a < b less than
a <= b less than or equal to


正常來說不論數字或字串比較,a及b的型態最好都相同,但若不同時可以直接看下例:
:if 0 == "one"
: echo "yes"
:endif


這個例子最後會輸出yes,當數字與字串比較時,字串會轉型為數字。由於one的第一個字元即不為數字所以它被直接翻成0,使得判別式成真。

VIM另外還有針對字串的判別方式,如下:
a =~ b matches with
a !~ b does not match with


左邊變數a會被成字串,右邊變數則會作為pattern,下面有個例子:

:if str =~ " "
: echo "str contains a space"
:endif
:if str !~ '\.$'
: echo "str does not end in a full stop"
:endif


此外,關於不分大小寫比對的話,在VIM裡可就複雜了一些,VIM有個option ignorecase來設定大小寫比對,有些時候可能我們不想設定這個值則可以直接從比對的算符來設定,想知道的人自己看一下[這個表格]。

while and for

VIM的while迴圈大概長底下這樣,它跟一般的語言一樣也有continue及break關鍵字。
:while counter < 40
: call do_something()
: if skip_flag
: continue
: endif
: if finished_flag
: break
: endif
: sleep 50m
:endwhile


VIM的for迴圈,通常是跟著list及dictionary這兩種型態一起使用,所以for迴圈我就留到那時候再講唄。

Exception
VIM跟C++ or Java一樣也有例外處理,用法跟他們都頗像,大概的用法就是try...cache...finally這三個關鍵字,請見以下範例:

:try
: read ~/templates/pascal.tmpl
:catch /E484:/
: echo "Sorry, the Pascal template file cannot be found."
:endtry


當檔案不存在時便會發生exception,在這個例子中是只catch E484:開頭的例外,當然,你也可以不要寫/E484:/,它就會抓所有的exception。

底下是個有finally的例子,finally在不論try的程式片段成功執行與否皆會執行finally後的程式片段。

:let tmp = tempname()
:try
: exe ".,$write " . tmp
: exe "!filter " . tmp
: .,$delete
: exe "$read " . tmp
:finally
: call delete(tmp)
:endtry

2009/03/31

輕輕鬆鬆寫VIM plugin: 變數及表示式

在開始之前,必需先介紹一下如何建立一個測試環境,小弟本身是有用兩種開發方式,一是開發小功能時用的,另一則是真正在開發一個plugin時用的。

先來介紹第一種開發小功能的環境,一般小弟會先在_vimrc裡建一個函式,接著再用map指令將這個函式對應到一個快速鍵,舉例來說在_vimrc裡插入以下指令將會建立一個foo函式,並且當輸入rfa時會呼叫到它。

map rfa <ESC>:call Foo()<CR>
function! Foo()
echo "Hello world 1"
endfunction


藉此我們便可將小功能先放在_vimrc裡測試,等到功能成熟時再建立一個plugin。此外,若是在反覆測試這個函式時,不想每次做小更動就必需重開VIM讓它reload檔案,可以在更動完後用:source指令來使檔案重新生效。如下,將使_vimrc的設定重新讀取:

:source $VIM\_vimrc


第二種方式就較為複雜,這種方式會用在開發一個plugin時使用,因為它包含了一個plugin前後的一些readme、檢查、command或keymap,所以目前還先不介紹。等到這些基本的語法講解完後,準備踏入plugin開發時才會說明。接著將進入本篇的主題,說明時我儘可能用範例說,少說一些廢話。


常數

數字常數除了一般十進位外,16進位的prefix為0x,8進位的為0,請看以下例子。
:echo 0x7f 036
127 30
:echo 0x7f - 036
97


字串常數則有分單引號括住及雙引號,單引號的會乎略跳脫字元,VIM的跳脫字元有很下這些:
\t <Tab>
\n <NL>, line break
\r <CR>, <Enter>
\e <Esc>
\b <BS>, backspace
\" "
\\ \, backslash
\<Esc> <Esc>
\<C-W> CTRL-W



變數

變數的命令規則跟C很像,這個不再贅述,而VIM的變數根據類型及生存空間有以下幾種:
b:name variable local to a buffer
w:name variable local to a window
g:name global variable (also in a function)
v:name variable predefined by Vim
$NAME environment variable
&name option
@r register (list all by :reg)


變數的建立及刪除有檢查存在,可用2個指令及1個函式
let
unlet
exists("s:call_count")


請看以下例子:
:if !exists("s:call_count")
: let s:call_count = 0
:endif
:echo "called" s:call_count "times"


NOTE: 關於if判別式,若是字串型態則VIM會將它自動轉成數字型態,轉成數字型態的字串是根據字串開頭的數字當成轉型後結果。若是程式寫了如下的判別式
:if "true"

則會回傳0,表false,因true的字首為t,不為一個數字,故回傳0。


表示式

數字運算
a + b add
a - b subtract
a * b multiply
a / b divide
a % b modulo


字串串接
:echo "foo" . "bar"
foobar


執行表示式(:execute)用在用我們的命令需插入變數時使用,:execute的行為與eval是十分相似(或是一樣)的,請見以下例子。
:execute "normal " . normal_commands

:let optname = "path"
:let optval = eval('&' . optname)

:exe 'let optval = &' . optname

2009/03/26

VIM: 製作跟VIM help一樣能跳來跳去的文字檔

最近想要自己製作VIM的help,VIM的help就是輸入:help後會顯示的說明頁,這種說明頁的好處除了有原本VIM的優點外,他還可以讓你用Ctrl-]和Ctrl+t[跳來跳去]。本文就是介紹這種"跳來跳去"的非源碼頁面。

(題外話)
會想試試看原因有好多,最大原因是最近工作雖忙但都是做無聊的事沒學到什麼東西感到很悶,另外最近訂了一隻gphone(htc dream),整天在想要拿那隻手機做啥,沒什麼心情工作。最近常在想比起做韌體,我好像比較適合做軟體,做韌體有bug就是用一些bug tool不斷縮小縮圍找bug,之後看看腳位有沒有設對,釐清是誰的問題。才工作半年就對這份工作感到無趣會不會太快了點,相對於之前2份軟體的工作這份工作似乎太快就沒興趣了。

(恢復正題)
廢話不多說,馬上進入正題,我以範例來解說製作方式。現在我要製作2份文件分別為a.txt及b.txt,在a.txt內要有一個link連到b.txt的頭,而b.txt會有一個link連到a.txt的頭,以下就是他們的文件真實內容。

a.txt的內容如下
*a.txt*
|b.txt|
------------------------------------------------------------------------------
vim:tw=78:fo=tcq2:isk=!-~,^*,^\|,^\":ts=8:ft=help:norl:


b.txt的內容如下
*b.txt*
|a.txt|
vim:tw=78:fo=tcq2:isk=!-~,^*,^\|,^\":ts=8:ft=help:norl:


我們以a.txt與b.txt相似,我們以a.txt為解說例。首先第一行以*...*括起來的a.txt是表示它是一個錨(anchor)用作於連結目的端,錨名為a.txt。第2行以|...|括起來的則是一個link連結到名為b.txt的錨。接著我們必需讓VIM將這些資料做成cache,輸入":helptag ."便會在工作徑下產生tags檔。現在便可以使用Ctrl+]跳來跳去了。

大家看到這裡可能還會有個疑問,我在文件的最後一行輸入(vim:tw...)的是什麼東西,那行叫[modeline]是用來指示這個檔案的VIM設定,像是這個範例就表示textwidth=78, iskeyword有那些, filetype為help等設定。若將這些都設定上檔案開起來就會像這樣:



本文參考自:[Add your note files to Vim help]

VIM tip: 刪除搜尋到的行

剛好看到有人用sed來刪除比對到的字串行,VIM也有類似用法,有時這個功能還算滿有用的。若是想刪除出現Rickey is foolish的這些行可以輸入

:g/Rickey is foolish/d


開對的g是表所有的意思,尾巴的d則是刪除,中間被/包圍的則是要搜尋的字這是允許regex的。

這些資料可以在vim doc的[10.4 The global command]及[delete]找到,有時vim doc看一看,真覺得vim有一堆很真正去理解的命令。

2009/03/20

VIM 系列文章的下一步

最近在思考這個部落格接下來可以寫些什麼,之前[打造自己的VIM系列]文章是寫給那些已經會使用VIM的人看的,目的是希望能藉著這個系列文章能讓各位用起VIM能更得心應手。現在有2個大方向可以讓VIM這個主題繼續GO,一是寫簡單的VIM教學,另一則是寫更難的。如果有熟悉我的朋友,應該猜的到我的選擇,選擇比較困難的地方前進。所以下個主題我打算來寫如何寫VIM plugin。

學會寫plugin其實有很多好處。像之前我在用[easygrep]這個plugin時,它並不支援不分大小寫的搜尋,所以我就稍微看一下它的程式,再把我需要的功能加進去,最後將修正的地方寄給原作者好讓原作者merge起來,作者也很快將把我把我的功能加進去而且上面還有我的名字(Doro Wu)(羞)。這就是open source的好處,需要什麼功能自己動手加進去。

要會寫plugin的首要之務是要會寫VIM script,所以我會先對VIM script簡介並再介紹一些常用的內建函式,之後才會開始告訴各位如何將script組合成plugin。目前打算依照這樣介紹:
  • 變數及表示法
  • 判斷句
  • 函式
  • 例外
  • 事件 autocommand
  • syntax highlighting
  • window and buffer
  • 命令輸出擷取
  • plugin簡介
  • 輕輕鬆鬆寫個vim plugin

2009/03/14

打造自己的VIM: 源碼補齊 SuperTab OmniCppComplete Code_Complete

VIM的源碼補齊是我比較少用的部分(這就是身在系統廠的悲哀,幾乎沒什麼機會寫大一點的專案),但就我以前寫code的經驗,小弟認為我這次要介紹的3個plugins應該是能滿足大部分的需求。這3個plugins為[SuperTab]、[OmniCppComplete]及[Code_Complete]。

SuperTab

SuperTab是這3個源碼補齊我最喜歡的plugin,它使用不需要什麼設定,也不用產生tags檔案,裝好即用。它補齊的所使用的關鍵字是藉由搜尋所有被開啟的檔案內的字。而使用方式也很容易,當你打字打到一半需要它幫你補齊時就按下<tab>鍵,它就幫你把剩下的字補齊。但有時我們會希望是插入一個真正的Tab而不是要幫助補齊,這時需要按下Shift+Tab,它的使用就這樣而已,是不是很容易呀。以下是一張截圖,可以看到圖上有2個關鍵字AAAA及AABB,當我輸入AA後要它補齊,又有多個關鍵字被找到它會彈出一個popup menu讓你選擇。



OmniCppComplete

OmniCppComplete是針對C/C++程式所設計的源碼補齊方式,它需要tags檔案的幫忙,若是還不知道要怎麼產生tags檔案,可以參考我之前的文章,安裝:[打造自己的VIM: 函式列表 TagList],產生:[打造自己的VIM: 源碼追蹤 SrcExpl]。關於OmniCppComplete的截圖可以到[這裡]來看,那裡提供了很多圖,我就不再為各位截圖了。

OmniCppComplete的使用除了先產生tags檔案外,另外可以用的鍵就只有<c-x><c-o>,按下Ctrl+X及Ctrl+O後,它就會依據tags檔案及目前游標前的的字彈出相對應的popup menu供使用者選擇,就使用上也是很容易。

而在設定上,我自己是什麼都沒設,如果有覺得使用上有什麼不便,可以看看它裡頭的doc,那裡有所以它可以設定的option,我稍微看了一下大概就是調整popup menu的顯示設定或是自動選擇第一個item。

Code_Complete

不知道各位有沒有看過一些在mac上的demo,那些人有些人是寫RoR有些是寫HTML(PHP),他們只要輸入if或for等關鍵字,他們的文字編輯器就會幫他們把後面相關的文字補齊,一整個寫起程式來很帥,Code_Complete就是提供這種功能。相信有人還是不懂我在說什麼,我用下的套圖來說明,下面第一張圖是一個C的程式,一般include完檔案後會寫個main function,在我輸入完main再按下Alt+d如圖2,它便幫我把該補完的補完了,並且跳到要繼續寫程式的地方;接著我輸入if如圖3,再按下Alt+d,它又幫我把剩下補完。若是想跳到下一個`<...>`處,只要按下Alt+d它就會幫我們跳過去。









到這裡應該大家都知道基本用法,但是Code_Complete他是根據什麼來補齊呢?各位可以打開code_complete.vim,可以看到有一行寫著:

let g:template['c']['main'] = "int main(int argc, char \*argv\[\])\<cr>{\<cr>".g:rs."...".g:re."\<cr>}"


等於符號左邊的意思是遇到附檔名屬於c程式且游標前面是main時,一按下Alt+d便用等於符號右邊的字串補完。至於右邊字串的意思大家就自己跟main產生出來的東東比對一下大概就可以猜到它的意思。

2009/03/11

VIM tip: TabBar的密技

TabBar裡其實有一些設定很少被提到,但是卻很實用,若需要更多的說明可以自己打開tabar.vim來看看,大概在100出頭行的地方,亦或是直接在code裡的某處。我這裡提一些看起來比較有用到的。

g:Tb_MaxSize (Default = 1)
有時開的檔案太多,TabBar視窗會容不下那麼多檔案同時在一行內被顯示,但是使用者(我)會希望它可以分成2行被顯示,這時只要將這個值設定2就行。

g:Tb_TabWrap (Default = 0)
若開啟檔案數超過一行可顯示且g:Tb_MaxSize又設成大於1時,超過一行可顯示的字會折到下一行而造成最後一個檔案標籤斷了,若設成1則它不會讓標籤斷掉,會直接讓行尾標籤放到下一行行首。

g:Tb_SplitBelow (1 = below, 0 = above(Default))
將TabBar視窗放在上面or下面

g:Tb_VSplit (0:top, 1:left)
將TabBar放在上面or左邊


我自己是設定這些值
let g:Tb_MaxSize = 2
let g:Tb_TabWrap = 1


這篇文章已被收錄在原本[TabBar介紹]的文章裡

2009/03/10

VIM tip: 自動插入數字列號,使用巨集及VIM內建函式

在ptt上看到網友CyberFret問了一個問題:

[問題]vim如何作到ultraedit的自動插入數字列號
input  int[0]
input  int[1]
input  int[2]
input  int[3]
如上面的sample code
在ultraedit裡面, 可以用 "區塊-->插入數字列號" 來自動插入一整排的等差數列
如上面的 0 -3, 請問在vim裡面要如何辨到? 謝謝


換句話說就是只輸入上列第一行,如何快速產生下面幾行。這個問題其實google一下應該能找到相關討論,我是從這[]來的,當然也不完全是抄啦 ^^"

要達到這個功能方法有2:
  1. 使用巨集
  2. 使用VIM built-in function
先來說說第一種方法。請在輸入完第一列(到底是列還是行??)後,在數字處按造下面keyin來製作巨集:
qa
yy
p
Ctrl-a
q

上面第一個命令表開始錄製巨集a;第二,複製游標所在列;第三,貼上;第四,將游標所在處的數字加1;第五,結束巨集。其中若要改成數字減一則在第四個命令改成Ctrl-x,另外,因為在windows中Ctrl-a對應到全選,所以對於windows的vim使用者必需先下:nunmap <C-A>將全選的功能取消。

在錄製好巨集後,接著再輸入15@a便會重覆執行巨集a,15次。以上是第一個方法。

第二種方法為使用內建函式。先從一簡單的例子來看,以下命令:
:0put =range(11,15)

將輸出
11
12
13
14
15

以此類推,若要CyberFret的要求則輸入以下命令即可。
:for i in range(0,3) | put ='input int['.i.']' | endfor

2009/03/05

打造自己的VIM: 多檔字串搜尋 EasyGrep

在追蹤源碼時,除了最常用到的tags方式,另外搜尋也是不可少的功能之一,在Linux環境底下最常見的方式就是開個termianal用grep搜尋,再到自己的文字編輯器把相對應的檔案打開,當搜尋的機會變多,這樣的動作真是麻煩又囉嗦。為了縮短這些麻煩regular routine,有人寫了一個plugin [EasyGrep]。EasyGrep主要是把Grep的功能整合在VIM裡,它可以使用跨平台VIM內建的vimgrep或是外部的指令grep、findstr等指令,而它是將搜尋結果輸出到QuickFix視窗,更多的QuickFix使用可以參考小弟寫得[這篇文章];基本上因為輸出到QF視窗的關係,也使得這個套件更好用了。要直接看demo可以到[這裡看]。而底下是它的option截圖,大家可以看一下它提供那些功能。






安裝方式請至官網下載EasyGrep.vim and EasyGrepFileAssociations到你的vim plugin資料匣,其中EasyGrepFileAssociations為設定搜尋檔案關連性,像上面那張圖的第30行,我設定ASM檔包括*.s *.asm...等5種檔案,各位可以修改Easy...Associations來更改這個值。

基本上EasyGrep不需要什麼特別的配置,因為它提供的快速鍵就足夠使用了。以下我整理了我常用的指令(就4個而已):

<leader>vv- Grep for the word under the cursor
<leader>va - Like vv, but add to existing list
<leader>vo - Select the files to search in and set grep options
:Grep SearchString


<leader>預設值是對應到"\"。

大部分的調整是都在<leader>vo裡找的到,只是有少部分的預設值可以從vimrc裡修改,像我自己是加了底下這些預設值,這些預設值大都是for windows才需要的,除了第1個是為了很懶的我,連5個字都要建個mapping變只需打2個字,哈哈。
map f/ <esc>:Grep
let g:EasyGrepCommand = 1
let g:EasyGrepFileAssociations = "C:\\Program Files\\Vim\\vim72\\plugin\\EasyGrepFileAssociations"
let g:EasyGrepRecursive = 1
let g:EasyGrepHidden = 0
let g:EasyGrepExtraWarnings=0
let g:EasyGrepIgnoreCase= 1


2009/03/03

VIM tip: 搜尋不分大小寫及取代

:set ic


ic是ignorecase的縮寫,不分大小寫在windows上常用到,Linux上就不太常用到了。若是需要用原字串作為取代一部分,可以再用&符號或\1之類的表示。舉例來說,若想取代所有AAA, AAa, Aaa...分別取代成AAA123, AAa123, Aaa123,可以這樣輸入:

:set ic
:%s/AAA/&123/cg

Linux Tip: less從最後一行開始看

方法1:
less +G file_name

方法2:
執行less後,G到最後一行,gg到第一行。這跟VIM是不是很像呢?

2009/02/24

打造自己的VIM: 樹狀檔案列表 NERD Tree

在VIM中,提到樹狀的檔案列表一定會讓人馬上想到[NERD Tree]。下圖為它的一個截圖,左邊紅框圈起處就是window of NERD Tree。[這裡]是作者提供的一個demo,看完demo就能完全知道這個plugin在做啥了。



NERD Tree的特色有:
  • 樹狀顯示檔案及資料匣
  • 資料匣或檔案的書籤
  • 以各種不同方式開啟檔案 (split of buffer)
  • 快速移動至各種節點
  • 可自訂NERD Tree window的位置
  • 支援滑鼠 (都在用VIM了,誰還在用滑鼠)
  • 過濾檔案內容
  • 檔案系統的操作 (刪除/移動檔案等等)

安裝方式自己參閱[官網]。


快速鍵及目錄定義

一個在Tools底下的目錄及F5開啟/關閉NERD Tree

an 50.20 &View.File\ Viewer<Tab><F5> <ESC>:NERDTreeToggle<CR>
map <F5> <ESC>:NERDTreeToggle<CR> " Toggles NERD Tree view (file viewer)



常用指令彙整


" ----------------------------
" 基本操作
o: 開檔/資料匣/書籤
x: 關資料匣
O: 開資料匣包含子資料匣
X: 關資料匣包含子資料匣
D: 刪除書籤

" ----------------------------
" 巡訪樹快速鍵
P: 到根目錄
p: 到母節點
K: 到第一個兄節點
J: 到最後一個兄節點
Ctrl+j: 到下一個兄節點
Ctrl+k: 到上個兄節點

" ----------------------------
" 檔案系統
C: 改變根目錄至所選資料匣
u: 改變根目錄至上一層的根目錄
U: 改變根目錄至上一層的根目錄且原來的目錄開著
cd: 改變工作目錄到現在所選目錄

" ----------------------------
" 書籤指令
:Bookmark <name>
:BookmarkToRoot <name>
:RevealBookmark <name>
:OpenBookmark <name>
:ClearBookmarks [<name>]
:ClearAllBookmarks


2009/02/17

打造自己的VIM: 檔案搜尋 FuzzyFinder

小弟在為我心愛的VIM找如何快速尋找檔案的plugin時,不小心找到一個超強的plugin,[FuzzyFinder],FuzzyFinder的功能只能說強到爆炸,有了它真是為了VIM的愛好者帶來了巨大的便利性。

FuzzyFinder它能夠幫我們快速找到好幾種東東,那些東東包含了:
  • Buffer (已開啟的檔案)
  • File
  • Tagged file (找在tag裡頭的檔案)
  • Most recently used(MRU) files (最近開過的檔案)
  • Directory (快速切換工作目錄)
  • Bookmark (使用FuzzyFinder建立及使用書籤)
  • Tag (模糊比較tag檔內的keyword)
  • MRU-Command (最近使用過的指令)

它的安裝方式請自己去官網下載.vim,再將.vim放到plugin裡面。以下我將只介紹如何使用它來找檔案及找tag功能,而其它功能因為用法太類似,所以各位就自行抓回去好好享受用它來開檔的快感吧。


File Mode

使用:FuzzyFinderFile指令來開啟FuzzyFinder的file mode,接著便能輸入一些pattern,FuzzyFinder就會幫我們找到類似的檔名,亦或者可以按下方向鍵的上下或Tab和Shift-Tab來直接選擇檔案。如下圖:



若是在資料匣上按下Enter,FuzzyFinder會幫我們自動補齊資料匣名,若是在檔案上則會直接開啟檔案,而開啟檔案的方式還有很多種,各位可以自己去參考文件,或是文章下面的指令彙整有稍微提到。

剛才的搜尋只限定在同一資料匣內,若我們想在搜尋資料匣內包含子資料匣內的檔案的話我們可以使用**\的wildcard,舉例來說,若我要在當前資料匣包含所有子資料匣內找1.txt這個檔案,我就可以打**\1.txt。(**這個符號不只針對FuzzyFinder是這個意思,在VIM中的一些其他地方,像某些built-in function也是這個意思)。下圖是我在arch資料匣找所有的.S檔案。


Tag Mode

FuzzyFinder的Tag mode有2種用法,一是不帶參數,第二則是帶參數。不帶參數如下圖,


它的用法跟File mode差不多,一樣先執行:FuzzyFinderTag,接著輸入tag來找tag檔內的關鍵字。但使用這種模式前,請先確認自己有tag file,若是不知道如何產生tag file,可以參考我[之前的文章]安裝並設定ctags,接著再參考[另一篇文章]產生tag file。

以上是第一種用法。第2種用法是有帶參數的,其用法為:FuzzyFinderTag 關鍵字。這邊我會加上快速鍵Ctrl+\,因為在某些時候FuzzyFinderTag會比Ctrl+t好用。快速鍵的語法如下:

map <silent> <C-\> :FuzzyFinderTag! <C-r>=expand('<cword>')<CR><CR>

配置好了,以後就只需在要查的關鍵字上按下Ctrl+\便能用FuzzyFinderTag來查詢,下圖是個範例,我在unwind_init函式上按下Ctrl+\則FuzzyFinderTag便直接開始查詢我要找的關鍵字。




指令彙整

以下我整理了一些關於FuzzyFinder的指令:

:FuzzyFinderBuffer " launchs Fuzzyfinder as Buffer mode.
:FuzzyFinderFile " launchs Fuzzyfinder as File mode.
:FuzzyFinderDir " launchs Fuzzyfinder as Directory mode.
:FuzzyFinderMruFile " launchs Fuzzyfinder as MRU-File mode.
:FuzzyFinderMruCmd " launchs Fuzzyfinder as MRU-Command mode.
:FuzzyFinderBookmark " launchs Fuzzyfinder as Bookmark mode.
:FuzzyFinderTag " launchs Fuzzyfinder as Tag mode.
:FuzzyFinderTaggedFile " launchs Fuzzyfinder as Tagged-File mode.


開啟選擇選項可以以下面這幾種模式:
<cr> - opens in a previous window.
<c-j> - opens in a split window.
<c-k> - opens in a vertical-split window.
<c-]> - opens in a new tab page.


其他:
<c-l> or <c-o> " To Switch the mode without leaving Insert mode.
<c-t> " If you want to temporarily change whether or not to ignore case
<c-e> " 暫時關閉pop視窗
<c-x><c-u> " 重新打開pop視窗
:FuzzyFinderRemoveCache " 刪除Cache資料



快速鍵及目錄

小弟新增以下幾個常用功能為快速鍵,將這些加入自己.vimrc吧。

map ff <esc>:FuzzyFinderFile<cr>
map fcd <esc>:FuzzyFinderDir<cr>
map fba <esc>:FuzzyFinderAddBookmark<cr>
map fbl <esc>:FuzzyFinderBookmark<cr>
map fu <esc>:FuzzyFinderBuffer<cr>
map <silent> <c-\> :FuzzyFinderTag! <c-r>=expand('<cword>')<cr><cr>
map <c-f12> <esc>:!ctags -R --c++-kinds=+p --fields=+iaS --extra=+q .<cr>


目錄部分則是,加在Tools裡頭,截圖如下:



其script為以下那幾行,各位可以加在自己的.vimrc也可以加在menu.vim,或是有人懶得自己加,可以直接抓我的[menu.vim]回去用。
an 40.310.10 &Tools.F&uzzyFinder.&File<tab>ff <esc>:FuzzyFinderFile<cr>
an 40.310.10 &Tools.F&uzzyFinder.Tag&File <esc>:FuzzyFinderTaggedFile<cr>
an 40.310.20 &Tools.F&uzzyFinder.&Dir<tab>fcd <esc>:FuzzyFinderDir<cr>
an 40.310.30 &Tools.F&uzzyFinder.&Bookmark<tab>fbl <esc>:FuzzyFinderBookmark<cr>
an 40.310.40 &Tools.F&uzzyFinder.&BookmarkAdd<tab>fba <esc>:FuzzyFinderAddBookmark<cr>
an 40.310.50 &Tools.F&uzzyFinder.B&uffer<tab>fu <esc>:FuzzyFinderBuffer<cr>
an 40.310.60 &Tools.F&uzzyFinder.&Tag <esc>:FuzzyFinderTag<cr>
an 40.310.70 &Tools.F&uzzyFinder.MRU-&File <esc>:FuzzyFinderMruFile<cr>
an 40.310.80 &Tools.F&uzzyFinder.MRU-&Command <esc>:FuzzyFinderMruCmd<cr>
an 40.310.90 &Tools.F&uzzyFinder.-SEP1- <nop>
an 40.310.100 &Tools.F&uzzyFinder.ClearCache <esc>:FuzzyFinderRemoveCache<cr>


打造自己的VIM: 源碼追蹤(ctags+cscope)及預覽視窗SrcExpl

Windows上重量級的源碼追蹤程式Source Insight,其最重要的功能之一就是他能依據程式內的函式名、結構名或其他源碼內使用之關鍵字,快速跳躍至該關鍵字的宣告或定義處。

超強編程軟體 - VIM - 也有這種能力。我們用VIM doc裡的文件來解釋一下什麼叫根據源碼關鍵字跳到定義處。如下圖:





我 們在write_block函式內用到write_line,若我們想看一下write_line的定義,在VIM裡只需將游標移到write_line 上,按下Ctrl+]就可以跳到該函式處。更進一步,在write_line裡頭用到write_char,我們也只需在write_char上按下 Ctrl+],又能再跳到write_char定義處。這樣的功能在追蹤大型的程式時是很方便的功能,在VIM要有這樣的能力只需一些小小的設定就能達 到。

本文參考2份VIM document,分別為[usr_29]及[tagsrch]。


ctags安裝及使用


要使用源碼追蹤的功能預設是必需在工作目錄下存在一個檔名為tags的檔案,該檔案會紀錄源碼內所有的關鍵字出現位置,tags file的產生可藉由ctags這支程式,ctags的安裝方法我在之前的文章[TagList]已經有介紹過了,所以這裡不再累述,需要安裝的人請參考那篇文章。

產生tags方式,必需先切換工作目錄至源碼根目錄下,並輸入下面指令(在命令提示字元下則不要輸入:!喔):

:!ctags -R --c++-kinds=+p --fields=+iaS --extra=+q .

如此就會產生一名為tags的檔案在此目錄下,是不是很容易呀。

另 外,還有一種情形值得一提,有時源碼庫是很大一包,每次執行ctags產生tags file可能會需要一段不短的時間,而我們維護的程式可能只是這一大包源碼庫的其中一個小小的資料匣,因此我們有時會只希望更新我們維護的資料匣,而不是 一大包的源碼庫。這種情形可以只在源碼的所在位置產生一個local tags file,並且再藉著tags option將local tag file加入tag搜尋檔案中。

首先在目前編輯檔案所在位置產生tags:

:!ctags -R --c++-kinds=+p --fields=+iaS --extra=+q -f "%:p:h\\tags" "%:p:h"

因 為tags option預設為./tags,tags (輸入:set tags即會顯示出來),因此只要產生local tags file即會自動被加入tag搜尋檔案中,不需再做設定tag搜尋檔案的工作。在網路上可以查到許多教各位如何將STL的header加入tags搜尋檔 案中,它的方法也是先在STL源碼庫內使用ctags產生tags file,接著再設定tag option。

有了tags files我們便可以開始追蹤源碼了,追蹤源碼我較常用到這幾個功能,當然這些功能有不少被後後的快速鍵給取代掉了:

Ctrl+] " 根據游標所在位置的字串常做關鍵字,跳進去(快速鍵:tj)。
Ctrl+t " 跳出來。
:tselect " 當有多個關鍵字在tags file中被找到時,可用tselect來選。
:tags " 查看現跳到那裡了快速鍵:ta)。
:tnext " 跳到下一個被找到的tag(快速鍵:tn)。
:tprev "跳到前一個被找到的tag(快速鍵:tp)。



cscope安裝及使用


cscope與ctags十分類似,只是它有些功能是ctags所沒有的(cscope似乎可以完全取代ctags ??),所以我在這裡就稍微提下它的安裝及用法。

首先要安裝cscope.exe跟之前安裝ctags一樣,也是使用cygwin即可安裝它的windows版本,這裡我就不再贅述。另外對於VIM有人已經製作了它的keymapping及自動載入cscope reference file(cscope.out)的script [cscope_maps.vim],將它下載後放至vim72\plugin裡即可。

如同ctags,cscope也要建立一個cscope.out的參考檔。建立方式如下:

cscope -Rbkq

除了讓它自己去搜尋所有檔案,你也可以自己指定一份檔案列表,我們可以先用find(cygwin, NOT windows find)找出所有.cpp及.h的檔案再讓cscope.exe去讀取。如下:

find . -name "*.h" -o -name "*.c" -o -name "*.cc" > cscope.files
cscope -Rbkq cscope.files


以下為cscope_maps.vim提供的功能及對應的按鍵:

Ctrl+\ s "s表Symbol,列出所有參考到游標所在字串的地方,包含定義和呼叫。
ctrl+\ g "g表Global,與ctags的Ctrl+]相同。
ctrl+\ c "c表Call,列出所有以游標所在字串當函數名的地方。
ctrl+\ t "t表Text,列出專案中所有出現游標所在字串的地方。
ctrl+\ f "f表File,以游標所在字串當檔名,開啟之。
ctrl+\ i "i表Include,以游標所在字串當檔名,列出所有include此檔的檔案。
ctrl+\ d "d表calleD,以游標所在字串當函式名,列出所有此函式呼叫的函式。


若想知道其他更詳細的用法可以參考:cs內的內容。

ps. 若是出現"沒有cscope連線",這應該是你的工作目錄下沒有cscope.out檔案,若是想不想關掉VIM卻想自行加入cscope連線,可以參考:cs connect指令。

參考資料: http://www.yuanma.org/data/2006/0908/article_1487.htm

快速鍵設定

我設定了2個快速鍵來建立global and local tags file,分別為Ctrl+F12及F12。以及多個快速鍵來來方便tag的使用,其設定如下:

map :!ctags -R --c++-kinds=+p --fields=+iaS --extra=+q -f "%:p:h\\tags" "%:p:h"
map :!ctags -R --c++-kinds=+p --fields=+iaS --extra=+q .
map :!cscope -Rbkq
nmap :exec "tjump ".expand("")
nmap :exec "ts ".expand("")<>CR>
nmap :exec "tnext"
nmap :exec "tprevious"


預覽視窗 SrcExpl

狂熱於使用VIM的開發人員至此還不是很滿意,他們想為什麼我們不分割一個視窗來做源碼預覽的效果,[SrcExpl]也就因此誕生了。它的截圖如下:



呼 叫SrcExpl預覽視窗為指令:SrcExplToogle,以上圖為例原先在編輯init/main.c,在叫出SrcExpl預覽視窗後,當我們移 到任意的關鍵字上,SrcExpl預覽視窗就會自動將查詢到的tags顯示在視窗內。上圖為游標在boot_cpu_init()後,預覽視窗即馬上顯示 函式定義。

說老實話,我大部份的時候很喜歡這個套件,但對於大project我很討厭它。主要原因是對於很大的project時,它tag檔很大,如果我開著這個功能我整個VIM都頓頓的,整個用起來很煩。各位看倌還是自己視情形用它吧

另外,呼叫SrcExpl預覽視窗,我也定義快速鍵F7

map :SrcExplToggle

2009/02/12

VIM tip: 單行註解一整個區塊

在C/C++或是其它有單行註解(//)語法的程式中,程式員有時會因為某些原因而不使用多行註解(/* */),為了能快速使用單行註解註解一整個程式區塊,VIM有人寫了一些plugin來幫助註解。但實際上,有些小方法能快速在一片區域前快速加入一些字。

以下有一段程式,假設我們要在210到215行插入註解為 "; Rickey modifies "。


我們先用區塊選擇將210到215行選起來,Windows為Ctrl+Q,Linux上為Ctrl+V,如下圖:



選起來後進入插入模式,按i,並輸入要插入的註解


最後按ESC離開便完成了。 (傑克!這真是太神奇了)

打造自己的VIM: 函式列表 TagList

[TagList]對於程式員而言是個不個貨缺的plugin。它提供了檔案內的結構、define及函式列表,並能讓使用者快速跳到這些變數的定義處。安裝TagList的過程中,除了將TagList抓下來,放到$VIM資料匣內,另外使用者必需提供一支外部程式ctags。本文將介紹在windows XP環境下如何安裝ctags及TagList的配置。


安裝

在將TagList解壓縮放到$VIM資料匣後,在Windows XP下我們必需再安裝ctags,小弟是用cygwin的安裝方式。進入[cygwin的首頁]後,在首頁下方會看到一個setup.exe的程式下載處,抓下來執行後便開始安裝了,安裝的過程中我們要選擇從網路上取得套件、套件取得的server、安裝位置等,最後一步則是選擇套件,選擇套件記得一定要選ctags,它位於Devel下,如下圖(若是有需要,你可以一便在Devel下找到gcc及make的套件來安裝),之後點選下一步後就開始安裝了。(在ubuntu下安裝因為太簡單,應該就不用介紹了)



安裝完後,ctags會放在c:\cygwin\bin下,接著我們就設PATH變數好讓TagList找得到ctags程式,在「我的電腦」上按右鍵選內容,其它步驟請看下圖。


接著我們打開「命令提示字元」應該打ctags應該就能執行ctags了。


配置TagList

快速鍵我是用F6,所以我在vimrc加入:

map <F6> <ESC>:TlistToggle<CR>

Menu我則是加在View底下,Menu加的方法請參考我以前我的[文章]。另外,底下是一些我覺得比較有機會用到TagList變數,我列在下方,後面都有註解,所以就自己看一下吧。

let Tlist_Show_One_File = 1 " Displaying tags for only one file~
let Tlist_Exist_OnlyWindow = 1 " if you are the last, kill yourself
let Tlist_Use_Right_Window = 0 " split to the right side of the screen
let Tlist_Sort_Type = "order" " sort by order or name
let Tlist_Display_Prototype = 0 " do not show prototypes and not tags in the taglist window.
let Tlist_Compart_Format = 1 " Remove extra information and blank lines from the taglist window.
let Tlist_GainFocus_On_ToggleOpen = 0 " Jump to taglist window on open.
let Tlist_Display_Tag_Scope = 1 " Show tag scope next to the tag name.
let Tlist_Close_On_Select = 0 " Close the taglist window when a file or tag is selected.
let Tlist_Enable_Fold_Column = 0 " Don't Show the fold indicator column in the taglist window.
let Tlist_WinWidth = 40


以上都都設定完後,以後只要按下F6就可以叫去TagList了,如下圖。




2009/02/11

打造自己的VIM: QuickFix 編譯視窗

QuickFix視窗(之後簡稱QF)在VIM裡是一個很方便的功能,它最常見的功能是將編譯時的輸出訊息導入到QF中,在QF中,我們可以快速切換至編譯錯誤的檔案及錯誤行上。除了這個功能外,我們亦可用一些plugin將搜尋字串或檔案的結果輸出到QF內,以方便我們快速瀏覽。

本篇文章,將簡介如何將QF用在編譯除錯及常見指令彙整,最後我將為QF做一些更方便快速鍵。本篇文章參考自VIM document [quickfix]


QF簡介

在編譯程式時,不管在Linux平台或Windows平台,make是最常使用到的專案管理工具之一。VIM則提供了一個:make的指令去呼叫外部make,可能是gmake或nmake來協助編譯程式並輸出到QF視窗中。與:make有關的選項,各位可以參考:options中第23大項的內容,如下圖或VIM document [quickfix]。



接著,我將由一個C的hello world帶領各位使用QF。因為編譯時會呼叫到外部指令,gcc或make,所以請各位在開始前先確定自己的shell(cmd.exe or bash)可以正確執行gcc及make。我的環境是Windows XP及Cygwin(包含make及gcc),並且在環境變數PATH加入了cygwin bin的路徑。

首先,我們先寫一個有問題的hello world,如下圖,在第6行處有一個變數未宣告。接著我們輸入

:make a

其中:make為VIM指令,a為檔名不包含副檔名。在這裡make與nmake會有差別,nmake必需輸入a.exe,這是由於兩種make程式的predefined rule不同的關係。按下enter後,a.c的視窗下方就會自動彈出QF視窗(若是沒彈出來,自己輸入:copen指令),且包含了錯誤訊息,接著各位可以再試:cnext或:cprev的指令來切換下一個或前一個錯誤訊息,在切換的過程,若檔案或行號不同,它會自動幫我們跳到該處。


對於一般的小程式(只有一份source code,不用複雜的compile和link),這樣的功能應該就夠了,對於稍有規模的專案則寫一個makefile就是必需的了,至於makefile要怎麼寫,各位就自己去查一下了,網上資源一堆。


指令彙整

我只列出我常用的。

:make " 編譯程式

:copen " 打開QF視窗
:cclose " 關閉QF視窗

:cnext " 移到下一個錯誤
:cprev " 移到前一個錯誤

:cnewer " 若有多個QF buffer,移到下一個錯誤訊息列表
:colde " 若有多個QF buffer,移到前一個錯誤訊息列表



快速鍵

跟QF有關的指令真是又多又長,若是用了前幾篇的[自訂目錄]的話,應該可以發現我加了幾個快速鍵,如下圖,我將依此目錄我有修改的部份一個個講解。這些分別為:
  • QuickFix switch
  • Newer List
  • Older List
  • Next Error
  • Previous Error
這些東西可以視自己的需要加到vimrc裡。


QuickFix Switch

切換QF視窗不只指令長,打開關閉也要用不同指令,實在是非常麻煩,所以小弟寫了一個小function及一個map便可用F8鍵來做切換QF的功能。

map <F8> <ESC>:call QFSwitch()<CR>
function! QFSwitch()
redir => ls_output
execute ':silent! ls'
redir END

let exists = match(ls_output, "[Quickfix List")
if exists == -1
execute ':copen'
else
execute ':cclose'
endif
endfunction

其它指令

因為其他都只是alias而已,我直接列出來我的設定。

map <F8> <ESC>:QFSwitch<CR>
map <S-F8> <ESC>:colder<CR>
map <C-F8> <ESC>:cnewer<CR>
map <C-n> <ESC>:cnext<CR>
map <C-p> <ESC>:cprev<CR>




2009/02/10

QTTabBar: 為windows檔案總管加上快速鍵

在公司實在沒辦法的情況下,只能在windows上工作,windows的檔案總管不像nautilus一樣,有很方便的tab功能,因此我google找到了這個軟體,它不只為檔案總管加了tab,它還提供了一些自訂的快速鍵,這對於我未來會分享的VIM有點關係,所以我先跟大家分享一下這個軟體。

[QTTabBar]網上一堆介紹我也不簡介了,畢竟我不會寫的比他們好。我只用幾張圖說明如何利用檔案總管,快速在當前目錄開啟VIM(快速鍵Ctrl+Alt+V)。如果有人不想看如何設定,我把我的設定檔放在[],需要的人安裝完QTTabBar後,把設定檔抓回去再雙點它就可以用我的設定了。







題外話,在gnome檔案總管nautilus也可以達到類似功能,我的方法是自己寫個開啟VIM在當前目錄的script放在自己的nautilus script資料匣,以後要開VIM則按鍵盤上的打開popup menu鍵,接著按S到script的menu item,最後再用方向鍵選擇script即可。等我把VIM系列寫完,再跟大家分享。


VIM tip: Pipe 使用外部命令處理VIM內資料

部分內容參考自[Daily VIM: Piping Buffers],完整的VIM doc請參考[change]

想使用外部指令來處理VIM內容,關鍵在於"!"這個filter command,舉例來說現在讀取VIM內的文字並交由外部程式sort處,可以這樣做:

:% ! sort

其中%是表文本內容(?)(應該是檔名吧? 有誰知道這個從vim doc那來的),最後的輸出結果也將目前文本內容全部取代。再舉一個例子,這個例子是用cat來加行號:

:% ! cat -n

有時我們是要由外部命令讀取資料進來,而且不想將外部指令的結果取代掉所有文本內容,這時我們可以用":r"這個命令。舉例來說,將ls輸出到游標所在處:

:r ! ls

再回到剛才cat的例子,我們若想插入文本內容,卻又不想取代掉現在文本內容,我們可以這樣做:

:exec ":r ! cat -n ".expand("%")

exec是叫VIM做這個命令,命令內容為後面那一串,其中expand("%")表示目前編輯的檔案檔名,所以這個命令在未儲存檔案時不能用的喔~~

打造自己的VIM: Folding


對於比較多行的程式,有時候源碼褶疊能隱藏函式或結構的定義,而只顯示函式的宣告,下圖是源碼折疊的一個簡單例子。



在VIM中,源碼折疊可以分成多種方法,我這裡只簡單介紹我會用到的幾種折疊方式,隨後會再介紹跟程式折疊有關的指令。本篇文章共參考到2份VIM document,分別為[user_28]及[fold]

折疊方式

我常用的折疊方式有3種,第1為syntax,簡單的說就是根據語言讓VIM幫你自動折疊程式,我大都使用這種。第2種為marker,很多VIM的script(plugin)都會採用這種,它是根據使用者在文檔中加入的特殊符號來折疊,VIM預設是用"{{{"及"}}}"來作為標示,並且為了讓這種標示不影響程式/文檔運行,通常這些標示會放在註解內,我們看一下下面2個例子。



這個例子太簡單,相信大家看一下就懂。而底下的另一個例子則在標示後面增加了一個號碼來說明這是第幾層的折疊



Mark這種折疊方式,我通常是用在整理某些特殊的比較沒有規則的文檔。

第三種折疊方式為為indent,這是根據縮排來折疊,這種折疊方式用在python這種程式,特別好用。

設置折疊的方式為foldmethod這個option

:set foldmethod=syntax

你可以把它加在vimrc裡,如果你常需要折疊功能的話。若你是像我一樣,偶爾用它,那就等文檔打開後再輸入這個指令,但這個指令也太長了,所以它有縮寫,像是上面的例可以取代成

:set fdm=syntax

此外,我比較常用的option為有這幾個foldnestmax(fdn)及foldcolumn(fdc)。foldnestmax它會限制最多折疊幾層,畢竟有時折疊太多層也很煩人,如下面這個指令它最多會折疊3種。

set foldnestmax=3

foldcolumn這個option則是設定在VIM最左邊預留一塊foldcolumn的空間顯示折疊情形,如下圖。




常用指令

zi      "啟用/關閉折疊

zo      "打開折疊
zc      "關閉折疊
zO      "打開所有折疊
zC      "關閉所有折疊

zx      "更新折壘,即除了游標所在折疊不關,其他都關掉




2009/02/09

打造自己的VIM: 書籤及游標移動

有在用ultraEdit或pspad等編輯器的人,應該都知道我們可以設置一些標籤(編號通常由1到0)在檔案的某些地方,這些標籤可以讓使用者快速回到設置標籤的位置。

在VIM裡當然也有這個功能且更強大,但就某方面來講,也可以說以便利性或是上手速度來說也較不容易。今天這篇文章會由簡入難,先跟大家簡述一下VIM的書籤功能,接著再介紹如何使用VisualMark來打造一個簡單易用的書籤環境,最後會跟各位分享我在VIM裡常用的游標移動功能,這些功能能讓各位更快的將游標移到自己想到的位置。

有關VIM document裡有關游標移動的章節為[motion],關於[書籤]的部分請參考這裡。


VIM的書籤功能

VIM的書籤分成2大類,1)同檔案內可以編號由a-z,2)跨檔案可以由編號A-Z,這兩類的差別是第一種在每個檔案內都有自己的書籤a-z,第二種則是所有檔案共享,換句話說,你可以由檔案A藉著書籤的方式跳至該書籤的所在檔案。

書籤設置的方法為

m{a-zA-Z}

舉例來說在normal mode底下輸入ma,即會設置書籤a。而輸入mA則是建立跨檔案書籤。

跳到書籤處的方式為

`{a-zA-Z}

"`"為1左邊的那個鍵。

顯示書籤則為

:marks

使用後大家或許會發現VIM的書籤的有個致命的缺點,就是他不會在每行的最左邊顯示這裡有設置書籤及書籤編號,這個缺點可以用[ShowMarks]這個Plugin來改善,此外ShowMarks也提供一些不錯用的快速鍵,有需要的人自己看一下他們網頁,自己稍微試一下吧。


VisualMark

[VisualMark]是另一個VIM書籤Plugin,請看下圖,它提供了2個功能,一是反白有書籤的行(圖362行及369),二是逐一(根據行號)跳至書籤位置。這是我常用的功能,我也把他加入到我的功能表了。並且在vimrc加入這些key mapping。

"<F9> mark: in plugin filesmap
<F9> <Plug>Vm_toggle_signmap
<c-F9> <Plug>Vm_goto_next_signmap
<s-F9> <Plug>Vm_goto_prev_sign





游標的瞬間移動


我以前幾乎不用這些游標移動的功能,後來發現螢幕愈來愈大光按著j (即向下),從螢幕第一行要移到最後一行挺痛苦的,所以我這裡稍微跟大家分享我自己常用的有關游標移動的快速鍵。

h "左
j "下
k "左
l "右

"這類移到我多到在選擇單字時
w "移動到下一個單字字首
W "移動到下一個單字字首,移動更多(某些標點符號不停)
e "移動到下一個單字字尾
E "移動到下一個單字字尾,移動更多(某些標點符號不停)
H "移到螢幕首
M "移到螢幕中
L "移到螢幕尾

zz "將目前所在行移到螢幕中
zt "將目前所在行移到螢幕第一行
zb "將目前所在行移到螢幕最後一行

* "往前找出游標所在字串 (按 n、N 繼續找)
# "往後找出游標所在字串 (按 n、N 繼續找)
gd "將游標所在字串視為 local 變數,找到定義此 local 變數的地方 (如果有的話)


% "找披配的括號
[[ "找函數的開頭
]] "找下一個函數的開頭

2009/02/07

打造自己的VIM: 多檔編輯TabBar

看圖比較快,如下圖,[Tabbar]就是上面那個檔案列表視窗。Tabbar的操作包含了:
  • 切換至下個視窗 Ctrl-Tab
  • 切換至上個視窗 Ctrl-Shift-Tab
  • 切換至第n個視窗(n為數字0-9) Alt-n
  • 用滑鼠雙點Tab名,像下圖的[2:iliad.h]
安裝方式請至[他們的網頁]看一下唄。




此外,我在用他們的plugin時,有時會不小心在-TabBar-的window內,按到切換檔案的鍵(像是剛剛提到的Ctrl-Tab, Ctrl-Shift-Tab...),降會要被切換到的檔案顯示在-TabBar- window中,若是想避免這種情形,其實是可以加一個自動指令及函式在vimrc裡,這個指令會在當window切換時自動被執行,加法如下:

autocmd! BufEnter * nested call Test()
func! Test()
if bufname("%") == "-TabBar-"
wincmd j ; 跳到下面的視窗
endif
endfunction


但是這樣寫會造成滑鼠雙點Tab名切換視窗的功能失效,要用的人自己斟酌一下。

(2009/2/9 新增)

在使用TabBar還有一個情形也是十分困擾我的,每次下:bd刪除buffer時,時常下個被顯示的buffer不會按照順序,舉例來說,假使我現在看第4個buffer,若是我用:bd將它將它關掉,下個被打開的視窗通常不會按照一定的規律跳到第3或第5個buffer,這個壞處是有時要關一個以上的buffer,不能一直:bd的按,把大於某個號碼的視窗全部關掉。所以我加了一個小函式及快速鍵在vimrc,它能在關掉buffer後,一定跳到前一個buffer,程式如下。

map <C-F4> <ESC>:call CloseTab()<CR>
func! CloseTab()
let s:buf_nr = bufnr("%")
echo s:buf_nr
exec ":Tbbp "
exec ":bdelete ".s:buf_nr
endfunction


(2009/3/11 新增)

TabBar裡其實有一些設定很少被提到,但是卻很實用,若需要更多的說明可以自己打開tabar.vim來看看,大概在100出頭行的地方,亦或是直接在code裡的某處。我這裡提一些看起來比較有用到的。

g:Tb_MaxSize (Default = 1)
有時開的檔案太多,TabBar視窗會容不下那麼多檔案同時在一行內被顯示,但是使用者(我)會希望它可以分成2行被顯示,這時只要將這個值設定2就行。

g:Tb_TabWrap (Default = 0)
若開啟檔案數超過一行可顯示且g:Tb_MaxSize又設成大於1時,超過一行可顯示的字會折到下一行而造成最後一個檔案標籤斷了,若設成1則它不會讓標籤斷掉,會直接讓行尾標籤放到下一行行首。

g:Tb_SplitBelow (1 = below, 0 = above(Default))
將TabBar視窗放在上面or下面

g:Tb_VSplit (0:top, 1:left)
將TabBar放在上面or左邊


我自己是設定這些值
let g:Tb_MaxSize = 2
let g:Tb_TabWrap = 1

2009/02/05

打造自己的VIM: 修改目錄(功能表)

本篇文章是[Make vim more powerful cont. and prolog]系列的第一篇。這篇文章要分享我修改vim目錄的一些分得,保括了修改目錄的方法、指令、希望修改的地方,最後將會貼一些修改後的圖及我的設定檔給各位取用。

VIM目錄基本上都會有一串數字來代表他的位置,舉例來說Close這個menu item所在的位置為10.330,如下圖所示,若想要再插入一個目錄在它底下其位址可介於10.330到10.335之間。若想在10.330處插入一個子目錄則是位址可以由10.330.0開始到10.330.9999。



指令

跟目錄有關的指令,基本上我只用到:anoremenu(abbr. :an)這個指令,它是用來插入一個目錄,而且不能remap。譬如說我想插入一個指令
  1. 在10.320的位置
  2. 第一層的menu item name為File且快速鍵為f
  3. 第二層的menu item name為Open Tab ...且沒有快速鍵
  4. 提示的指令為:tabnew
  5. 真正執行的指令為:browse tabnew
這個指令如下:

:an 10.320 &File.Open\ Tab\.\.\.<TAB>:tabnew :browse tabnew<CR>

要注意的是有些特殊字元必需用"\"來跳脫,像是"."或" "。另外<TAB>是換行的意思。

此外,若是想插入一個分隔線則指令如下:

:an 10.400 &File.-SEP2-

其中-SEP2-,同一階的目錄下名字必需不同。

若是想知道更多指令,亦或是針對不同mode出現的目錄,就自行參考[vim document usr_42]。此外,如果有人有興趣瞭解script基本語法,像是流程控制、變數型態、變數類型等等,可再自己看一下[vim document usr_41]。


目錄設定檔在哪?

可以用:version指令找到,截圖如下:



我想要改成...

在修改前,先列一下我們想要修改的地方吧:
  • 加入我自己的快速鍵
  • 把不會用到的功能刪掉
  • 一些我認為它擺錯地方的目錄移到正確的地方

修改後的結果...

Edit menu: 擴充了Find的指令,像是Find Files or Find in Files,還有一些有關設定的都放在這。


Tools menu: 加了不少自己工具,像是Code Trace、Virsual Mark等等,這些功能在之後的文章才會介紹。


View menu: 又加了不少特殊功能,F5到F7都是,這些都後面幾篇文章會介紹。



結論

「師父引入門,修行在個人」學習vim也是這樣,有心想要修改自己目錄的人都應該要自己開一下$VIMRUNTIME\menu.vim有看看,並且視自己的需求打造自己的編輯器,改過一些東西后就會發覺原來改目錄那麼簡單。所以,還等什麼,快點把你的設定檔打開吧!

我的設定檔:http://sites.google.com/site/fcwunctu/vim

2009/02/04

VIM tip: 將tab取代成space及程式縮排方式

最近找到一個vim的網站 Daily VIM,是關於一些vim tips,裡頭有些東西還不錯,近期如果有空應該會轉錄一些我覺得比較有用的到我這來。

過去將全文裡的tabs取代成space我多半用取代的方式:

:%s/\t/ /cgi

另一作法,vim控制tab距離是靠tabstop (option),若是要根據tabstop來轉換tab成space,可以用這個方法:

:set expandtab
:retab!


其中,tabstop的值可以用類似這種指令來控制:

:set tabstop=2

稍微提一下,expandtab不是只用到這裡,若是想在編輯時自動將tab轉換成space可以用此命令。而取代所有tab成space的命令是retab這行。

在縮排程式時,有另一個常用的情形是這樣,將某行右移一個tab距離,即在normal mode時,輸入>>。若要左移則輸入<<。若要縮排一個區塊則可用V先選擇欲縮排的區塊,再輸入一個<>即可。當然,若是想要多縮幾個tab距離則可以按.來重覆上一個動作。這裡的一個tab距離寬度是用shiftwidth這個option來控制的。

另外,還有一種自動縮排的功能"=",跟之前一樣先選擇一塊區塊用V鍵,再輸入=則自動完成縮排。

2009/02/03

打造自己的VIM

一年前寫了一篇關於vim的文章[Make vim more powerful], 那篇文章裡介紹了許多scripts或是小技巧,但現在來看這些scripts or tips都有一些更好的方法來取代之。此外,再加上最近因為開始了我的第一份"正式"的工作,所以我花了點時間,又重新修改我的vim環境,讓他更適合現 在的工作。這篇文章主要要介紹大都以之前那篇文章以底,並再做些更新,最後會再附上我目前的設定給大家參考。

以下是我所做的所有增加或修改,並且在後面列出快速鍵(如果有的話):
  1. [menu修改]
  2. [多檔編輯TabBar]
  3. [檔案總管 NERD Tree] (F5)
  4. [多檔字串搜尋 EasyGrep] (f/)
  5. [檔案搜尋 FuzzyFinder] (ff)
  6. [Folding 程式碼摺疊]
  7. [Marks 書籤及游標移動] (F9)
  8. [QuickFix 編譯視窗] (F8)
  9. [函式列表 TagList] (F6)
  10. [源碼追蹤ctags+cscope及預覽視窗SrcExpl] (F7)
  11. [源碼補齊 SuperTab OmniCppComplete Code_Complete]
  12. [YouCompleteMe 源碼補齊,最近改用這個]
因為功能不少,所以我也順便修改了menu,除了把我自己增加的功能放到menu裡(提醒用),也把原本gvim那不合理(我自認為)的MenuItems排列大搬家了一下,所以首先我會先介紹menu如何修改,並接序的主題儘量以menu來以一貫之。

除了這些內容外,關於VIM的文章還有VIM tip系列,要找到他們可以直接從右邊的搜尋欄輸入vim tip即可找到他們,當然這些內容會持續的更新。


最後,我的設定檔可以在[這裡]抓,需要的人請自行取用。