目录

Vim使用指南

可以使用已有的配置文件

安装

源码安装

拉取源代码:

1
git clone https://github.com/vim/vim

安装依赖:

1
sudo apt install git make clang libtool-bin

编译&安装:

1
2
3
4
cd src
make distclean  # if you build Vim before
make
sudo make install

如果需要安装Python依赖:

1
sudo apt install libpython3-dev

配置编译启用-python3选项:

1
2
3
4
# Makefile中取消一下的注释
CONF_OPT_PYTHON3 = --enable-python3interp
# 保存后执行
make reconfig

基本概念

Buffers

buffer就是内存中的一块空间,你可以在这里写入或编辑文本。当你在Vim中打开一个文件时,文件的数据就与一个buffer绑定。当你在Vim中打开3个文件,你就有3个buffers。

1
2
# 打开两个缓冲区
vim file1.js file2.js

但是实际上默认看到的是一个缓冲区,可以通过:buffers查看缓冲区:

./buffers-demo.png

Windows

一个window就是在buffer上的一个窗口,在Vim中,你同样可以拥有多个窗口。

./window-demo.png

Tabs

Tabs就是windows的集合。它就像窗口的布局。在大部分的现代文本编辑器(还有现代互联网浏览器)中,一个tab意味着打开一个文件/页面,当你关闭标签,相应的文件/页面就消失了。但在Vim中,tab并不表示打开了一个文件。当你在Vim中关闭一个tab,你并不是关闭一个文件。你仅仅关闭了窗口布局。

Register 寄存器

在vim中,寄存器是一个用于存储文本的内存区域,它可以存储文本、命令、宏等内容。

可视模式

高亮显示文本块并对其进行更改,是很多文本编辑器中的常见功能。 Vim也可以使用可视模式实现这一功能。Vim有三种可视模式:

  • v 逐字符可视模式
  • V 逐行可视模式
  • Ctrl-v 逐块可视模式
示例:跨多行编辑

如果我们有文本:

1
2
3
const one = "one"
const two = "two"
const three = "three"

我们需要在每一行的末尾都增加上;,我们可以如下操作:

  • ctrl-v 进入逐块模式,使用jj选到行尾
  • A 然后输入;
  • <esc> 退出可视模式

所有行的末尾便都加上了;

示例:递增数字

Vim有Ctrl-XCtrl-A命令来减少和增加数字。与可视模式一起使用时,可以跨多行递增数字。假定我们有如下的HTML元素:

1
2
3
4
5
<div id="app-1"></div>
<div id="app-1"></div>
<div id="app-1"></div>
<div id="app-1"></div>
<div id="app-1"></div>

有多个相同名称的id不是一个很好的方式,因此我们通过下面的方式是他们id递增:

  • 光标移动到第2行的1
  • ctrl-v 3j 启动逐块模式,并显示剩余的高亮1
  • g ctrl-A 逐行递增

标签 Tag

快速转到任意定义处,是文本编辑中一个非常有用的特性Vim中则使用标签来做到这一点。

而现代 Vim 不自带标签生成器,你需要配合标签生成器来配合使用。我们这里使用Universal ctags来说明:

1
2
# install on ubuntu linux ❗️ 这种方法安装的话可能会导致Tagbar使用有问题,建议还是使用源码安装
snap install universal-ctags

在安装好之后,可以通过以下命令生成一个基本标签:

1
2
# R 选项告诉 ctags 从当前位置 (.) 递归扫描文件。稍后,你应该在当前文件夹看到一个tags 文件
ctags -R .
示例:使用标签

假设我们有两个ruby文件one.rbtwo.rb,文件内容如下:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
## one.rb
class One
  def initialize
    puts "Initialized"
  end

  def donut
    puts "Bar"
  end
end
1
2
3
4
5
## two.rb
require './one'

one = One.new
one.donut

我们可以使用如下命令生成标签

1
ctags -R .

随后,我们便可以在vim中使用这些标签了。

在普通模式下,您可以使用Ctrl-]跳转到定义。在two.rb中,转到one.donut所在行,将光标移到donut处,按下Ctrl-]

颜色模式

Ref

如果我们使用sainnhe/edge 主题,我们会定义如下的配置:

1
2
3
if has('termguicolors')
  set termguicolors
endif

这个地方本质上是配置是否使用24位True color。

Vim语法

你只需要知道一个Vim语言的语法规则:

1
verb + noun # 动词 + 名词

而对于Vim中我们可以把操作符 (Operator)作为动词动作 (Motion)视为名词

示例:使用动词和名词的结合
  • 复制当前位置到行尾的所有内容

    1
    
    y$ # 因为y代表yank(复制),$代表跳转到当前行尾
    
  • 删除当前位置到下一个单词的开头

    1
    
    dw # 因为d代表delete(删除),w代表跳转到下一个词的开头
    
  • 修改当前位置到这个段落的结尾

    1
    
    c} # 因为c代表change,}代表跳转到这个段落结尾
    

动作motions也接受数字作为参数。

示例:使用动词和带参数的名词的结合
  • 向左拷贝两个字符 y2h
  • 删除后两个单词 d2w
  • 修改后面两行 c2j

文本通常是结构化的,特别是代码中,文本经常被放置在小括号、中括号、大括号、引号等当中。Vim提供了一种处理这种结构的文本对象的方法。

示例:操作文本对象
  • 删除括号内部内容但保留括号 di
  • 删除括号以及内部的内容 da{

Vim的结合性最强大之处体现在它和外部程序结合时,Vim有一个过滤操作符!可以用外部程序过滤我们的文本。

操作符 operator

可以使用:h operator查看 vim 中所有的操作符,以下是可用的操作符:

operator command remark
c c change
d d delete
y y 复制
g~ g~ 反转字符的大小写
gu gu 使得
gU gU 使得
! ! filter through an external program 执行外部的命令

动作 motion

在Vim中,motion(即movement)是你在编辑器中移动的方式。它们是在键入时以高速和精度移动光标的命令。有许多不同的motion命令,每个命令最适合用于不同类型和长度的移动。以下是一些常用的 motion:

motion remark example
h left h 光标左移一个字符
l right l 光标右移动一个字符
j down j 光标下移一行
k up k 光标上移一行
w 移动到下一个单词的开头 w
} 移动到下一个段落 }
$ 移动到行末尾 $
i + object Inner Text Object yi" 复制当前"abc"里面的abc
a + object Outer Text Object ya" 复制当前"abc"里面的"abc"

命令

点命令

在编辑文本时,我们应该尽可能地避免重复的动作。

而在vim中可以使用点命令重放上一个修改操作。当你使用普通模式下的命令来更新(添加,修改或者删除)当前缓冲区中的内容时,你就是在执行一个修改操作了。其中的例外是使用命令行命令进行的修改(以:开头的命令),这些命令不算作修改操作。

示例:使用点命令

假设我们有以下的文本:

1
2
3
let one = "1";
let two = "2";
let three = "3";

我们现在想将let都替换为const,则我们使用如下的操作:

  1. /let找到第一个位置,回车
  2. cwconst + <esc>完成替换
  3. n找到下一个位置
  4. . 重复修改操作

在这4步做完之后,结果如下:

1
2
3
const one = "1";
const two = "2";
let three = "3";

宏命令

宏命令可以自动完成一些普通的任务。其基本语法如下:

  • qa 开始记录动作到寄存器a
  • q 停止记录
  • @a 执行寄存器a中的宏
示例:使用宏命令

假设有以下文本,我们想把每一行都变成大写

1
2
3
4
5
hello
vim
macros
are
awesome

把光标移动到hello行首,然后执行如下的命令:

1
qa0gU$jq

可以分解该命令如下:

  • qa 录制宏到寄存器a
  • 0 移动到行首
  • gU$ 将从光标到行尾的字母变成大写
  • j 移动到下一行
  • q 停止记录

然后我们可以使用@a调用a宏,则记录可以成为:

1
2
3
4
5
HELLO
VIM
macros
are
awesome

常用操作

导航

移动

基本的方向键移动:

  • h
  • j
  • k
  • l

按照单词移动:

  • w 移动到一个单词的开头
  • e 移动到一个单词的末尾
  • b 移动到一个单词的开始
  • ge 移动到一个单词的结尾

当前行导航:

  • 0 移动到本行的第一个字符
  • ^ 移动到本行的第一个非空字符
  • g_ 移动到本行的最后一个非空字符
  • $ 移动到本行最后一个字符

句子段落导航:

  • ( 跳到前一个句子
  • ) 跳到后一个句子
  • { 跳到上一个段落
  • } 跳到下一个段落

滚动

  • Ctrl-e 向下滚动一行
  • Ctrl-d 向下滚动半屏
  • Ctrl-f 向下滚动一屏
  • Ctrl-y 向下滚动一行
  • Ctrl-u 向下滚动半屏
  • Ctrl-b 向下滚动一屏

匹配导航

程序员经常编辑含有代码的文件,这种文件内容会包含大量的小括号,中括号和大括号,并且可能会把你搞迷糊你当前到底在哪对括号里。 许多编程语言都用到了小括号,中括号和大括号,你可能会迷失于其中。 如果你在它们中的某一对括号中,你可以通过%跳到其中一个括号或另一个上(如果存在)。

示例:匹配导航示例
./match-nav.png

此外,还可以使用[{来跳转到{的开头处,或者使用]}跳到}处。

跳转(行号导航)

  • gg 跳转到第一行
  • G 跳转到最后一行
  • ng 跳转到第n
  • n% 跳转到文件的n%。

使用:123可以跳转到第123行。

搜索

在命令模式下,输入/加上需要搜索的内容即可,回车可以到高亮处。可以使用//重复上一个搜索。按*可以高亮出所有的匹配内容。

使用n键为下一个关键词

使用N键为上一个关键词

示例:搜索
./search-demo.png

编辑

输入

可以在命令模式中传递一个计数参数,便可以重复输入

1
10i

则输入的内容会被重复10遍。

撤销/恢复撤销

  • 撤销:命令模式u
  • 恢复撤销:命令默认ctrl + r

剪切/复制/粘贴

  • 单行复制:yy
  • 单行剪切:dd
  • 多行复制:nyy其中n表示数字,表示从光标开始的多少行
  • 多行剪切:ndd其中n表示数字,表示从光标开始的多少行
  • 粘贴:p

替换

简单的可以参考:【vim】批量替换文件内容

替换语法如下:

1
:[range]s/pattern/string/[option]

其中,pattern表示要被替换掉的字符串,可以使用正则表达式,string表示替代的字符串,range表示检索范围,缺省表示当前行,%表示整个文件,其中s表示替换操作。操作类型option有以下几种选项:

  • g 全局替换
  • c 进行确认
  • i 不区分大小写
示例:替换ubuntu的source.list

将原来的源替换成中科大的镜像源:

1
2
# 其中1,50表示1-50行范围,如果改成%就表示全局替换
:1,50s/archive.ubuntu.com/mirrors.ustc.edu.cn/g
示例:全局替换

源文本:

1
2
3
4
5
345
345
456
456345
345:

替换的语句:

1
:%s/345/123/g

替换之后的内容:

1
2
3
4
5
123
123
456
456123
123:

删除

删除行:可以使用:[range]d来删除行。

示例:删除全文
1
:%d
示例:删除1-20行
1
:1,20d

plugins 插件

在Vim中,一般会使用vim-plug来对vim的插件进行管理。在unix下可以使用如下脚本安装:

1
2
curl -fLo ~/.vim/autoload/plug.vim --create-dirs \
    https://raw.githubusercontent.com/junegunn/vim-plug/master/plug.vim

其基本用法如下: 在~/.vimrc中加入一个vim-plug的节:

  1. call plug#begin()开始
  2. 使用Plug命令列出要管理的插件
  3. call plug#end()结束

搜索

fzf.vim

fzf.vim是一个基于fzf模糊搜索引擎的Vim插件,它可以帮助用户更快速、更高效地查找和打开文件、缓冲区、标签、历史记录等内容。

使用vim-plug来安装fzf:

1
2
Plug 'junegunn/fzf', { 'do': { -> fzf#install() } }
Plug 'junegunn/fzf.vim'

fzf的基础语法如下:

  • ^ 表示前缀精确匹配。要搜索一个以"welcome"开头的短语:^welcom
  • $ 表示后缀精确匹配。要搜索一个以"my friends"结尾的短语:friends$
  • ' 表示精确匹配。要搜索短语"welcom my friends":'welcom my friends
  • | 表示或者匹配。要搜索"friends"或"foes":friends | foes
  • ! 表示反向匹配。要搜索一个包含"welcome"但不包含"friends"的短语:welcome !friends
示例:使用fzf.vim搜索文件

搜索文件

1
:Files

./fzf-search-file.png

示例:使用fzf.vim搜索Window

搜索文件内容

1
:Windows

./fzf-search-windows.png

Git

fugitive.vim

fugitive.vim是一个基于Git的Vim插件,它提供了许多Git操作的快捷方式和命令,可以帮助用户更方便地在Vim中使用Git。

使用vim-plug进行安装:

1
Plug 'tpope/vim-fugitive'

以下是插件的常用用法:

  • :Git 可以调用任何的git命令

Code

ALE

ALE(Asynchronous Lint Engine)是一个插件,在 NeoVim 0.2.0+ 和 Vim 8 中提供linting(语法检查和语义错误),并且在编辑文本文件时,并充当Vim语言服务器协议客户端。

使用vim-plug进行安装:

1
Plug 'dense-analysis/ale'

ALE充当language client,支持各种语言服务器协议功能,包括:

  • Diagnostics 诊断(通过语言服务器协议 linter)
  • :ALEGoToDefinition 跳转到定义
  • 自动补全
  • :ALEFindReferences 寻找引用
  • :ALEHover 悬浮信息
  • :ALESymbolSearch 符号查询
示例:ALE显示Go语言Lint

在使用之前,我们需要对ALE进行配置:

1
2
3
4
5
let g:ale_completion_enabled = 1
let g:ale_fixers = {
\   'go': ['gofmt', 'goimports', 'golines', 'gopls'],
\}
let g:ale_fix_on_save = 1

使用vim打开Go文件,然后可以看到文件中有>>标示表示错误: ./ale-go-lint.png

Tagbar

❗️ 使用之前需要安装ctags或者兼容ctags的一些制品,安装方法可以参考文档

使用vim-plug进行安装

1
Plug 'preservim/tagbar'
  • s 可以改变排序的方式:Name或者File Order

/posts/linux/tools/vim/Tagbar-preview.png

vim-gutentags

使用前需要按照文档 安装ctags。

Link:如何管理库文件tags

该插件可以管理tags文件,以及自动生成对应的tags文件。该插件甚至能够管理cscope文件的生成,可以设置:

1
let g:gutentags_modules = ['ctags', 'cscope']

vim-cscope

使用vim-plug进行安装(安装了一个镜像的):

1
Plug 'dr-kino/cscope-maps'

通常安装之后,还会配置如下的内容:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
if has("cscope")
  set csprg=/usr/local/bin/cscope
  set csto=0
  set cst
  set nocsverb
  " add any database in current directory
  if filereadable("cscope.out")
      cs add cscope.out
  " else add database pointed to by environment
  elseif $CSCOPE_DB != ""
      cs add $CSCOPE_DB
  endif
  set csverb
endif

常规的用法如下:

主要用来查询,查询的语法如下:

1
:cs find {querytype} {name}

其中querytype可以使用的值如下表所示:

number querytype remark
0 s 找到这个symbol
1 g 找到定义 definition
2 d 找到被这个函数调用的函数
3 c 找到调用(call)这个函数的函数
4 t 找到这个文本
6 e 找到这个正则表达模式
7 f 找到这个文件
8 i Find files #including this file
9 a 找到赋值 Find places where this symbol is assigned a value

也可以使用Ctrl+\加上querytype快速查询光标所在位置。

示例:使用cscope寻找reference

使用cscope寻找__init的定义。

./cscope-find-definition.png

Reference

英文

中文

插件