標籤:

如何用 Vim 重構代碼?

例如:我現在有一個 cpp 類的成員函數的參數列表發生了變化,如何快速的更新整個工程中聲明,定義以及調用?


就我所知,Vim的重構工具並不太多,與Eclipse等集成IDE不一樣,Vim本身不集成語言相關、語義層面(semantic level)的複雜重構功能。而另一方面Vim提供非常方便好用的基於正則表達式的替換工具,我經常使用它來進行各種文件(包括各種語言的代碼、配置、文檔等)的批量處理(包括「重構」,也包括各種批量插入、刪除甚至生成代碼等)。以下是幾種常見情形的解決辦法:

如何對當前文件進行統一替換?

舉個例子,現在你希望把所有的foo()函數調用最後都加上一個NULL參數(當然,你可以優先考慮為該函數定義加上一個默認參數或者函數重載,這樣有更好的向後兼容性),你只需在normal mode輸入:

:%s/(foo([^)]*))/1, NULL)/g

即可將當前文件的所有調用進行替換。想了解更多,在normal mode輸入:

:h :s

如何對當前文件的一部分進行替換?

方法類似,只需要之前先用字元選取命令(v)或行選取命令(V)選取替換範圍即可(小提示:v/V可以配合查找一起使用,比如替換到下一次出現頂行右大括弧,你可以在normal mode輸入:

V/^}

如何對多個文件進行統一替換?

你可以使用argdo和bufdo兩個命令來實現。argdo用於對指定文件列表進行批量操作(指定文件列表使用args命令);bufdo對於所有的緩衝區(已打開的文件)進行批量操作。如:

:args *.txt
:argdo %s/(foo([^)]*))/1, NULL)/g | update

update命令用於保存修改。

如何在進行每一個替換前先確認?

很簡單,在每一個s命令的/g之後都加上c(表示confirm)即可。

如何只替換符合某種條件的行?

如果你的條件可以用正則表達式表達,則可以結合:g命令來使用。:g表示全局替換。比如,如果你想在所有出現bar的行進行替換,則可以在normal mode輸入:

:%g/bar/s/(foo([^)]*))/1, NULL)/g

在所有不出現bar的行進行替換,則可以在normal mode輸入:

:%g!/bar/s/(foo([^)]*))/1, NULL)/g

想了解更多,在normal mode輸入:

:h :g

我就是想要重構工具,可以有嗎?

可以有的,別忘了vim還有各式各樣的插件,比如這個:lhRefactor -
lh-vim -

lh-refactor: Generic refactoring plugin

若有其它問題,歡迎提問。


作為 exVim 的作者,我會推薦使用 exVim 來解決重構問題。

當然,客觀地說,在 Vim 里重構代碼,是非常艱巨的任務。因為Vim的工具鏈更偏重於靜態分析,文本分析。而對於好的重構工具,他需要一定的語義分析能力,並且不同的編程語言也會面臨不一樣的挑戰。簡單的說,靜態語言重構相對動態語言而言要輕鬆一些。

一般我會通過 exVim 中的 gg 或者 :GS & 指令來完成重構中的檢索操作。在通過 :GS 全局查找需要重構的 類名,變數名等信息後,我會在 exGlobalSearch 插件中進行一些必要的過濾操作,比如如果我希望檢索出所有調用 func_name 的地方,在 C++ 中,我會加入檢索過濾 -&>func_name 並在 exGlobalSearch 中做第二次過濾查找。

在完成檢索結果後,就是比較麻煩的替換操作。在 exVim 中,可以對 exGlobalSearch 中的查找結果做全局替換,通過指令 :SUB name1/name2/option 。這個指令和 Vim 中的 :s/name1/name2/opt 格式是一樣,只不過他做的事情是對每一條 exGlobalSearch 中過濾出得檢索結果做一次 Vim 的 :s 操作。

當然,由於執行的是文本替換,我個人並不是非常放心替換結果,所以,每次完成名字替換的重構操作後,我還會根據 exGlobalSearch 的檢索條目,一一檢查替換結果。

誠然Vim不是重構利器,但是在做諸如以上的文本操作時,工作量還是屬於可控的。對於靜態語言編程,這樣的方法已經足夠,如果是C語言編程,更有cscope這樣的靜態分析利器(對應exVim的 exCscope) 來幫助重構和代碼分析。

讓我比較迷茫的是動態語言(Lua, Javascript)的重構過程,目前我並沒有特別好的方法。所以也想借這個問題詢問。


在同一個文件里,使用多游標,這個很給力。terryma/vim-multiple-cursors · GitHub

在多個文件查找的情況,主要是有一個靠譜的文本搜索工具。推薦使用The Silver Searcher這個超快的搜過工具,和vim結合,需要用到一個更牛叉的插件Shougo/unite.vim · GitHub 。Unite.vim實現一套搜索的介面,實現有點像sublime的goto anywhere,不夠沒那麼強,可以直接接入ag。使用命令,

:Unite grep

不過,這個首先需要在命令行下有ag。其他的比如ack也可以。ag配置如下

" For ag
if executable("ag")
" Use ag in unite grep source.
let g:unite_source_grep_command = "ag"
let g:unite_source_grep_default_opts =
"--line-numbers --nocolor --nogroup --hidden --ignore " .
""".hg"" --ignore "".svn"" --ignore "".git"" --ignore "".bzr"""
let g:unite_source_grep_recursive_opt = ""
endif


easygrep插件不錯喲~


推薦一個插件 dyng/ctrlsf.vim · GitHub

使用ag, 在其editor模式中, 可以配合terryma/vim-multiple-cursors · GitHub 選中直接編輯保存, 批量修改所有文件

一些鍵位修改, 可以參考 wklken/k-vim · GitHub


vim連定位個symbol都困難,碰見複雜點template更是直接完犢子了,所以還是用大番茄+VS重構吧


cscope?


https://github.com/wsdjeg/DotFiles


補充一個,exVim,用過的最好用的VIM環境, exVim | exDev Studio


直接在vim使用!調用系統命令。

重構js推薦工具 grasp 很方便,支持各種語法和局部,選擇替換,整個項目替換等功能……


推薦閱讀:

Mac OS X Lion 下 Vi 怎麼回到行首/行尾以及 page up/page down 呢?
在 Vim 中移動游標需要先切換模式,是否很麻煩?
如何優雅地使用 Vim?
到底 VIM 能配置到多強大的程度?
你最愛的一個 Vim 命令是什麼?

TAG:Vim |