Vim技能修煉教程(10) - 代碼跳轉
程序員功能
前麵我們用了5講的篇幅來講基本編輯的基本功:第4講是基本操作,第5講是操作符,第6講行編輯ex命令,第7講可視模式,第8講多窗口,第9講緩衝區和標簽頁。
從這一講開始,我們從通用功能向程序員常用功能挺進。首先我們從瀏覽代碼最常用的跳轉功能開始。
代碼跳轉
代碼跳轉,需要傳說中的Exuberant Ctags工具,地址在:https://ctags.sourceforge.net/。
當然大家根據係統不同各顯神通吧。比如我是macOS,就通過Homebrew來安裝了。大家手頭有什麼"apt install","dnf install","zypper install"之類的獨門兵器就往上用吧。
目前Exuberant ctags支持41種編程語言,具體列表在:https://ctags.sourceforge.net/languages.html
如果要支持這41種語言之外的,請看擴展指南:https://ctags.sourceforge.net/EXTENDING.html
將來我們用到了再說,目前常用的語言要麼是ctags已經支持了,要麼是語言官方有支持了。基本上常用語言對於vim和emacs的支持還是比較全的。
代碼跳轉速成教程
- 首先我們用vim打開源代碼的根目錄。比如我打開Google的Magenta內核的源代碼根目錄
-
運行ctags重新生成索引
:!ctags -R
源代碼有較大變化後,就需要重新生成索引,否則索引就匹配不上了。
-
設置要查找的tags文件的路徑
先可以通過:set tags?來查查當前值:set tags?
默認值為:
tags=./tags,tags
如果想要設置的話,可以用:set tags=tags文件名的方式來設置。
我們因為是在源碼根目錄下剛生成,應該是能找到的,我們就直接進入下一步。 為了對照方便。我們可以充分利用之前學習的多窗口功能。比如用:vsplit豎切成兩半,對照著看。
- Ctrl-] 跳轉。比如我想查看mp_init()是實現啥的,光標定位過去之後,點擊"Ctrl-]",就跳轉到mp_init實現的部分:
如果要退回剛才的位置,功能鍵是Ctrl-t
-
如果想讓左右屏的內容重新同步一下,把左邊關了再重切就是了
:only | :vsplit
如果有重名怎麼辦?
對於沒有重名的,上麵的方式都工作得很好。但是很不幸,有時候,函數的定義是有重名的。這時候我們不方便簡單地用Ctrl-]了,我們有多選的g+Ctrl-]. 如圖的例子:arch_mp_send_api函數在arm64和x86上各有自己的實現,我們用g+Ctrl-]就會出現下麵的選擇列表:
不是非要跳到代碼上才能查
如果跳到代碼上查比較慢的話,我們也可以通過ex命令直接搜。
- :tag {關鍵字} - 相當於Ctrl-]
- :tjump {關鍵字} - 相當於g+Ctrl-]
除了全字匹配,:tag和:tjump命令還支持正則表達式搜索。
比如,用:tjump init,全字匹配能得到的結果如下:
# pri kind tag file
1 F m init kernel/include/app.h
struct:app_descriptor
app_init init;
2 F m init kernel/lib/unittest/include/unittest.h
struct:unitest_testcase_registration
unitest_testcase_init_fn_t init;
3 F m init system/ulib/ddk/include/ddk/driver.h
struct:mx_driver_ops
mx_status_t (*init)(void** out_ctx);
4 F m init system/ulib/mxio/private.h
struct:__anon440
bool init;
5 F f init third_party/uapp/dash/src/init.c
init() {
6 F v init third_party/uapp/dash/src/mkinit.c
char init[] = "\
7 F m init third_party/ulib/cryptolib/include/lib/crypto/cryptolib.h
struct:clHASH_vtab
void (* const init)(struct clHASH_CTX*);
8 F f init third_party/ulib/qrcodegen/qrcode.cpp
class:qrcodegen::ReedSolomonGenerator
Error ReedSolomonGenerator::init(size_t degree) {
9 FS f init system/core/acpisvc/main.c
static ACPI_STATUS init(void) {
10 FS f init system/uapp/gpt/gpt.c
static gpt_device_t* init(const char* dev, bool warn, int* out_fd) {
11 FS f init third_party/uapp/dash/src/mksyntax.c
init(void)
我們換成:tjump /init,則包含init所有的內容都能搜出來,要顯示好多屏:
# pri kind tag file
1 F m init kernel/include/app.h
struct:app_descriptor
app_init init;
2 F m init kernel/lib/unittest/include/unittest.h
struct:unitest_testcase_registration
unitest_testcase_init_fn_t init;
3 F m init system/ulib/ddk/include/ddk/driver.h
struct:mx_driver_ops
mx_status_t (*init)(void** out_ctx);
4 F m init system/ulib/mxio/private.h
struct:__anon440
bool init;
5 F f init third_party/uapp/dash/src/init.c
init() {
6 F v init third_party/uapp/dash/src/mkinit.c
char init[] = "\
7 F m init third_party/ulib/cryptolib/include/lib/crypto/cryptolib.h
struct:clHASH_vtab
void (* const init)(struct clHASH_CTX*);
8 F f init third_party/ulib/qrcodegen/qrcode.cpp
class:qrcodegen::ReedSolomonGenerator
Error ReedSolomonGenerator::init(size_t degree) {
9 FS f init system/core/acpisvc/main.c
static ACPI_STATUS init(void) {
10 FS f init system/uapp/gpt/gpt.c
static gpt_device_t* init(const char* dev, bool warn, int* out_fd) {
11 FS f init third_party/uapp/dash/src/mksyntax.c
init(void)
12 f Init kernel/arch/x86/hypervisor.cpp
class:PerCpu
status_t PerCpu::Init(const VmxInfo& info) {
13 f Init kernel/arch/x86/hypervisor.cpp
class:VmcsPerCpu
status_t VmcsPerCpu::Init(const VmxInfo& vmx_info) {
14 f Init kernel/dev/pcie/pcie_bridge.cpp
class:PcieBridge
status_t PcieBridge::Init(PcieUpstreamNode& upstream) {
15 f Init kernel/dev/pcie/pcie_device.cpp
class:PcieDevice
status_t PcieDevice::Init(PcieUpstreamNode& upstream) {
16 f Init kernel/kernel/vm/vm_aspace.cpp
class:VmAspace
status_t VmAspace::Init() {
17 f Init kernel/lib/magenta/io_mapping_dispatcher.cpp
class:IoMappingDispatcher
status_t IoMappingDispatcher::Init(const char* dbg_name,
18 f Init kernel/lib/mxtl/arena.cpp
class:mxtl::Arena
status_t Arena::Init(const char* name, size_t ob_size, size_t count) {
19 f Init kernel/lib/mxtl/arena.cpp
class:mxtl::Arena::Pool
void Arena::Pool::Init(const char* name, mxtl::RefPtr<VmMapping> mapping,
20 f Init system/dev/bus/virtio/block.cpp
class:virtio::BlockDevice
mx_status_t BlockDevice::Init() {
21 f Init system/dev/bus/virtio/gpu.cpp
class:virtio::GpuDevice
mx_status_t GpuDevice::Init() {
22 f Init system/dev/bus/virtio/ring.cpp
class:virtio::Ring
mx_status_t Ring::Init(uint16_t index, uint16_t count) {
-- More --
小結
- !ctags -R 生成索引
- :set tags=路徑 設定ctags生成的tags文件的路徑
- Ctrl-] 跳轉到唯一的或者是第一個匹配的代碼
- g+Ctrl-] 提供多選列表
- :tag {關鍵字} : ex命令版的Ctrl-]
- :tjump {關鍵字}: ex命令版的g+Ctrl-]
- :tag或:tjump /{關鍵字} :正則表達式搜索
最後更新:2017-07-12 22:05:08