在Emacs中使用gdb調試程序
1 引言
Emacs除了具備強大的編輯功能,還能夠做爲調試工具gdb的前端,對程序進行調試。使用Emacs進行調試,能夠將程序的編寫與調試統一到Emacs中,並利用Emacs強大的功能輔助調試,是將Emacs做爲IDE使用的一項必備功能。 php
本文假定讀者具備基本的程序調試知識,但願知道在Emacs下進行基本調試的對應操做。水平有限,歡迎拍磚。 html
2 準備工做:將調試信息編譯在程序中
要使程序能被gdb調試,須要在編譯時加入調試所需的信息。若是使用gcc/g++進行編譯,須要使用參數-g,如: 前端
若是使用 ./confiugre && make 的編譯流程,能夠將使用以下方式引入-g參數: java
1
2 |
CFLAGS="-g" ./configuremake |
注意:不要加入任何優化參數(例如-O、-O2),否則調試時會有很靈異的現象發生…… node
3 開始:開啓Emacs的調試模式GUD
3.1 運行gdb
在編譯好程序後,就能夠開始調試了。直接運行gdb命令M-x gdb RET 在minibuffer中會出現須要執行的gdb命令。例如:gdb –annotate=3 prog 若是當前目錄下有可執行文件(一般剛好是須要調試的文件),gdb會在其後自動補上可執行文件,不然須要在minibuffer中補上要調試的程序文件名。 python
繼續回車,Emacs的GUD(Grand Unified Debugger)就會關聯到gdb並加載要調試的程序了。 linux
3.2 gdb界面
啓動gdb後,Emacs的界面會變成下面兩種之一: c++
GDB單窗格模式git
|
GDB多窗格模式程序員
|
能夠經過gdb-many-windows來切換這兩種界面佈局。
若是界面被打亂了(例如,在minibuffer中使用補全,查看幫助,從新編譯程序),能夠使用gdb-restore-windows來恢復界面佈局。
3.3 小結
命令 |
功能 |
gdb |
啓動gdb進行調試 |
gdb-many-windows |
切換單窗格/多窗格模式 |
gdb-restore-windows |
恢復窗格佈局 |
接下來就要開始調試程序了。
4 調試:設置斷點,控制程序流程
4.1 設置、刪除斷點
首先將斷點設置在要調試的地方。有兩種方法:
第一種,在要設置斷點的行左邊的fringe上單擊一下(就是文本左邊與滾動條之間空出的那一塊)。隱藏了fringe的朋友能夠M-x fringe-mode顯示它。
第二種,使用默認快捷鍵C-x C-a C-b, 或者 C-x <SPC>。它們都關聯到命令gud-break。
不管使用哪一種方法,fringe上都會在設置了斷點的行上顯示一個紅點,表示這行設了斷點:
同時,在斷點buffer中也會顯示已有的斷點信息:
斷點buffer
要刪除斷點,一樣有兩種對應的方法:在fringe的斷點上單擊一下,或者使用快捷鍵C-x C-a C-d(對應命令gud-remove)。
能夠在斷點buffer上單擊某個斷點切換到斷點所在位置。將光標移動到斷點處回車也有一樣的效果。
在斷點buffer上按空格鍵能夠切換斷點的激活和禁用狀態。
4.2 運行程序
設置好斷點後就能夠運行程序了。單擊工具欄上的就開始運行了。也能夠使用gud-go命令來運行。奇怪的是沒有任何默認快捷鍵綁定。
當程序運行到斷點時,程序會在斷點處停下來,並自動打開停下的語句所在的代碼文件。同時在fringe上在停下的語句處有三角形的指示器。
如今,咱們來一步步運行程序。
4.3 單步執行、運行到光標處
在調試中最經常使用的功能就是單步執行了。單步執行有兩種:將函數調用做爲一條語句執行(Next)和遇到函數時進入函數中進行調試(Step)。
要使用第一種方式,默認快捷鍵是C-x C-a C-n,對應命令爲gud-next。也能夠單擊工具欄上的 。
第二種方式的默認快捷鍵是C-x C-a C-s,對應命令爲gud-step。也能夠單擊工具欄上的 。
若是想跳出當前函數,能夠使用命令gud-finish,默認快捷鍵爲C-x C-a C-f,工具欄上有 可用。
在Emacs中還能夠運行到光標所在的行。使用命令gud-until便可,默認快捷鍵爲C-x C-a C-u。1
也能夠直接把當前語句指示器拖到任意一行,程序會運行到那一行再停下來。
4.4 繼續運行程序
在程序中斷後要繼續運行程序,依然是使用gud-go命令或 ,也能夠使用命令gud-cont,對應快捷鍵爲C-x C-a C-r。
4.5 小結
功能 |
命令 |
默認快捷鍵 |
添加斷點 |
gud-break |
C-x C-a C-b 或 C-x <SPC> |
刪除斷點 |
gud-remove |
C-x C-a C-d |
運行/繼續程序 |
gud-go |
無 |
單步執行,無視函數 |
gud-next |
C-x C-a C-n |
單步執行,進入函數 |
gud-step |
C-x C-a C-s |
跳出當前函數 |
gud-finish |
C-x C-a C-f |
運行到光標所在語句 |
gud-until |
C-x C-a C-u |
繼續運行程序 |
gud-cont |
C-x C-a C-r |
5 察看變量的值
調試的過程當中免不了要查看變動的值。Emacs提供了方便地功能讓咱們查看變量的值。
5.1 本地變量buffer
若是打開了gdb-many-windows,在右上角會顯示Locals buffer,其中顯示了當前局部變量的值。若是顯示的是寄存器(Register)buffer,單擊左邊的Locals就能夠切換到Locals buffer了。在其中能夠方便地觀察到各變量的值。
若是沒有打開gdb-many-windows,也能夠使用gdb-display-locals-buffer來顯示該buffer。
5.2 察看變量值
遇到一些Locals裏沒有顯示的變量,或者比較複雜的結構,就須要用到觀察變量的功能了。
將光標停留在要觀察的變量上,執行命令gud-watch,能夠將變量加入觀察列表中。默認的快捷鍵是C-x C-a C-w。也能夠使用工具欄上的 。
被觀察的變量將在Speedbar中顯示。對於複雜結構,能夠單擊Speedbar上的+號將其展開或收縮。在+號上按空格鍵也有相同的效果。2
有時候Emacs觀察的變量不是你所想要的,通常是a->b這類的狀況。這時能夠將要觀察的部分選中,再使用上述方法便可。
5.3 用工具提示顯示變量值
能夠用gud-tooltip-mode開啓或關閉工具提示。開啓後將鼠標指針停留在變量名上時將在工具提示中顯示變量的值。
5.4 小結
功能 |
命令 |
默認快捷鍵 |
觀察變量 |
gud-watch |
C-x C-a C-w |
展開/收縮變量 |
|
<SPC> |
開啓/關閉工具提示 |
gud-tooltip-mode |
|
6 輸入輸出
若是程序須要與標準輸入/輸出交互,那麼你極可能須要用到下面要介紹的功能。
6.1 單獨的IO buffer
默認來講,程序的輸入輸出是在gdb buffer裏顯示的。這樣輸出信息和gdb信息混合在一塊兒,閱讀起來很是不便。這時候,你須要把輸入輸出單獨顯示在一個buffer裏,方便查看。
使用gdb-use-separate-io-buffer,能夠在程序代碼buffer右側新建一個IO buffer,程序對標準輸入輸出的操做都會重定向到這裏。再執行一次該命令則會隱藏。
6.2 輸入數據
須要輸入數據的時候,只須要在IO buffer中輸入數據回車便可。已經輸入的數據會被加粗,以和輸出信息區分開來。
6.3 重定向到文件
有時候咱們已經準備好了用於輸入的數據在文件中,以免調試時煩瑣的輸入。這時候就須要在調試時進行輸入輸出重定向了。
要進行重定向,只能使用gdb自帶的功能。在gdb buffer中輸入 run < data.in > data.out 就能夠將標準輸入重定向到data.in,將標準輸出重定向到data.out了。
7 按鍵綁定
說實話,gud自帶的按鍵綁定實在是麻煩,使用一個功能要三次組合鍵才行,小姆指按Ctrl都按酸了。因此通常將經常使用的按鍵綁定在方便的位置,這樣纔能有和另的IDE同樣的快感。
如下是將F五、F七、F8分別綁定到gud-go、gud-step和gud-next的代碼:
1
2
3
4 |
(add-hook 'gdb-mode-hook '(lambda () (define-key c-mode-base-map [(f5)] 'gud-go) (define-key c-mode-base-map [(f7)] 'gud-step) (define-key c-mode-base-map [(f8)] 'gud-next))) |
之因此綁定到c-mode-base-map上,是由於我基本上在代碼buffer中調試。若是要在gdb-buffer中使用的話,須要使用gud-mode-map。若是想在全部buffer上使用的話,能夠綁定到全局按鍵中:
(global-set-key [(f5)] 'gud-go) |
8 結尾
有了調試功能,Emacs做爲一個IDE纔算是完整了。本文介紹了在Emacs下使用gdb調試的基本方法,Emacs的調試功能還遠不止這些,進一步學習可參閱 Emacs Manual 的 Debuggers 一節。
因爲我也是邊學邊寫,必定有許多不足或者錯誤,還請各位多多指教。
Footnotes:
1 注:我在使用時只有光標所在的行在當前行以後而且位於同一函數內才行,不然會跳到很奇怪的地方,還請高手指教。
2 我在使用過程當中常常出現展開沒反應,或者加入新元素後才展開,運行幾步才展開的狀況,求高人講解。
對初學者學習vim的建議
網上有很多人一方面對Vim
非常好奇,另外一方面又對Vim
表示出不屑一顧的鄙夷,更有甚者認爲使用Vim
的人只是裝逼
我不知道這種意識怎麼出現的,只以爲這種人很傻很天真,我也不指望這種人學會Vim
,假使學會,那他們可就真是用來「裝逼
」的了 初學者只需謹記如下幾點建議:
- 剛開始不要糾結於配置,網上找個配置好的版本先用上再說
- 初學不要看
Vim
枯燥的文檔,找幾篇清晰的入門教程學會基本的幾個操做就夠用了
- 或許你會以爲
Vim
某些地方用着不爽,那你能夠試着找找改變的方法,嘗試修改本身的配置文件
Vim
不是用來學的,學只是一個基礎,最終仍是得用,最好是每天都用
- 不要奢望有哪一個編輯器能比
Vim
更強大(Emacs
例外),目前來講是不可能的,用好你的Vim
就是
- 不要覺得用
Vim
就很厲害,不要將Vim
用做充門面的工具,要知道,這是一種很白癡的行爲
- 適合的就是最好的,若是你以爲現有的編輯器或
IDE
用起來很舒服,那你不必非要來學什麼Vim
,感受不夠舒服了再來學吧
- 儘可能不要轉入編輯器的宗教之爭,這沒有任何意義,有時間還不如寫點使用心得,造福後來者
- 本身有什麼新的發現和感悟、本身的配置文件有什麼高明之處,分享出來吧,
Vim
社區從來有崇尚分享的傳統
Vim
的學習曲線仍是比較陡峭的,通常來講,一週小成
,一月入門
,半年熟練
,一年掌握
,至少也要用上近一個月
才能體會到Vim
的妙處。慢慢來,無需着急,隨着熟練度的愈來愈高,使用起來也會愈來愈順手,你會發現,本身無形中已經愛上了Vim,
一旦你發現本身沒事幹時老喜歡按j
、k
這兩個鍵,那麼恭喜你,你已經入門了
有趣或者有用的網友回覆:
普通人的編輯利器Vim
若是你是一名程序員,那就千萬不要錯過vim,它真的爲程序員提供了太多貼心的功能。
- 1.支持幾乎全部語言類型
不誇張的說,vim真的是將這一點作到了極致,只要是你們知道的語言,大到c++,python,小到bash,sql,vim所有都默認支持了這些語言的語法高亮,自動縮進,等等。一個編輯器搞定全部源碼編寫,不用爲每門語言學習他的編輯器,下降學習成本,何樂而不爲?
- 2.支持各類語言的代碼自動補全和智能提示
詳見:vim所支持的自動完成詳解,把VIM打形成一個真正的IDE(3)
- 3.快速查找函數定義功能及顯示函數列表功能
vim+tags+taglist便可輕鬆實現上面的功能,功能上徹底能夠替代si或者vs.詳見:把VIM打形成一個真正的IDE(2),在Vim中使用ctags
- 4.支持相似textmate的代碼片斷功能
我目前使用的是snipMate,固然提供這種功能的插件可不僅這一個,你能夠有更多選擇~
- 5.集成編譯調試功能,快速定位編譯錯誤
vim提供了quickfix的功能,能夠集成gcc,g++,java,c#,python,php等各類語言的錯誤定位功能,極大提升了代碼編譯調試時的錯誤定位。參見:VIM-一鍵編譯單個源文件
- 6.開源
若是發現vim有bug,那麼大能夠本身去研究代碼修復~
- 7.跨平臺
在linux,windows,mac等多平臺都有相應的版本,不用擔憂跨平臺開發的問題!
- 8.支持插件,無限擴展本身想要的功能
vim自己有本身的腳本語言,若是你真的不想再多學一門語言,那也不是什麼大事,gvim7.3已經默認編譯支持了python,ruby,lua,perl等等腳本語言,用你喜歡的腳本語言開發去吧!(我愛python!),與emacs的lisp相比,vim自身的腳本語言確實有所欠缺,可是python較之lisp也算是旗鼓至關了吧
vim更像是一個超級終端,vim已經支持用python,lua,perl,ruby等多種腳本語言進行腳本編寫,只要你願意,你能夠用腳本語言實現任何你想要的功能,而後經過vim展現出來。
簡單來講,即
vim替你實現了一個通用的界面,而你只須要編寫你的邏輯代碼,而展示到屏幕這一層,就調用vim的接口,由vim來完成就能夠了~
這就是我所說的超級終端的定義,若是仍是不能理解,那咱們就用實例來講明吧!
編輯上的功能基本都同樣,你以爲vim或者emacs沒有那同樣功能只是你不知道,其實是內置或者可經過某個插件來完成,我以爲不一樣就在於vim注重的是編輯,編輯文件時按鍵方面比emacs方便,而emacs注重的是功能,各類功能集成在一塊兒,管理項目這些比vim方便
有一個著名的把用戶看成傻瓜的軟件,老是把句子的行首單詞Capitalize,並且自動把他認爲錯了的單詞改過來,每次我都要費盡心機想辦法,怎麼把這個功能關掉。這個軟件應該是office,我也經常爲這個功能頭痛
本質上來講,vim的哲學是瀏覽器+編輯器,因此瀏覽功能應該比emacs好些, 剩下的編輯功能,emacs靠lisp,vim靠python,都能實現那些你能想到的功能。
user experience來講, 插件管理,窗口管理, 其實二者都有待增強。
我用EMACS而不用VIM由於我不喜歡ESC,不喜歡模式切換。
但我會基本的VIM,我以爲VIM絕對不比EMACS差。
我以爲經過組合鍵,不停的編輯與移動,非快非快…… 而VIM要切來切去,切來切去…… 瘋
你不喜歡切換模式?不會是你的鍵盤Esc鍵沒有和佔用着好地盤的無用按鍵Capslock交換吧?改過鍵後,左手小指Esc切換模式使用vim,要多爽有多爽,爽到難以用語言來形容。並且不僅vim中爽,其餘應用程序中,使用Esc換掉CapsLock也很爽。
@,
其實說到底仍是看我的習慣,若是習慣輕量級,專業,和擊鍵輕鬆,vim比較好;
若是喜歡all in one,按組合鍵,emacs好。
並且emacs還能夠實現vim模式,最新的叫evil,名字還頗有意思,
evil邪惡的,同時也是emas vim layer
剛剛從vim轉過來,vim的輸入效率確實很高,發現emacs的快捷鍵太複雜太麻煩,啓動也要比vim慢的多。
可是vim有幾個缺點:
一、插件比較挫,自己用的插件語言的表達能力就不強,有點不三不四,感受執行效率也不高,功能也比較弱,應該換成一個更通用的腳本語言,這樣持續性才強。斷斷續續用了一年,我仍是沒有找到一個能正確格式化html文件的插件。我寫代碼的種類比較多,vim不能知足。
二、很是陡峭的學習曲線加上不同凡響的模式轉換機制,使得不少ide都不能很好的和vim integrate。eclipse和intellij都帶有emacs的快捷鍵集,可是沒有vim的(雖然有插件,可是都不太好用),由於操做方式差得太遠。
vim自己比較適合快速的輸入,但擴展性上確實有待提升。
在嵌入式平臺下, 有時候須要ssh進去配置. 編輯文件的只能是vim.
因此有時候在vim編輯的時候, 不知不覺會按到crtl鍵
source in sight 的自動搜索一個函數的 caller 這個功能我認爲 cscope的c-x s s, 是能夠實現的。我一直這麼用。
或者我還有個很笨的辦法,用doxyen生成程序的文檔,而後在文檔內能夠清晰的看到一個函數calling了哪些函數,有哪些caller,類圖,集成圖,協做圖,還有…不少。
令:emacs裏若是使用doxymacs,那麼能夠很是方便的生成doxyen格式的注。
cscope的確是使用tag作基礎的,並且符號位置和行號相關;大量修改以後的確須要從新更新cscope.files和cscope.out。可是,若是隻是微量修改,xcscope.el能夠檢查cscope數據庫的更新狀態,須要更新時會自動再次索引部分源文件,而後查找,結果仍是至關準確的。
對,效果很不錯,我就是用的xcscope.el,我寫了一個大量修改後更新cscope的腳本,找的結果倒是非常精準。
ctags也很好用。
@negatlov, 哈,我也有這個緣由,不過我主要仍是剛用emacs就以爲好用,可是就是一直用不慣vi,並且還曾經專門花時間學vi,仍是用不慣
[回覆]
曾經vim對emacs最大的優點就是長期使用emacs會致使左手小拇指健康情況惡化,甚至肌肉萎縮(衆所周知vim是esc到死,而emacs是ctrl到死),以致於許多用emacs的大牛如今只能單手coding。
若是按做者的方法把Esc改成c+]的話,只怕vimer也會在不久的未來面臨嚴重的亞健康問題。
目前相對合理的作法仍是交換caps和esc的鍵值(for vimer)或者交換caps和ctrl的鍵值(for emacser),具體的交換方法網上有不少,搜索就是。
另一個折中的辦法對蘋果用戶比較適用,設置蘋果的command鍵爲ctrl,這樣的話,小拇指的壓力就轉移到肌肉發達的大拇指上了。如此無疑會好上許多。
我已經告別 ESC 了.如今已經習慣了ctrl+[
(其實也就適應了不到一週)
我還看到了朋友說 將 capslock 與 esc 互換.這樣作也很好.
可是…
若是你在本機習慣了 capslock 與 esc 互換.換了其它機器 … 就不方便了 .
把emacs的ctrl映射到windows鍵盤的windows鍵就能夠用大拇指按ctrl了。原本emacs設計的時候,ctrl鍵就是用大拇指按的。用默認ctrl位置,用手掌壓,而不要用小拇指按也是省力和一種保護
有個高人專門寫文章研究了ctrl的問題,考證出 emacs發明時代的鍵盤佈局和現代鍵盤不一樣,當時的鍵盤ctrl鍵在大拇指可及的位置。最後做者建議,ctrl鍵正確的使用方法是使用手掌去按。
事實上 Vim 在 Insert 模式下也支持 Emacs 的不少按鍵,若是你只是想要一個編輯器的話,Emacs 反而很羅嗦。固然若是你須要學 Lisp 編程或者研究理想化的操做系統,Emacs 纔是有必要用的。
vim中 ctrl+[ 能夠代替esc... 我也習慣用ctrl+[
lz錯了,emacs不須要用小指。改下鍵盤vim和emacs均可以很是舒服,而且能夠同時使用。我就是這麼幹的,有時用vim,有時用emacs。
說下個人作法:
1.esc和capslock兌換
2.左邊的control和alt兌換。
由於原來的emacs發明者用的鍵盤就相似這樣的。
至於兌換的方法,網上有不少,能夠搜下。
按鍵不是emacs和vim的根本區別。
vim ESC Ctrl-[ 替換爲CapsLock的方法
在 ~/.Xmodmap 中加入如下幾行,沒有這個文件的話就建立一個:
remove Lock = Caps_Lock
keysym Escape = Caps_Lock
keysym Caps_Lock = Escape
add Lock = Caps_Lock
僅適用於 Unix.
注:若是想要 CapsLock 的功能,除了按 Escape 外,還能夠先所有小寫,而後 gU
圖形界面下,還能夠
- System -> Preferences -> Keyboard
- Select Layouts tab, then Layout Options
- Click on 'CapsLock key behavior'
- Click on 'Swap ESC and CapsLock'
http://www.cnblogs.com/sunza/archive/2011/08/20/2146935.html
#############################
我是如何從vim轉向Emacs的
http://emacser.com/from-vi-to-emacs.htm
之前,我屢次試圖從 vim 轉變到 emacs 都失敗了。緣由不少,主要緣由是 vim 的確一個很強大的 editor 不愧爲 emacs 的主要競爭對手,vim 不少強大的功能,很難在 emacs 中找到相應的功能,那個時候尚未水木Emacs版,若是有的話,狀況會好一些, 還有一個緣由就是我周圍幾乎沒有人用 emacs ,如今也是。
emacs 的入門比較 vim 要困難不少,我指的入門不是指簡單的使用,而是高效的使用。vim 的不少操做幾乎不須要配置就能夠完成了,可是若是離開我那些複雜的 .emacs 文件,我認爲 emacs 並不比 vim好。有了個人 .emacs , emacs 絕對是最好的 platform (not only an editor) ,由於他是個人軟件,一些我經常使用的功能,都是按照個人方式工做的,並且我能夠隨時實現我喜歡的功能,也許別人不喜歡這樣的操做,可是我喜歡,我可讓 emacs 讓我喜歡的方式操做。幾乎沒有其它軟件能夠作到這一點。
我轉變到 emacs 是一個痛苦和偶然的過程。我曾經煞有介事的「學習」 emacs , 寫了不少筆記,如今看來,很傻,emacs 不是學出來的,是用出來的,不少功能不是用腦子記住的,而是用手記住的,咱們不得不認可,有的時候肌肉的記憶能力,要比腦子的記憶能力強,並且快速,實用。不少體育運動員不就是用大量的訓練提升肌肉對動做的記憶嗎?
一次偶然的機會我發現了幾個 vim 沒法代替的幾個功能,因而我開始真正喜歡 emacs 了。(注:筆者作此文時,vim版本爲6.2)
首先是編寫 TeX 文件的時候,不少數學符號能夠快速的輸入,能夠方便的生成 dvi 文件,能夠快速的輸入 TeX 特有的特殊符號。
而後是 Python mode ,他是很是好的 Python 的 IDE ,能夠很容易的編寫 Python 程序,尤爲是 Python 程序中用縮進來表示語法結構,在Emacs中很容易處理縮進。很容易把一段代碼放入到Python 的解釋器中執行,而後在解釋器中交互的測試程序。參見 個人Python 學習筆記
一個編輯 C or C++ 的時候的一些功能,例如 auto insert 功能,hungry delete, M-SPC(M-x just-on-space) indent 功能 (TAB) ,在 emacs 中寫出來的程序,是最漂亮的格式。最重要的是還能夠選擇本身喜歡的 c style 。 固然 vim 中也能夠,可是默認的是用 tab 鍵格式化 ,這樣的缺點就是不能保證程序在全部的編輯器中都是同樣的效果,可是我之前也用 TAB 來 indent ,緣由是我不肯意輸入不少 space 。並且 vim 對從新 indent 一段代碼的功能也不是很好,儘管 g= 等等鍵也能夠工做,可是不如 emacs 中的好。
vim 中的不少編輯命令要比 emacs 快的多,只要輸入不多的鍵。
可是, 我認爲中 emacs 的理念是,有不少工做,作好不要讓用戶記住那些快鍵,按照用戶的習慣,猜測用戶(主人)的意思,默默的作好(討好用戶)就好了。
例如,在 C 中,咱們習慣用 tab 鍵來 indent 程序。那麼就用 tab 鍵來 完成 M-x indent-line 的功能。咱們常常在輸入分號以後, 輸入一個回車,那好,emacs 就根據上下文猜想應該回車的地方,自動回車。你想刪除不少空格,那好,emacs 就會根據上下文,只留下一個空格(M-x just-on-line) 或者空行(M-x delete-blank-line) ,若是你在只有一個空行下還要 M-x delete-blank-line ,那麼就把single blank line 也刪掉。
還有的功能也很好用。
1
2 |
C-c C-c (M-x comment-region) C-u C-c C-c uncomment-region |
還有自動補齊右邊括號,補齊引號的功能,還有補齊大花括號的功能。 參見Emacs 中自動添加有半邊括號的功能和寫C程序,輸入左大花擴號自動補齊不少東西
還有 abbrivate 擴展的功能。
還有 fly spell 的功能。 emacs 知道主人是個粗心的人自動提示主人錯了,可是 emacs 歷來不把主人當傻瓜,不會自做聰明的改動,只有主人真的認可說,我錯了 (按M-$)(注:我記不住具體的M-x 命令了,能夠用C-h k 查一個鍵的bind 的函數,記作 help key bind , 也能夠用 C-h w 記作 help where, 查找一個函數的快鍵是什麼 ) ,emacs 就提示不少可選的單詞,供主人選擇。 我記得有一個著名的把用戶看成傻瓜的軟件,老是把句子的行首單詞Capitalize,並且自動把他認爲錯了的單詞改過來,每次我都要費盡心機想辦法,怎麼把這個功能關掉。
還有 auto fill 的功能, M-q 也總能幹正確的事情。
還有 version control 的功能,emacs 幾乎不用主人親自備份文件了,他知道應該在合適的時候,備份文件。
還有 auto insert 的功能,他會自動根據環境,把當前的文件增長可執行權限,參見在保存文件的時候,會自動給腳本增長可執行權限
還能夠自動增長
#!/bin/bash or #!/bin/perl #!/bin/python
參見Emacs 在建立文件的時候,自動添加 template 的內容
header.el的擴展還能夠自動插入和更新 C 文件中的開頭的一些信息,包括文件名稱,建立日期,改動次數,紀錄誰在何時爲何作了修改。還有公司信息,做者信息,版權信息等等。參見輕輕鬆鬆爲源 程序增長文件頭信息
還有 emacs 有不少程序無縫結合 ,如 python, perl,octave(matlab), gdb, pydb 等等,emacs 是最好的 IDE 了。
總之,馴化了的 emacs 是你的忠實的奴僕,他會按照主人的方式工做,猜測主人的意圖。
然而,有的時候 emacs 是奔放的野馬,老是難以駕馭,要想emacs按照主人的意志工做,那麼主人就有義務詳細的告訴他該如何工做。
有兩種辦法,一種是向其餘主人學習,請教,按照他的辦法馴化emacs 。
另外一種辦法是掌握 emacs 的高級用法,只有瞭解他的語言,Elisp (Emacs Lisp) ,明白了 emacs 的語言,纔可以和 emacs 很好的交流,溝通, emacs 是一個很聽話的孩子。
若是要融入 emacs 的文化,或者叫理念,甚至叫宗教, 那麼就要 Hack 他的程序,瞭解他的五臟六腑,作一個 hacker。(注: hacker is NOT cracker ) 除了安裝emacs-x-xx.rpm 還要安裝 emacs-el.x-xx.rpm , 而後用 M-x find-function 看任何一個函數是如何實現的。
瀏覽了一下子,你會感到什麼是自由軟件,什麼是真正的自由。只要你願意,你能夠探索任何一個功能是怎麼實現的。
使用其餘的軟件的時候,我老是在想辦法發現軟件提供給我什麼功能,我怎樣按照軟件定義好的方式工做,我怎麼去適應軟件。
若是運氣很差,碰到一個自覺得是的軟件,我會以爲被軟件的做者愚弄。
若是運氣再差一點,我會以爲被軟件的做者侮辱,由於他把我當成傻瓜。
固然,也有運氣好的時候,例如 vim,他的編輯方式是最快的方式。
可是 emacs 不一樣,使用 emacs 的時候,我會想我喜歡用什麼樣的方式完成某個功能,大多數的狀況,均可以簡單的用global-set-key, or local-set-key 解決掉。若是功能很複雜,就查找一下是否是有人實現過了, emacs 的社區中有不少好心人, www.emacswiki.org 是一個好地方。若是沒有人實現,那麼就本身寫一個,而後貼到網上去。
開放,自由,這就是 emacs 。
emacs 老是想辦法如何適用用戶的方式,固然,缺點就是,初看上去 , emacs 不是很友好, 用戶須要學習如何配置emacs 。
如今我很喜歡擺弄 emacs , 我知道,只要我想獲得,emacs 通常是能夠作獲得, 固然我想的要合理,我想買彩票中500萬,emacs 確定作不到 ,並且還不能和其餘你須要的功能衝突。
有一項功能我一直沒有想辦法辦到,就是相似source in sight 的自動搜索一個函數的 caller ,自動成員變量補全,class browser 等等。這個功能很難,由於他要包含語言的語法語義分析。C++ 中的 template , typedef , #define #if , inline function, inner class (or structure, enum) , name space等等的語言特性,增長了其難度。
儘管 semantic 號稱能夠,可是和 source in sight 還有差距。我用了幾回,很差用, ECB 也是不三不四。
我認爲 semantic 的目標太大了,他要容納全部語言的語法語義模糊分析的功能,這個很難,儘管他的做者是大名鼎鼎的 eric 。
我仍是很喜歡 semantic ,由於我相信他行,因而我試圖hack semantic ,實現那些功能,儘管自動補全成員變量的功能,勉強能夠了,可是其餘複雜的功能,仍是很難實現。semantic 太複雜了。
可是一有時間,我仍是喜歡看上 semantic 幾眼。
我這篇文章是用 notepad 編輯的,因而順便列舉一些 emacs 和 notepad 相似的功能,參見相似Notepad 基本操做快速入門
用CEDET瀏覽和編輯C++代碼(續) – 使用Emacs 23.2內置的CEDET
http://emacser.com/built-in-cedet.htm
1 前言
今天,emacs-23.2發佈了,最大的改變就是集成進了CEDET,因此有了這個續, 介紹下build in CEDET和offical CEDET的區別,以及內置CEDET缺乏某些功能的替代方案。
PS1:雖然如今官方release版本是1.0pre7,內置的CEDET用cedet-version命令看輸入也是1.0pre7,可我總感受內置的CEDET用起來比官方版本慢不少,我猜測內置的CEDET可能沒升級到1.0pre7的release。
PS2:內置CEDET不支持emacs-lisp語言了,沒想明白是爲何。
2 semantic配置
2.1 基本配置
官方的CEDET經過semantic-load-enable-minimum-features等幾個函數來啓動,而內置的CEDET增長了一個單獨的minor mode,即semantic-mode,能夠經過(semantic-mode)命令來Enable或Disable。
(semantic-mode)是經過semantic-default-submodes這個變量來決定啓用哪些minor mode,默認的semantic-default-submodes包含了下面兩個minor mode:
- global-semantic-idle-scheduler-mode
- global-semanticdb-minor-mode
根據(semantic-mode)的文檔,semantic-default-submodes裏能夠設置下面這些minor mode:
- global-semanticdb-minor-mode
- global-semantic-idle-scheduler-mode
- global-semantic-idle-summary-mode
- global-semantic-idle-completions-mode
- global-semantic-decoration-mode
- global-semantic-highlight-func-mode
- global-semantic-stickyfunc-mode
- global-semantic-mru-bookmark-mode
能夠根據本身的須要設置,好比我開啓了下面4個minor mode:
1
2
3
4
5 |
(setq semantic-default-submodes '(global-semantic-idle-scheduler-mode
global-semanticdb-minor-mode
global-semantic-idle-summary-mode
global-semantic-mru-bookmark-mode)) (semantic-mode 1) |
另外,emacs-23.2的Tools菜單下下新增了」Source Code Parsers (Semantic)」菜單項,能夠經過這個菜單項來Enable和Disable semantic-mode,和命令(semantic-mode)的功能是同樣的。
此外,官方CEDET裏還有其它一些minor mode,如今基本上都還能夠用,好比我還打開了下面幾個:
1
2
3 |
(global-semantic-highlight-edits-mode (if window-system 1 -1)) (global-semantic-show-unmatched-syntax-mode 1) (global-semantic-show-parser-state-mode 1) |
關於system-include-dir的設置,還和之前同樣:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17 |
(defconst user-include-dirs
(list ".." "../include" "../inc" "../common" "../public" "../.." "../../include" "../../inc" "../../common" "../../public")) (defconst win32-include-dirs
(list "C:/MinGW/include" "C:/MinGW/include/c++/3.4.5" "C:/MinGW/include/c++/3.4.5/mingw32" "C:/MinGW/include/c++/3.4.5/backward" "C:/MinGW/lib/gcc/mingw32/3.4.5/include" "C:/Program Files/Microsoft Visual Studio/VC98/MFC/Include")) (let ((include-dirs user-include-dirs)) (when (eq system-type 'windows-nt) (setq include-dirs (append include-dirs win32-include-dirs))) (mapc (lambda (dir) (semantic-add-system-include dir 'c++-mode) (semantic-add-system-include dir 'c-mode)) include-dirs)) |
2.2 代碼跳轉
代碼跳轉和官方版本同樣仍是用semantic-ia-fast-jump命令,不過在emacs-23.2裏直接用這個命令可能會報下面的錯誤:
semantic-ia--fast-jump-helper: Symbol's function definition is void: semantic-analyze-tag-references |
這多是emacs的bug,semantic-analyze-tag-references這個函數是定義在semantic/analyze/refs.el這個文件中的,而semantic/ia.el裏寫的是(eval-when-compile (require ’semantic/analyze/refs)),因此運行時這個feature沒被load進來,咱們須要本身load一下:
(require 'semantic/analyze/refs) |
另外,官方CEDET裏semantic-ia-fast-jump後能夠經過命令semantic-mrub-switch-tags來回到曾經跳轉過的地方,不過在emacs-23.2裏會提示:
Semantic Bookmark ring is currently empty
這是由於semantic-ia-fast-jump會用函數push-mark把跳過的地方放到mark ring裏去,官方CEDET經過定義push-mark的advice把它也放到了semantic-mru-bookmark-ring裏去,semantic-mrub-switch-tags就是從semantic-mru-bookmark-ring來找位置的,但build in的CEDET裏把push-mark的advice去掉了,因此semantic-mru-bookmark-ring老是空的,個人辦法是把官方CEDET裏對push-mark的device拷貝到個人.emacs中來:
1
2
3
4
5
6
7
8 |
(defadvice push-mark (around semantic-mru-bookmark activate) "Push a mark at LOCATION with NOMSG and ACTIVATE passed to `push-mark'. If `semantic-mru-bookmark-mode' is active, also push a tag onto the mru bookmark stack." (semantic-mrub-push semantic-mru-bookmark-ring
(point) 'mark) ad-do-it) |
這樣,我之前寫的semantic-ia-fast-jump-back函數也能用了:
1
2
3
4
5
6
7
8
9
10 |
(defun semantic-ia-fast-jump-back () (interactive) (if (ring-empty-p (oref semantic-mru-bookmark-ring ring)) (error "Semantic Bookmark ring is currently empty")) (let* ((ring (oref semantic-mru-bookmark-ring ring)) (alist (semantic-mrub-ring-to-assoc-list ring)) (first (cdr (car alist)))) (if (semantic-equivalent-tag-p (oref first tag) (semantic-current-tag)) (setq first (cdr (car (cdr alist))))) (semantic-mrub-switch-tags first))) |
對這個函數須要說明一下:網友fangzhzh提過能夠用C-u C-space來跳回原來的mark,ahei說能夠用C-x C-x來跳回,可我測試這兩個按鍵好像跳得都有點亂,不能和semantic-ia-fast-jump的位置對應。我估計是這兩個key是跳回push-mark函數mark的位置,而push-mark不光CEDET用。個人需求是隻跳回semantic-ia-fast-jump曾經到過的地方,因此仍然保留了這個函數。
個人習慣仍是綁定到F12上:
1
2
3
4
5
6
7
8 |
(defun semantic-ia-fast-jump-or-back (&optional back) (interactive "P") (if back
(semantic-ia-fast-jump-back) (semantic-ia-fast-jump (point)))) (define-key semantic-mode-map [f12] 'semantic-ia-fast-jump-or-back) (define-key semantic-mode-map [C-f12] 'semantic-ia-fast-jump-or-back) (define-key semantic-mode-map [S-f12] 'semantic-ia-fast-jump-back) |
這兒多出來個semantic-ia-fast-jump-or-back函數,是由於我有時候在putty裏操做遠程的emacs,putty裏用不了S-f12這個key,因此我把f12綁定到semantic-ia-fast-jump-or-back上,這樣我能夠在putty裏經過C-u f12來跳回。
之前的semantic-analyze-proto-impl-toggle命令還能用:
(define-key semantic-mode-map [M-S-f12] 'semantic-analyze-proto-impl-toggle) |
2.3 代碼補全
官方版本里能夠用命令semantic-ia-complete-symbol-menu彈出semantic的補全菜單,不過這個命令在內置的CEDET裏不存在了(多是由於emacs官方版本認爲這個命令只在GUI下能用,不夠通用吧)。
不過,內置的CEDET卻是能夠經過命令complete-symbol(默認綁定到ESC-TAB)在另外一個buffer裏顯示可能補全的內容,像這樣:
semantic的complete-symbol
若是還但願能使用補全菜單,能夠使用其它插件,好比auto-complete或company-mode:company-mode-0.5已經能夠支持emacs內置的CEDET了;auto-complete-1.2對內置CEDET的支持還有些問題,關於如何配置auto-complete-1.2讓它支持內置的CEDET,我準備另外寫文章介紹。
3 EDE配置
ede和官方版本沒有區別,仍然用(global-ede-mode t)啓用就好了;不過emacs-23.3的Tools菜單下新增了」Project support (EDE)」菜單項,能夠完成global-ede-mode同樣的功能。
4 其它
4.1 可視化書籤
官方CEDET裏的visual-studio-bookmarks在內置的CEDET裏沒有了,因此我如今使用bm了。
4.2 pulse
pulse的功能在內置CEDET裏還存在,不過官方CEDET裏能夠用pulse-toggle-integration-advice函數來切換pulse,在內置CEDET裏這個函數消失了,如今的辦法是設置pulse-command-advice-flag變量來切換:
(setq pulse-command-advice-flag (if window-system 1 nil)) |
另外,官方版本里對下面這些函數設置了pulse的device:
- goto-line
- exchange-point-and-mark
- find-tag
- tags-search
- tags-loop-continue
- pop-tag-mark
- imenu-default-goto-function
內置版本里這些device都沒了,因此我直接把官方版本里的advice拷貝過來了:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29 |
(defadvice goto-line (after pulse-advice activate) "Cause the line that is `goto'd to pulse when the cursor gets there." (when (and pulse-command-advice-flag (interactive-p)) (pulse-momentary-highlight-one-line (point)))) (defadvice exchange-point-and-mark (after pulse-advice activate) "Cause the line that is `goto'd to pulse when the cursor gets there." (when (and pulse-command-advice-flag (interactive-p) (> (abs (- (point) (mark))) 400)) (pulse-momentary-highlight-one-line (point)))) (defadvice find-tag (after pulse-advice activate) "After going to a tag, pulse the line the cursor lands on." (when (and pulse-command-advice-flag (interactive-p)) (pulse-momentary-highlight-one-line (point)))) (defadvice tags-search (after pulse-advice activate) "After going to a hit, pulse the line the cursor lands on." (when (and pulse-command-advice-flag (interactive-p)) (pulse-momentary-highlight-one-line (point)))) (defadvice tags-loop-continue (after pulse-advice activate) "After going to a hit, pulse the line the cursor lands on." (when (and pulse-command-advice-flag (interactive-p)) (pulse-momentary-highlight-one-line (point)))) (defadvice pop-tag-mark (after pulse-advice activate) "After going to a hit, pulse the line the cursor lands on." (when (and pulse-command-advice-flag (interactive-p)) (pulse-momentary-highlight-one-line (point)))) (defadvice imenu-default-goto-function (after pulse-advice activate) "After going to a tag, pulse the line the cursor lands on." (when pulse-command-advice-flag
(pulse-momentary-highlight-one-line (point)))) |
另外,我還喜歡對下面這些函數定義pulse:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25 |
(defadvice cua-exchange-point-and-mark (after pulse-advice activate) "Cause the line that is `goto'd to pulse when the cursor gets there." (when (and pulse-command-advice-flag (interactive-p) (> (abs (- (point) (mark))) 400)) (pulse-momentary-highlight-one-line (point)))) (defadvice switch-to-buffer (after pulse-advice activate) "After switch-to-buffer, pulse the line the cursor lands on." (when (and pulse-command-advice-flag (interactive-p)) (pulse-momentary-highlight-one-line (point)))) (defadvice previous-buffer (after pulse-advice activate) "After previous-buffer, pulse the line the cursor lands on." (when (and pulse-command-advice-flag (interactive-p)) (pulse-momentary-highlight-one-line (point)))) (defadvice next-buffer (after pulse-advice activate) "After next-buffer, pulse the line the cursor lands on." (when (and pulse-command-advice-flag (interactive-p)) (pulse-momentary-highlight-one-line (point)))) (defadvice ido-switch-buffer (after pulse-advice activate) "After ido-switch-buffer, pulse the line the cursor lands on." (when (and pulse-command-advice-flag (interactive-p)) (pulse-momentary-highlight-one-line (point)))) (defadvice beginning-of-buffer (after pulse-advice activate) "After beginning-of-buffer, pulse the line the cursor lands on." (when (and pulse-command-advice-flag (interactive-p)) (pulse-momentary-highlight-one-line (point)))) |
4.3 h/cpp切換
官方CEDET裏的eassist.el沒有了,因此eassist-switch-h-cpp也沒了,如今我用sourcepair代替,sourcepair比eassist-switch-h-cpp更好用。
4.4 代碼摺疊
semantic-tag-folding.el沒有了,可我沒找到其它更好的替代方案,因此我把官方CEDET裏的semantic-tag-folding.el拷過來了,只須要把文件中(require ’semantic-decorate-mode)替換成(require ’semantic/decorate/mode)就能像之前同樣用了。
之前的senator-fold-tag功能還能夠使用。
最後插播個廣告,我關於內置CEDET的配置(最後那部分):http://github.com/meteor1113/dotemacs/blob/master/init-basic.el
在Emacs下用C/C++編程
http://emacser.com/emacs-cpp-dev.htm
1 參考文獻
按照慣例,我寫的文章在最開始處放參考文獻。
- hhuu @ newsmth 的《Emacs的平常生活》
- emacs 的文檔
- emacs 相關插件的文檔
2 序
用emacs寫程序也有5個年頭了,深切地體會到Emacs的強大。程序員有三種,一種是用vi的,一種是用emacs的,還有一種是其餘。或許有些誇張,但也頗能體現出emacs在程序員中的地位。
emacs最大的問題在於入門門檻較高。它看起來和多數人想象中的IDE相差甚遠,不少人看到emacs的第一眼就以爲它是個記事本(仍是個很是難用的記事本),稍微好些的每每以爲emacs也就是個ultraEditor而已,真是暴殄天物了。
我是個懶人,不喜歡記太多的快捷鍵,相信不少人和我同樣。因此從我後面的敘述能夠看出來,除了經常使用的命令都是快捷鍵外,其餘命令多數都是用M-x執行或者用鼠標點菜單。這僅僅是我的風格問題,先說明一下。
個人基本編程環境是:
- Debian GNU/Linux sid 操做系統
- Gnome 2.10.0 桌面環境
- GUN Emacs 23.0.0.1 for debian
- 使用 Gnu tool chains(gcc,make,gdb等等)
後面的敘述都基於上述環境。另外,本文主要針對C/C++程序開發,對其餘語言有些也適用,從難度上說,本文主要針對入門者。
本文確定會有不少錯誤,請指正, 謝謝。
3 基本流程
寫C++程序基本上是這麼幾個步驟:
- 編輯代碼
- 編寫Makefile
- 編譯代碼,修改編譯錯誤
- 調試代碼,修改邏輯錯誤
固然,每每還須要閱讀別人的代碼。
根據上述步驟,本文主要針對如下幾個方面:
- 配置Emacs,創建便利的代碼編輯環境和Makefile編寫環境。
- 在Emacs中編譯代碼,並修改編譯錯誤。
- 在Emacs中配合GDB調試程序。
- 利用cscope和ecb在emacs中閱讀代碼
4 基本環境設置
4.1 編輯環境配置
要寫C++程序,固然要用到cc-mode插件。CC-Mode本來是支持C語言的,但如今也能支持不少語言,好比 C++,Java,Objective-C,CORBA,AWK,Pike等等。CC-Mode是gnu-emacs的標準插件。若是您要求不高,那麼默認的配置或許就能知足。CC-Mode的各類行爲均可以自由地定製,您能夠參考這裏的文檔:CC-Mode參考文檔
這裏是個人.emacs文件中關於CC-Mode配置的部分,僅供參考:
1
2
3
4
5 |
;;;; CC-mode配置 http://cc-mode.sourceforge.net/ (require 'cc-mode) (c-set-offset 'inline-open 0) (c-set-offset 'friend '-) (c-set-offset 'substatement-open 0) |
1
2
3
4
5
6
7
8
9
10
11
12
13
14 |
;;;;個人C/C++語言編輯策略 (defun my-c-mode-common-hook() (setq tab-width 4 indent-tabs-mode nil) ;;; hungry-delete and auto-newline (c-toggle-auto-hungry-state 1) ;;按鍵定義 (define-key c-mode-base-map [(control \`)] 'hs-toggle-hiding) (define-key c-mode-base-map [(return)] 'newline-and-indent) (define-key c-mode-base-map [(f7)] 'compile) (define-key c-mode-base-map [(meta \`)] 'c-indent-command) ;; (define-key c-mode-base-map [(tab)] 'hippie-expand) (define-key c-mode-base-map [(tab)] 'my-indent-or-complete) (define-key c-mode-base-map [(meta ?/)] 'semantic-ia-complete-symbol-menu) |
注意一下,上面最後兩行是代碼自動補齊的快捷鍵。後面我會提到代碼自動補齊。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16 |
;;預處理設置 (setq c-macro-shrink-window-flag t) (setq c-macro-preprocessor "cpp") (setq c-macro-cppflags " ") (setq c-macro-prompt-flag t) (setq hs-minor-mode t) (setq abbrev-mode t) ) (add-hook 'c-mode-common-hook 'my-c-mode-common-hook) ;;;;個人C++語言編輯策略 (defun my-c++-mode-hook() (setq tab-width 4 indent-tabs-mode nil) (c-set-style "stroustrup") ;; (define-key c++-mode-map [f3] 'replace-regexp) ) |
4.2 自動補齊
自動補齊一般用的都是hippie-expand,我也用了很長時間。不過有時候會以爲這個自動補齊「傻」了一點,常會補齊出一些絕不相干的東西,由於hippie-expand是根據你敲過的詞和kill-ring等進行判斷的,並不對程序語法進行分析。
因此你還須要安裝一個代碼分析工具,而後把它加進hippie-expand的擴展策略裏去。咱們能夠用semantic。實際上,hippie-expand+semantic是我所發現的最好的選擇了,若是您有更好的,請您也告訴我一聲:)
Semantic是CEDET 中的一個工具,CEDET是Collection of Emacs Development Environment Tools的縮寫,它包含了好幾個工具,都挺不錯的。惋惜我只會用其中兩個。
您能夠在.emacs中對Semantic進行配置,下面是個人.emacs相關的配置,僅供參考:
導入cedet:
(load-file "~/lib/emacs-lisp/cedet-1.0pre3/common/cedet.el") |
配置Semantic的檢索範圍:
1
2
3 |
(setq semanticdb-project-roots (list (expand-file-name "/"))) |
自定義自動補齊命令,這部分是抄hhuu的,若是在單詞中間就補齊,不然就是tab。
1
2
3
4
5
6
7
8 |
(defun my-indent-or-complete () (interactive) (if (looking-at "\\>") (hippie-expand nil) (indent-for-tab-command)) ) (global-set-key [(control tab)] 'my-indent-or-complete) |
hippie的自動補齊策略,優先調用了senator的分析結果:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18 |
(autoload 'senator-try-expand-semantic "senator") (setq hippie-expand-try-functions-list '( senator-try-expand-semantic
try-expand-dabbrev
try-expand-dabbrev-visible
try-expand-dabbrev-all-buffers
try-expand-dabbrev-from-kill
try-expand-list try-expand-list-all-buffers
try-expand-line
try-expand-line-all-buffers
try-complete-file-name-partially
try-complete-file-name try-expand-whole-kill
) ) |
注意一下我前面CC-Mode配置中有這麼兩行:
1
2 |
(define-key c-mode-base-map [(tab)] 'my-indent-or-complete) (define-key c-mode-base-map [(meta ?/)] 'semantic-ia-complete-symbol-menu) |
這樣,咱們在CC-Mode中就能夠調用自定義的hippie補全了,快捷鍵是Tab。
另外,我還把快捷鍵「Alt + / 」綁定到了semantic-ia-complete-symbol-menu命令上,這是semantic的命令,它會根據分析結果彈出補齊的菜單,效果如圖顯示:
自動補齊效果圖
CEDET中還有一個不錯的工具是speedbar,你能夠用它在多個文件中快速切換。在個人.emacs配置文件裏,我把speedbar關聯到了F5上:
(global-set-key [(f5)] 'speedbar) |
這樣用F5就能夠調出speedbar,效果以下:
speedbar
不過說實話,我本身不多用到speedbar,我一般都是用dired配合bookmark使用:)
5 編譯和調試程序
按上面的配置,寫完程序和Makefile文件後,在Emacs源代碼窗口中按F7就能夠進行編譯。由於在my-c-mode-common-hook()函數裏,有這麼一行:
(define-key c-mode-base-map [(f7)] 'compile) |
默認狀況下,emacs的compile命令是調用make -k,我把它改爲了make。你也能夠把它改爲其餘的,好比gcc之類的。改下面的「make」就好了。
'(compile-command "make") |
Emacs會劃分一個窗格顯示編譯的消息,在編譯結束後,emacs會自動將編譯器的輸出和程序關聯起來,告訴你第幾行的程序有問題。直接在出錯的行號上按Enter,就能夠跳轉到相應文件的相應行。其實我一般都是用鼠標中鍵去點出錯行號:)
搞定了編譯錯誤後,接着要和邏輯錯誤鬥爭了。其實對簡單的程序來講,把中間結果打印到終端是最簡單好用的調試辦法:)不過稍微複雜點的程序就會暈菜了,這時咱們就須要拿gdb跟蹤程序流程了。
你用下面的命令就能夠啓動gdb了。
M-x gdb
一般我喜歡進入gdb-many-windows模式,這樣就會把一個Frame劃分爲5個窗格,同時顯示:gdb命令窗口,當前局部變量,程序文本,調用棧和斷點。
gdb的命令就不在這裏說了,它的文檔幾乎處處都是。emacs把gdb的命令和快捷鍵作了綁定,對於經常使用的命令,仍是輸入快捷鍵比較方便。好比,C-c C-n是Next line,C-c C-s是step in,其實用的最多的快捷鍵也就是這兩個。
下面是個人gdb效果圖:
GDB
6 閱讀代碼
在emacs下讀代碼一般有三種工具,最簡單的是etags,最複雜的是ecb(emacs code browser),位於中間的是cscope。
etags和ctags同樣,只不過前者是用於emacs的,後者是用於vi的。我我的以爲etags功能稍稍顯得不夠用一點,固然,也多是我用的很差:) 歡迎大牛指導。
使用tags以前要先對源代碼分析創建tags文件,在代碼所在目錄中運行:etags -R 便可。
我經常使用的就這幾個命令和快捷鍵:
M-x visit-tags-table <RET> FILE <RET> 選擇tags文件
M-. [TAG] <RET> 訪問標籤
M-* 返回
C-u M-. 尋找標籤的下一個定義
ecb聽說功能強大,可是太複雜了,我懶得折騰它。誰搞定了教教我吧:) 下面是一張ecb的效果圖。
cscope是我感受比較合適的一個工具。它實際上是一個獨立的軟件,徹底能夠脫離vi和emacs使用。可是結合emacs的強大功能,cscope就顯得更加方便了。GNU Emacs默認自帶cscope的支持。在使用以前,cscope也須要對代碼進行索引。在emacs中能夠這樣作:
C-c s a 設定初始化的目錄,通常是你代碼的根目錄
C-s s I 對目錄中的相關文件創建列表並進行索引
建完索引以後,你就能夠用cscope在代碼裏遊蕩了。經常使用的一些命令以下:
C-c s s 序找符號
C-c s g 尋找全局的定義
C-c s c 看看指定函數被哪些函數所調用
C-c s C 看看指定函數調用了哪些函數
C-c s e 尋找正則表達式
C-c s f 尋找文件
C-c s i 看看指定的文件被哪些文件include
上面這些快捷鍵其實我本身也經常記不全,不要緊,擡頭看看上面的菜單欄,有一欄就是Cscope,這些命令裏頭都有:)
貼一個cscope的效果圖吧:
cscope
寫完了。但願這篇文章對您能有一些用處。有問題或建議能夠和我 聯繫。
用CEDET瀏覽和編輯C++代碼
http://emacser.com/cedet.htm
2 簡介
cedet是一堆徹底用elisp實現的emacs工具的集合,主要有:
2.1 EDE
用來管理項目,它能夠把emacs模擬得像一個IDE那樣,把一堆文件做爲一個project來管理。
2.2 Semantic
Semantic應該是cedet裏用得最多的組件了,代碼間跳轉和自動補全這兩大功能都是經過semantic來實現的。
2.3 SRecode
SRecode是一個模板系統,經過一些預約義的模板,能夠很快地插入一段代碼。我的以爲這個功能跟msf-abbrev和yasnippet的功能有些相似。
2.4 Cogre
全稱叫」Connected Graph Editor」,主要和圖形相關,好比能夠用它來爲C++類生成UML圖。
2.5 Speedbar
Speedbar能夠單首創建一個frame,用於顯示目錄樹,函數列表等等。這個組件已經包含在emacs官方發佈包中。
2.6 EIEIO
EIEIO是一個底層庫,它爲elisp加入了OO支持。cedet的其它組件都依賴於EIEIO。
3 安裝
安裝就很少說了,這兒詳細說明了如何下載安裝。
要注意的是經過cvs下載必需要編譯後才能用,而官方發佈後的包能夠直接解壓不編譯也是能用。
安裝完後首先固然要load它(確保安裝的路徑已經在load-path中了):
4 semantic配置
4.1 功能介紹
通常裝插件的思路,都是先load而後enable某個minor mode。cedet基本上也遵循這個規則,不過有點區別是semantic定義了不少個mode,要是挨個去enable,用戶可能就要罵娘了,因此cedet的做者Eric定義了幾個方便使用的函數,這些函數會自動幫你enable某些minor mode,大概有這麼幾個:
1
2
3
4
5 |
(semantic-load-enable-minimum-features) (semantic-load-enable-code-helpers) (semantic-load-enable-guady-code-helpers) (semantic-load-enable-excessive-code-helpers) (semantic-load-enable-semantic-debugging-helpers) |
簡單介紹一下各個函數的功能:
4.1.1 semantic-load-enable-minimum-features
這個函數開啓了最基本的三個特性:
- semantic-idle-scheduler-mode
enable這個mode讓cedet在emacs空閒的時候自動分析buffer內容,好比正在編輯的buffer內容改變後。這個mode通常應該是須要enable的,若是沒有enable這個mode,那只有手工觸發纔會讓cedet從新分析。
- semanticdb-minor-mode
semanticdb是semantic用來保存分析後的內容的,因此也是應該enable的。
- semanticdb-load-ebrowse-caches
這個feature我不是很肯定,大概的意思好像是semantic能夠利用ebrowse的結果。這個feature大概就是把ebrowse生成的文件load給semantic使用。(要是誰瞭解這個feature具體意義請告訴我下)
4.1.2 semantic-load-enable-code-helpers
這個函數除enable semantic-load-enable-minimum-features外,還包括:
- imenu
這個feature可讓imenu顯示semantic分析出的類,函數等tags。如圖:
imenu顯示semantic分析出的類
- semantic-idle-summary-mode
打開這個mode以後,光標停留在一個類/函數等tag上時,會在minibuffer顯示出這個函數原型,如圖:
用ssemantic在minibuffer顯示函數原型
- senator-minor-mode
senator開啓以後,會在emacs上增長一個senator的菜單,能夠經過菜單在當前文件的各個tag之間先後移動,跳轉;還能夠在裏面方便地打開/關閉某個feature;還有另一些實用的功能,看看菜單大概就能明白:
senator菜單
- semantic-mru-bookmark-mode
cedet有tag跳轉的功能,可是常常跳轉完後還須要跳回剛纔的位置,這時候就須要mru-bookmark-mode了。打開這個mode以後,每次跳轉semantic都會把位置看成書籤同樣記錄下來,之後能夠經過M-x semantic-mrub-switch-tags(綁定到按鍵C-x B上)來選擇跳回之前的任意一個位置。
4.1.3 semantic-load-enable-gaudy-code-helpers
這個函數除enable semantic-load-enable-code-helpers以外,還包括:
- semantic-stickyfunc-mode
這個mode會根據光標位置把當前函數名顯示在buffer頂上,如圖:
在head-line上顯示函數名
這個mode我以爲用處不大,由於基本上能夠用which-func-mode代替。並且我習慣打開tabbar-mode,這個mode會覆蓋tabbar-mode,因此我是不打開它的。
- semantic-decoration-mode
打開這個mode後,semantic會在類/函數等tag上方加一條藍色的線,源文件很大的時候用它能夠提示出哪些是類和函數的頭。如圖:
semantic標記函數頭
- semantic-idle-completions-mode
這個mode打開後,光標在某處停留一段時間後,semantic會自動提示此處能夠補全的內容。好比下面這段代碼:
semantic自動補全當前光標內容
若是把光標停留在」this->」的後面,稍隔一會會提示:
semantic自動補全當前光標內容
若是提示的函數不是須要的,按TAB鍵能夠在各個可能的函數之間循環,按回車就能夠肯定了。
4.1.4 semantic-load-enable-excessive-code-helpers
這個函數除enable semantic-load-enable-gaudy-code-helpers以外,還包括:
- semantic-highlight-func-mode
打開這個mode的話,semantic會用灰的底色把光標所在函數名高亮顯示,以下圖中,函數Delete被高亮了,而LexicalCast沒被高亮:
semantic高亮當前函數
- semantic-idle-tag-highlight-mode
用過XCode或eclipse的人應該會喜歡高亮光標處變量的功能:就是在函數內部,光標停留在一個變量上,整個函數內部用這個變量的地方都高亮了。在emacs裏只要打開semantic-idle-tag-highlight-mode,光標在變量處停留一會,就會把相同的變量全都高亮,好比下圖中的變量mAddr:
semantic智能高亮當前符號
semantic的這個tag-highlight雖然智能,但是我感受它顯示得太慢了,因此我是用另外一個插件highlight-symbol來高亮的,這兒有它的介紹。
- semantic-decoration-on-*-members
把private和protected的函數用顏色標識出來,如圖:
semantic用顏色區分方法的訪問權限
- which-func-mode
這個其實就是emacs自帶的which-function-mode,把光標當前所在的函數名顯示在mode-line上。
4.1.5 semantic-load-enable-semantic-debugging-helpers
這個函數會enable幾個和調試semantic相關的特性:
- semantic-highlight-edits-mode
打開這個mode後,emacs會把最近修改過的內容高亮出來,以下圖中begin就是剛輸入的,因此用灰底色高亮了:
semantic高亮最近修改
隔一段時間後高亮會自動取消,不會一直高亮着讓整個buffer看起來混亂。
其實emacs自帶也有高亮修改內容的mode:highlight-changes-mode,它會用紅色的字體高亮全部修改的內容,可是不會自動取消,因此修改多了整個buffer就會亂七八糟糕。用semantic這個就好多了。
- semantic-show-unmatched-syntax-mode
這個mode會把semantic解析不了的內容用紅色下劃線標識出來,好比下面這個文件是從emacs源代碼中來的:
semantic用紅色下劃線標記不匹配的語法
- semantic-show-parser-state-mode
打開這個mode,semantic會在modeline上顯示出當前解析狀態,這是關閉mode的樣子:
這是打開mode的樣子:
能看出modeline上文件名前的橫線多了一條,其實倒數第二條就是用來顯示當前semantic解析狀態的:未解析時顯示爲」!」,正在解析時顯示」@」,解析完後顯示」-」,若是buffer修改後未從新解析顯示爲」^」。
semantic會在空閒時自動解析,另外能夠打開senator-minor-mode,按[C-c , ,]或者在senator菜單中選[Force Tag Refresh]強制它立刻解析。
4.2 基本配置
瞭解了上面這些feature,就能夠根據須要配置了,爲了使用semantic,至少須要開啓semantic-load-enable-minimum-features定義的三個基礎feature,其他的feature就能夠根據本身的須要開啓了。好比個人配置是:
1
2
3
4
5 |
;; (semantic-load-enable-minimum-features) (semantic-load-enable-code-helpers) ;; (semantic-load-enable-guady-code-helpers) ;; (semantic-load-enable-excessive-code-helpers) (semantic-load-enable-semantic-debugging-helpers) |
由於imenu,idle-summary-mode,senator-mode,mru-bookmark-mode都是我須要的。特別是senator,有時候我會碰到semantic等好久也不自動解析文件的問題,這時候就須要在senator菜單裏[Force Tag Refresh]一下了,而且senator還能夠經過菜單方便地打開和關閉某些mode,用起來仍是很方便的。
(semantic-load-enable-guady-code-helpers)和(semantic-load-enable-excessive-code-helpers)定義的那些feature,對我來講用處不大,並且我感受打開的話還會讓emacs反應變慢,因此我就不啓用了。
(semantic-load-enable-semantic-debugging-helpers)的幾個feature我都比較喜歡,因此我也啓用了。
有了這些基本配置,在emacs打開C和C++文件的時候,semantic就會自動解析文件。不過有個問題,一個cpp文件中確定會include不少頭文件,要想解析這個cpp的內容,頭文件的信息是必要的;可是頭文件可能和cpp放在一塊兒,也可能放在系統某個目錄下,semantic怎麼才能找到這個頭文件一塊兒解析呢?
semantic是這樣處理的:一、若是當前目錄中能找到,就直接在當前文件中讀取頭文件。二、若是當前目錄下沒有,就上系統INCLUDE目錄中去找(在Linux下,咱們通常使用gcc編譯器,semantic會自動調用gcc,取得gcc的INCLUDE目錄,好比/usr/include,/usr/local/include等,可是Windows下就不行了)。
BTW:不少文檔中提到須要load semantic-gcc,不過我沒有load它,在Linux下semantic仍然能自動把gcc的INCLUDE目錄加進來。
semantic這種找法確定會形成大量的頭文件找不到的(找不到頭文件還怎麼解析啊),有兩個問題須要解決:一、不少工程中都會把頭文件和實現文件分開放置,好比頭文件放在include(或者inc,public,common等)目錄中,實現文件放在src目錄中,這些目錄semantic是不能本身找的;二、在Windows下怎麼能讓semantic去找編譯器的INCLUDE目錄。
既然semantic不能自動查找找,那就只能咱們告訴semantic了,辦法是調用semantic-add-system-include函數,這個函數會根據mode把路徑加入到semantic-dependency-system-include-path裏去。下面是個人配置:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19 |
;; (setq semanticdb-project-roots (list (expand-file-name "/"))) (defconst cedet-user-include-dirs
(list ".." "../include" "../inc" "../common" "../public" "../.." "../../include" "../../inc" "../../common" "../../public")) (defconst cedet-win32-include-dirs
(list "C:/MinGW/include" "C:/MinGW/include/c++/3.4.5" "C:/MinGW/include/c++/3.4.5/mingw32" "C:/MinGW/include/c++/3.4.5/backward" "C:/MinGW/lib/gcc/mingw32/3.4.5/include" "C:/Program Files/Microsoft Visual Studio/VC98/MFC/Include")) (require 'semantic-c nil 'noerror) (let ((include-dirs cedet-user-include-dirs)) (when (eq system-type 'windows-nt) (setq include-dirs (append include-dirs cedet-win32-include-dirs))) (mapc (lambda (dir) (semantic-add-system-include dir 'c++-mode) (semantic-add-system-include dir 'c-mode)) include-dirs)) |
由於我在Windows下可能用MinGW和VC6,因此我把它們的include目錄都加進來了,要是你用別的編譯器,就改爲本身的目錄好了。
另外,我找了一些通常項目中常常用到的頭文件目錄名(include,inc,common,public),把它們也加進來了,這樣對於通常的項目來講基本上都能解析正確(好比咱們在項目中見到頭文件放在include目錄實現文件放在src目錄的方式,對src目錄下一個cpp文件,經過「../include」這個路徑就能找到對應的頭文件)。若是你的項目中還用了其它一些目錄名,也能夠配置在這兒。
上面配置中那一行(require ’semantic-c nil ‘noerror)是必須的,由於semantic的大部分功能是autoload的,若是不在這兒load semantic-c,那打開一個c文件時會自動load semantic-c,它會把semantic-dependency-system-include-path重設爲/usr/include,結果就形成前面自定義的include路徑丟失了。
順便說一下semanticdb-project-roots的配置,不少地方都說要把它配置成」/」,可是我在Linux/Mac/Windows都試驗過,不配這一行並沒什麼影響。
解析文件是semantic基本高級功能的基礎,正確地解析了文件咱們才能實現:代碼跳轉和代碼補全。
4.3 代碼跳轉
有了前面的配置,semantic自動就解析c/c++文件,解析完後跳轉就容易了:光標放在函數上,執行M-x semantic-ia-fast-jump,立刻就跳轉到函數的定義上了。若是跳不過去,那就檢查一下前面配置的INCLUDE路徑,是否是當前文件include的全部頭文件都能在INCLUDE中找到。若是檢查了不少遍都很差用,那就換個項目或者別的文件試試,確實存在semantic對某些文件支持不太好的狀況,好比boost。
semantic-ia-fast-jump這個功能如此經常使用,我就把它綁定到f12上去了。
(global-set-key [f12] 'semantic-ia-fast-jump) |
另外,前面咱們說過跳轉過去了咱們還須要跳回來,在打開mru-bookmark-mode的狀況下,按[C-x B],emacs會提示你跳回到哪一個地方,通常默認的就是上一次semantic-ia-fast-jump的位置,因此回車就能夠回去了。
不過看代碼時候我常常須要跳轉後立刻就跳回來,要按[C-x B] [RET]這麼多鍵實在有點麻煩,因此我寫了個函數不提示直接就跳回上次的位置,並把它綁定到shift+f12上了:
1
2
3
4
5
6
7
8
9
10
11
12 |
(global-set-key [S-f12] (lambda () (interactive) (if (ring-empty-p (oref semantic-mru-bookmark-ring ring)) (error "Semantic Bookmark ring is currently empty")) (let* ((ring (oref semantic-mru-bookmark-ring ring)) (alist (semantic-mrub-ring-to-assoc-list ring)) (first (cdr (car alist)))) (if (semantic-equivalent-tag-p (oref first tag) (semantic-current-tag)) (setq first (cdr (car (cdr alist))))) (semantic-mrub-switch-tags first)))) |
除了semantic-ia-fast-jump能夠跳轉以外,其實semantic中還有兩個函數也有相似的功能:
- semantic-complete-jump-local
- semantic-complete-jump
看名字很容易看出來,前一個只能在當前buffer內跳轉,後一個能夠跳轉到其它文件。不過這兩個命令都須要用戶手工輸入要跳轉的Tag名,不能像semantic-ia-fast-jump那樣自動識別當前光標處單詞,因此瀏覽代碼時仍是semantic-ia-fast-jump舒服。
cedet還有個功能在函數和聲明和實現間跳轉,通常的,函數聲明放在h文件中,函數的實現放在cpp文件中,光標在函數體的時候經過M-x semantic-analyze-proto-impl-toggle能夠跳到函數聲明去,在聲明處再執行的話就會再跳回函數體,我把它綁定到M-S-F12上了:
(define-key c-mode-base-map [M-S-f12] 'semantic-analyze-proto-impl-toggle) |
不是這個功能不是十分準確,通常在cpp中函數實現處想跳到函數聲明處正常,可是從聲明處跳到實現處的話cedet不必定能找到cpp文件的位置。
4.4 代碼補全
semantic中有4個用來代碼補全的命令:
- senator-complete-symbol
- senator-completion-menu-popup
- semantic-ia-complete-symbol
- semantic-ia-complete-symbol-menu
senator-complete-symbol和semantic-ia-complete-symbol這兩個函數是新開一個buffer提示可能的補全內容;而senator-completion-menu-popup和semantic-ia-complete-symbol-menu會彈出一個補全菜單。
至於功能,以senator開頭的兩個函數是調用senator補全,另外兩個是調用semantic-ia補全。至於senator和semantic-ia的區別,http://alexott.net/en/writings/emacs-devenv/EmacsCedet.html#sec9是這樣解釋的:
「semantic-ia調用semantic-analyze-possible-completions函數來取得可能的補全內容,它能爲用戶提供精確的補全列表;而senator用了一個更簡單的的函數來獲取補全內容,因此有可能會提供錯誤的結果。」
也就是說semantic-ia的補全更智能一些。
至於semantic-ia這兩個補全選哪同樣就看各人喜愛了,我喜歡用semantic-ia-complete-symbol-menu,由於看起來更直觀一些,像這樣:
semantic的補全菜單
我喜歡把它綁定到[Alt+n]上:
(define-key c-mode-base-map (kbd "M-n") 'semantic-ia-complete-symbol-menu) |
不過semantic-ia-complete-symbol-menu只能用於GUI下,要是在終端下,就只能用semantic-ia-complete-symbol了。(終端下想要semantic-ia-complete-symbol同樣的結果能夠用別的插件,好比auto-complete或者company-mode)
若是啓用了semantic-idle-completions-mode,不用按鍵只須要光標在.或者->後面停一會semantic就會自動開始補全了。
若是你用cedet不能補全,檢查一下semantic是否是已經啓用了,個人emacs上常常出現第一次打開c++-mode時semantic沒自動啓用的狀況。看semantic是否正常有個直觀的方法就是senator,若是啓用了senator-minor-mode,打開c++文件時emacs會出現Senator菜單,若是沒有Senator菜單你能夠關掉再從新打開試試,要是仍然不出現菜單那就得檢查配置是否是有問題。
若是確認semantic啓用了仍然不能補全,就須要檢查INCLUDE路徑的配置,經過C-h v semantic-dependency-system-include-path RET檢查INCLUDE路徑,確保當前cpp中直接或間接include的頭文件都能在INCLUDE路徑中找到。
5 EDE配置
EDE是用來管理project的工具,用下面的代碼啓用它:
EDE會在emacs中加一個叫作「Project」的菜單:
EDE的Project菜單
經過菜單能夠建立project,往project裏添加/移除文件;還能夠編譯project,不過好像只能經過已有的Makefile編譯。
另外EDE還能夠經過Speedbar顯示整個project的目錄樹(見右邊的Speedbar):
用Speedbar顯示project的目錄樹
EDE能夠支持四種類型的project:
- Automake
- 手工寫的Makefile
- C++ Root project
- Simple project
而且EDE能解析Autoconf/Automake,若是打開一個文件時在當前或者上級目錄中能找到Makefile.am文件,EDE會自動解析文件(認爲這是一個Automake的project),識別出Makefile.am中定義的target和編譯需用到的文件;打開目錄樹的話EDE能由Makefile.am中涉及到的文件生成目錄樹(上圖的目錄樹就是EDE經過Makefile.am自動生成的)。
爲了讓semantic找到C/C++的頭文件,前面是經過調用semantic-add-system-include把系統中可能出現的INCLUDE目錄都告訴semantic的來實現的。其實semantic還能夠經過EDE識別project中特定的INCLUDE目錄,方法是在.emacs文件中定義C++ Root project,好比:
1
2
3
4
5
6
7
8
9
10
11 |
(setq libutil-project
(ede-cpp-root-project "libutil" :file "~/projects/libutil/configure.in" :system-include-path '("/home/meteor1113/projects/include" "/home/meteor1113/projects/common" "/home/meteor1113/projects/libutil/pub"))) (setq test-project
(ede-cpp-root-project "test" :file "~/test/Makefile" :system-include-path '("/test/include" "/usr/include/boost-1.42"))) |
上面定義了兩個project,而且設定了各個project各自的INCLUDE目錄。
不過這種方式有兩個缺點:
- 不能支持常見的Makefile/Makefile.am型project。
- 我不肯意爲每一個project都定義這樣一個project,對於天天都要本身寫代碼的項目生成個C++ Root project還能夠接受,有時候只是臨時閱讀一下其它項目,要是還要爲它寫個EDE的project配置就太麻煩了。
因此這個功能我也一直沒用過,有問題的請參考官方文檔。我以爲把全部可能的目錄都加進system-include裏更方便。
6 其它
6.1 可視化書籤
emacs有自帶的書籤功能(c-x r m, c-x r b, c-x r l),不過對於用了多年VC6的我來講仍是更習慣讓一個書籤能高亮顯示出來。cedet裏就帶了一個可視化的書籤,經過下面的語句能夠啓用它:
(enable-visual-studio-bookmarks) |
以後就能夠經過下面幾個按鍵操做書籤了:
- F2 在當前行設置或取消書籤
- C-F2 查找下一個書籤
- S-F2 查找上一個書籤
- C-S-F2 清空當前文件的全部書籤
看這個效果:
cedet的可視化標籤
有點遺憾的是這個書籤功能只能在當前buffer的書籤間跳轉。
6.2 pluse
使用semantic-ia-fast-jump跳轉時,cedet有個很酷的效果:在跳轉到的行上實現一個淡入淡出的效果。具體的分析和使用看這兒。
6.3 h/cpp切換
cedet的contrib目錄下有一些實用的小功能,好比eassist.el就提供了一個在C++的頭文件和實現文件間跳轉的小功能。
要使用這個功能首先要load它:
(require 'eassist nil 'noerror) |
以後就能夠經過命令M-x eassist-switch-h-cpp來切換了,我喜歡把它綁定到M-F12上:
(define-key c-mode-base-map [M-f12] 'eassist-switch-h-cpp) |
這個功能是依賴semantic的,也就是說經過cpp找頭文件時它也會上配置好的INCLUDE路徑中去查找,不過若是經過頭文件找cpp文件,好像只能找和頭文件所在的同一目錄了。
eassist-switch-h-cpp有個BUG:它是經過文件擴展名來匹配的(經過eassist-header-switches可配置),默認它能識別h/hpp/cpp/c/C/H/cc這幾個擴展名的文件;可是C++的擴展名還可能會有別的,好比c++,cxx等,對一個擴展名爲cxx的文件調用eassist-switch-h-cpp的話,它會建立一個新buffer顯示錯誤信息。因此我把eassist-header-switches配置爲:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17 |
(setq eassist-header-switches
'(("h" . ("cpp" "cxx" "c++" "CC" "cc" "C" "c" "mm" "m")) ("hh" . ("cc" "CC" "cpp" "cxx" "c++" "C")) ("hpp" . ("cpp" "cxx" "c++" "cc" "CC" "C")) ("hxx" . ("cxx" "cpp" "c++" "cc" "CC" "C")) ("h++" . ("c++" "cpp" "cxx" "cc" "CC" "C")) ("H" . ("C" "CC" "cc" "cpp" "cxx" "c++" "mm" "m")) ("HH" . ("CC" "cc" "C" "cpp" "cxx" "c++")) ("cpp" . ("hpp" "hxx" "h++" "HH" "hh" "H" "h")) ("cxx" . ("hxx" "hpp" "h++" "HH" "hh" "H" "h")) ("c++" . ("h++" "hpp" "hxx" "HH" "hh" "H" "h")) ("CC" . ("HH" "hh" "hpp" "hxx" "h++" "H" "h")) ("cc" . ("hh" "HH" "hpp" "hxx" "h++" "H" "h")) ("C" . ("hpp" "hxx" "h++" "HH" "hh" "H" "h")) ("c" . ("h")) ("m" . ("h")) ("mm" . ("h")))) |
基本上全部C/C++的擴展名都包含了,同時ObjectiveC也能夠用了。
6.4 代碼摺疊
6.4.1 semantic-tag-folding
從我開始用emacs開始就聽大蝦們說hs-minor-mode能夠實現代碼摺疊,因此個人.emacs裏一直把hs-minor-mode打開的,但是用了5年以後我發現仍是不習慣它的按鍵,另外也不是很喜歡它顯示的樣子,5年來Hide/Show這個菜單對我來講基本上是個擺設。
我期待像eclipse那樣能夠經過鼠標在直接點擊就能夠打開和摺疊代碼,這個功能在cedet也實現了(惋惜這麼長時間一直沒發現它),就是semantic-tag-folding.el(也在cedet的contrib目錄下)。
1
2 |
(require 'semantic-tag-folding nil 'noerror) (global-semantic-tag-folding-mode 1) |
看這個圖:
cedet的代碼摺疊
只要用鼠標點擊左側的小三角圖標就能夠打開或摺疊代碼了。箭頭向下的空心三角表示這段代碼能夠被摺疊,箭頭向右的實心三角表示這段代碼被打折過了。
爲了方便鍵盤操做,我把按鍵綁定到了[C-c , -]和[C-c , +]上(綁定這麼複雜的
按鍵主要是爲了和senator兼容,後面會講到senator實現代碼摺疊):
1
2 |
(define-key semantic-tag-folding-mode-map (kbd "C-c , -") 'semantic-tag-folding-fold-block) (define-key semantic-tag-folding-mode-map (kbd "C-c , +") 'semantic-tag-folding-show-block) |
同時它還提供了兩個函數能夠同時打開和摺疊整個buffer的全部代碼,分別是
semantic-tag-folding-fold-all和semantic-tag-folding-show-all,我把它們
綁定到了[C-_]和[C-+]上:
1
2 |
(define-key semantic-tag-folding-mode-map (kbd "C-_") 'semantic-tag-folding-fold-all) (define-key semantic-tag-folding-mode-map (kbd "C-+") 'semantic-tag-folding-show-all)) |
打開semantic-tag-folding-mode後,用gdb調試時不能點左側的fringe切換斷點了,因此我把C-?定義爲semantic-tag-folding-mode的切換鍵,在gdb調試時臨時把semantic-tag-folding關掉:
(global-set-key (kbd "C-?") 'global-semantic-tag-folding-mode) |
不過,semantic-tag-folding在終端下會有一點點小問題:終端下semantic-tag-folding在函數前面加了個「+」或「-」號,看下面這個圖:
終端下的semantic-tag-folding
雖然功能不受影響(除了不能用鼠標操做外,快捷鍵和GUI下是同樣的),不過代碼不能對齊了仍是令我有些不爽,因此終端下我是禁用semantic-tag-folding的,最終個人配置以下:
1
2
3
4
5
6
7 |
(when (and window-system (require 'semantic-tag-folding nil 'noerror)) (global-semantic-tag-folding-mode 1) (global-set-key (kbd "C-?") 'global-semantic-tag-folding-mode) (define-key semantic-tag-folding-mode-map (kbd "C-c , -") 'semantic-tag-folding-fold-block) (define-key semantic-tag-folding-mode-map (kbd "C-c , +") 'semantic-tag-folding-show-block) (define-key semantic-tag-folding-mode-map (kbd "C-_") 'semantic-tag-folding-fold-all) (define-key semantic-tag-folding-mode-map (kbd "C-+") 'semantic-tag-folding-show-all)) |
須要注意的是,semantic-tag-folding依賴於語法解析,也就是說必須等semantic解析完文件以後才能使用。若是找開文件在fringe處找不到空心三角,能夠[Force Tag Refresh]下,或者檢查下semantic是否配置正確。
6.4.2 senator-fold-tag
終端下不用semantic-tag-folding了,最好能有替代方案吧:首先能夠用回hs-minor-mode,此外cedet的senator也提供了一種代碼摺疊方案。
只要啓用了senator-minor-mode(emacs中會出現Senator菜單),就能夠經過M-x senator-fold-tag和M-x senator-unfold-tag來摺疊和打開代碼了,GUI和終端下均可以使用。
默認地,senator-fold-tag綁定到[C-c , -],senator-unfold-tag綁定到[C-c , +]上(因此前面我把semantic摺疊的快捷鍵也綁定到這兩個鍵上,這樣GUI和終端下快捷鍵就一致了)。不過senator裏好像沒有對應的fold-all和show-all方法。
negatlov 回覆:
四月 27th, 2010 at 1:22 下午
@ahei,
我比較討厭VI中按ESC鍵。這個設計讓我感受不太爽
[回覆]
ahei 回覆:
四月 27th, 2010 at 2:09 下午
呵呵,我也是,那麼遠的鍵,不過還好,C-c基本上99%的狀況下能代替ESC,我碰到的只有C-v I的狀況下不能代替
[回覆]
chapter7 回覆:
五月 1st, 2010 at 10:18 上午
@ahei,
VIM中 C-[ 是跟ESC等價的
[回覆]
ahei 回覆:
五月 1st, 2010 at 12:30 下午
呵呵,沒有C-c好按