閱讀463 返回首頁    go 阿裏雲 go 技術社區[雲棲]


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豎切成兩半,對照著看。

kernel_init

  • Ctrl-] 跳轉。比如我想查看mp_init()是實現啥的,光標定位過去之後,點擊"Ctrl-]",就跳轉到mp_init實現的部分:

mp_init

  • 如果要退回剛才的位置,功能鍵是Ctrl-t

  • 如果想讓左右屏的內容重新同步一下,把左邊關了再重切就是了

    :only | :vsplit
    

如果有重名怎麼辦?

對於沒有重名的,上麵的方式都工作得很好。但是很不幸,有時候,函數的定義是有重名的。這時候我們不方便簡單地用Ctrl-]了,我們有多選的g+Ctrl-]. 如圖的例子:arch_mp_send_api函數在arm64和x86上各有自己的實現,我們用g+Ctrl-]就會出現下麵的選擇列表:

arch_mp_send_api

不是非要跳到代碼上才能查

如果跳到代碼上查比較慢的話,我們也可以通過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

  上一篇:go  青萍之末 光伏“搶屋頂”風潮來襲
  下一篇:go  KAFKA介紹(分布式架構)