Vim技能修炼教程(10) - 代码跳转
程序员功能
前面我们用了5讲的篇幅来讲基本编辑的基本功:第4讲是基本操作,第5讲是操作符,第6讲行编辑ex命令,第7讲可视模式,第8讲多窗口,第9讲缓冲区和标签页。
从这一讲开始,我们从通用功能向程序员常用功能挺进。首先我们从浏览代码最常用的跳转功能开始。
代码跳转
代码跳转,需要传说中的Exuberant Ctags工具,地址在:http://ctags.sourceforge.net/。
当然大家根据系统不同各显神通吧。比如我是macOS,就通过Homebrew来安装了。大家手头有什么”apt install”,”dnf install”,”zypper install”之类的独门兵器就往上用吧。
目前Exuberant ctags支持41种编程语言,具体列表在:http://ctags.sourceforge.net/languages.html
如果要支持这41种语言之外的,请看扩展指南:http://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 /{关键字} :正则表达式搜索
Vim技能修炼教程(10) - 代码跳转的更多相关文章
- Vim技能修炼教程(11) - 代码折叠
上一讲我们是程序员篇的第一讲,关于代码跳转.代码跳转是一个付出很少收获很大的功能.这一节我们开始一个收获很多,但是付出也相对多一点功能:代码折叠. 代码折叠 折叠的类型 折叠有下面几种类型: * Ma ...
- Vim技能修炼教程(2) - 语法高亮速成
语法高亮速成 我们继续在人间修行Vim技能之旅.上一次我们学习了如何通过vundle安装插件,这次我们迅速向写插件的方向挺进. 我们先学习一个最简单的语法高亮插件的写法. 语法高亮基本上是由三部分组成 ...
- Vim技能修炼教程(13) - 变量
VimScript变量 上节我们介绍了Python和Ruby来编写Vim插件的方式. 不过,Python和Ruby并不是所有的Vim都支持的功能,如果以最小依赖的原则来说,还是原汁原味的Vimscri ...
- Vim技能修炼教程(8) - 多窗口
多窗口 如果一个vim只能开一个窗口,那肯定是有点low.尤其是写代码的时候,打开多个文件是经常的需求. 速成教程 横着切成两个 :split 文件名 上下切换窗口 Ctrl-W加上上下键,可以实现上 ...
- Vim技能修炼教程(7) - 可视模式
可视模式 可视模式是与正常模式.插入模式一起并列的模式.它的作用就像图形化编辑器下用鼠标来选择一个块. 在vim下,使用正常模式和ex命令,连搜带跳行的,未必就比用鼠标慢. 我们先做一个例子找找感觉, ...
- Vim技能修炼教程(4) - 基本功
基本功 前面我们学会了插件管理器和如何实现语法高亮,相信大家已经从中体会到了vim插件的强大功能.现在,是时候回来补一补基本功了. Vi有三种主要模式,正常模式,插入模式和可视化模式.正常我们推荐的方 ...
- Vim技能修炼教程(3) - 语法高亮进阶
语法高亮进阶 首先我们复习一下上节学到的三个命令: * syntax match用于定义正则表达式和规则的对应 * highlight default定义配色方案 * highlight link将正 ...
- Vim技能修炼教程(1) - 使用vundle管理插件
世界上有两个伟大的编辑器:一个是emacs,一个是vi.它们从诞生以来,一直在Unix/Linux世界得到最广泛的支持. 尽管过了几十年,在Windows平台上和跨平台上有层出不穷的后起之秀不断挑战它 ...
- Vim技能修炼教程(16) - 浮点数计算函数
浮点数计算函数 这一节的所有函数,只有在vim编译时支持了+float时才有效. 三角函数 sin() : sine正弦函数 cos() : cosine余弦函数 tan() : tangent正切函 ...
随机推荐
- 学号20145322 《Java程序设计》第一周学习总结
学号20145322 <Java程序设计>第一周学习总结 教材学习内容总结 Java诞生于Sun公司,于1998年12月4日发布J2SE,约以两年为一周期推出重大版本更新. 2010年Or ...
- uboot下ext4load的用法
将sd卡的某个分区下的某个目录里的某个文件加载到内存的某个地址,示例如下: ext4load mmc 0:1 0xa0000000 /bin/vi
- 【网络结构】VGG-Net论文解析
目录 0. 论文链接 1. 概述 2. 网络结构 2.1 卷积核 2.2 池化核 2.3 全连接层 3. 训练 4. 测试 5. 其他 6.参考链接 @ 0. 论文链接 论文链接 1. 概述 VG ...
- windows组策略屏蔽
点“IP安全策略,在本地机器”——>创建IP安全策略---->下一步---->名称随便写,如输入阻止,然后一直点下一步,出现提示点是,一直到完成,这个时候就创建了一个名为“阻止”的策 ...
- ANDROID教程目录
html5 如何打包成apk,将H5封装成android应用APK文件的几种方法
- authentication vs authorization 验证与授权的区别
认证和授权的区别 Authentication vs. Authorization简单来说,认证(Authentication )是用来回答以下问题: 用户是谁 当前用户是否真的是他所代表的角色 通常 ...
- Java 类的构造器的调用顺序
规则如下: 对于一个复杂的对象,构建器的调用遵照下面的顺序: (1) 调用父类构建器.这个步骤会不断重复下去,首先得到构建的是分级结构的根部,然后是下一个子类,等等.直到抵达最深一层的子类. (2) ...
- spring mvc:视图解析器
ModelAndView对象中的view对象,可以使用字符串来让Spring框架进行解析获得适合的视图.而解析View的就是ViewResolver技术. ViewResolver的定义如下: pub ...
- bzoj1014: [JSOI2008]火星人prefix splay+hash+二分
Description 火星人最近研究了一种操作:求一个字串两个后缀的公共前缀.比方说,有这样一个字符串:madamimadam,我们将这个字符串的各个字符予以标号:序号: 1 2 3 4 5 6 7 ...
- [myeclipse]@override报错问题
@Override是JDK5 就已经有了,但有个小小的Bug,就是不支持对接口的实现,认为这不是Override 而JDK6 修正了这个Bug,无论是对父类的方法覆盖还是对接口的实现都可以加上@Ove ...