总结Vim使用技巧

Last Updated: 2024-02-13 11:55:14 Tuesday

-- TOC --

Vim是我在Linux环境下几乎唯一使用的编辑器,它即古老有新奇,能够做到指随心动。不可否认,Vim的学习曲线有些陡峭。

vim

Philosophy of Vim

When programming, you spend most of your time reading/editing, not writing. For this reason, Vim is a modal editor: it has different modes for inserting text vs manipulating text. Vim is programmable (with Vimscript and also other languages like Python), and Vim’s interface itself is a programming language: keystrokes (with mnemonic names) are commands, and these commands are composable. Vim avoids the use of the mouse, because it’s too slow; Vim even avoids using the arrow keys because it requires too much movement.

The end result is an editor that can match the speed at which you think.

我的Vim配置

配置文件为~/.vimrc,内容如下:

set number " show line number
syntax on
" utf-8 encode
set encoding=utf-8
set fileencoding=utf-8
set termencoding=utf-8
" only LF ending
set fileformat=unix
" Tab = 4 spaces
set tabstop=4
set shiftwidth=4
set expandtab
set autoindent
" active mouse
set mouse=a
" show a vertical line at 80th char position
set cc=80
colorscheme darkblue
set foldmethod=indent
set foldlevel=99
set hlsearch
set scrolloff=4

每次在新的环境上,我都直接copy这个配置来使用,有的时候会修改一下colorscheme。

修改colorscheme

:colorscheme <color_name>,永久改变修改~/.vimrc文件。

系统保存vim颜色的路径为:/usr/share/vim/vim82/colors,里面的每个.vim文件,表示一个配色方案。由此可以得到系统中所有的预设颜色配置,我们也完全可以自己照猫画虎弄一个配色方案。

设置或去掉行号

设置行号是基本的Vim操作:

:set number
:set nu  " also ok

取消行号:

:set nonumber
:set nonu

显示和取消相对行号(一般很少使用相对行号,看着费劲):

:set relativenumber
:set norelativenumber

语法高亮

:syntax on
:syntax off

Vim能自动识别编程语言,启动对应的高亮方案。

光标的移动

在命令模式下,按hjkl,即 左下上右,这是最基本的移动光标的指令,每次只移动一个符号位置。

直接到最后一行的开头,G

直接到第一行的开头, gg or 1G

直接跳到第n行,在命令模式输入 :n or ngg or nG

将光标移动到行尾,$

将光标移动到行首,^ or 0 (数字0)

G指令,就是Go;$和^的含义,与正则表达式中的一样。

快速向下翻页,Ctrl+d < Ctrl+f

快速向上翻页,Ctrl+u < Ctrl+b

移动到下一个空行处,Shift+}

移动到上一个空行处,Shift+{

移动到下一个word处, w,反向是 b

移动到上一行的第一个字符处,-

移动到下一行的第一个字符处,+

-, 0, +, 这3个指令可以放在一起!

打开文件时的光标位置

$ vim +<linenumber> file

显示当前文件名,总行数和光标百分比位置

:f or Ctrl+g

上面两个指令,可以在Vim底部看到当前文件名,总行数,光标的百分比位置。

如何进入insert模式

insert就是vim的编辑模式,有好多种进入insert模式的方式:

i,这可能是最广为人知的方法,在命令模式下按i键,就可以在当前光标的位置开始输入编辑;

I,输入大写的I,光标自动跳到当前行的最开始的位置,并且进入可编辑状态;即在行首的位置开始输入;

a,从当前光标位置的后面开始进入编辑状态;

A,在当前行的末尾开始,进入Insert模式;

o,小写的o,从当前行的下一行开始输入;

O,大写的o,从当前行的上一行开始编辑;

s,删除当前光标所在字符,然后进入插入模式;

S,删除当前光标所在行,然后进入插入模式;

退出insert模式

ESC or Ctrl+[ or Ctrl+c

去掉文件中的^M (CFLF){:#ff}

将Windows环境下编辑的文件(比如代码或任意文本文件),在Linux环境显示出来,就会看到^M符号。

这不是个错误,而是由于操作系统环境的不同导致的。Windows环境下,行结尾是CR+LF,而Linux环境下,行结尾就只是LF。CR+LF在Linux环境下,显示出来(比如使用diff这样的工具)就是^M。

将Windows环境下编辑的文件,copy到Linux环境下,再继续编辑,一般都需要去掉^M。

我们可以通过VIM这个工具来做这件事情,具体操作方式如下:

:set fileformat=unix
:w

列操作

  1. 进入Vim命令模式,调整光标位置,按Ctrl+v进入列操作模式;(此时在Vim底部可以看到-- VISUAL BLOCK -- 字样)
  2. 使用hjkl选择要编辑的列的范围;
  3. 列输入或列删除:
    1. 如果是做列输入,键入大写的I,Shift+i,然后键入你想输入的内容,最后按Esc,Vim会自动在你所选择的每一列复制这些内容;
    2. 如果是列删除,直接按d即可。

VIM的列操作,也被称为块操作。

如何删除

dd,删除光标所在行;

删除多行,比如要删除从5到55行:

:5,55d

x,删除光标所在的那一个字符;

D,删除从光标开始到这一行最后的所有字符;d0,删除从光标开始到这一行最开始的所有字符;

ndd,连同光标所在行,删除n行;

Undo & Redo

undo,直接按 u

u按多了,希望redo,按 Ctrl+r

U:该命令会一次性撤销自上次移动到当前行以来做过的所有操作,再使用一次U命令则撤销之前的U命令所做的操作,恢复被撤销的内容,即可以反复按U!

拷贝,剪切和粘贴

拷贝某部分代码需要先选择,Vim中有3种选择模式:

  1. v,普通选择;
  2. Shift+v,选择行;
  3. Ctrl+v, 选择列。

选择好了之后,y 拷贝,d 剪切。移动光标到指定位置后,按 p 将拷贝或剪切的内容放在光标所在位置后面;P 如果是大写P,就是放到光标所在位置的前面。

当选择行时,p将内容插入光标所在行的后面行;P将内容插入光标所在行的前面行。

剪切动作也可以用 m 指定来实现,比如将5到30行的代码移动到第50行:

:5,30 m 50

拷贝动作也可以用 co 指令来实现,比如将5到30行代码copy到第50行:

:5,30 co 50

拷贝剪贴板内容

Shift+Insert

不要使用Ctrl+s

Ctrl+s在Windows下,一般都是保存的快捷键,但Linux系统不是。在Linux系统,Ctrl+s的作用是暂停终端的输出。

在Vim中,如果按下了 Ctrl+s,整个屏幕就不动了,任何输入都看起来没有响应。其实不是没有响应,只是屏幕不动而已,此时用 Ctrl+q 就可以恢复。

Linux下Ctrl+s暂停终端的输出,主要是用来调试时使用,比如屏幕输出很多,用这个命令可以暂停一下输出,查看一些内容。

缩进和回缩

默认情况下,VIM多行缩进或回缩,都是8个字节的距离,可以做个设置,将缩进和回缩的距离设置为4个字节,或2个字节:

:set shiftwidth=4

缩进操作:选中需要操作的行,按 >

回缩操作:选中需要操作的行,按 <

单行缩进:>>

单行回缩:<<

insert模式下单行缩进:Ctrl+t

insert模式下单行回缩:Ctrl+d

保存和退出

保存::w

退出::q

保存并退出::wq

不保存退出::q!

如果文件有修改,就保存退出,没有修改就直接退出::x or ZZ

关闭所有窗口并退出::qa

不保存关闭所有窗口并退出::qa!

保存并关闭所有串口并退出::xa or :wqa

w和x的区别是,w会改写文件的mtime,x只在文件有变更的情况下,参会修改文件,修改mtime。

另存为

:w file,将当前文件另存为file。

:15,49 w file,将当前文件的15到49行,另外保存到file中。

:15,49 w >> file,将当前文件的15到49行,追加保存到file中。

代码折叠

设置按indent做代码折叠:

:set foldmethod=indent

应该还有其它代码的折叠的方式,暂时还不会。

设置代码折叠层次:

:set foldlevel=99

基本上设置为99,就很大了,什么都可以折叠了。

下面是关于代码折叠的指令:

zM, 全部折叠

zR, 全部展开

za, 在当前位置进行折叠和展开

zj, 移动到下一个折叠点

zk, 移动到上一个折叠点

要在有代码的行使用以上命令,在空行使用很可能无效。

垂直线

保持每行代码不超过80个字符,是一条古老的,但是良好的编码风格。要遵循这条编码规范,就需要编辑界面有一条用来提示的垂直线:

:set cc=80

80表示字符宽度。

取消垂直线,就是将垂直线的位置设置为0:

:set cc=0

水平线

VIM默认没有水平线,可以这样来设置一条:

:set cursorline

取消鼠标水平线:

:set nocursorline

也许有人不喜欢水平线,anyway...

屏幕滚动偏移

无意中发现别人分享的一个vim小技巧,可以很有效的提高编辑代码时的体验。

默认VIM的光标都是要移动到最上一行或者最下一行时,屏幕才会滚动的。

有一个VIM设置,可以使得屏幕开始滚动的时候,光标距离窗口上下边缘还有一点距离,这个距离是行数,可以设置:

:set scrolloff=4

设置屏幕滚动时,上下距离为4行。效果很不错。

关键词搜索

从当前位置向下搜索:

:/keyword

从当前位置向上搜索:

:?keyword

nN 分别是移动到下一处,或上一次,不是向上向下移动。

如果不输入前面的冒号,也可以搜索,这就跟在类似less这样的命令中搜索一样,少按两次键盘,操作速度更快!

设置搜索关键词高亮显示:

:set hlsearch

取消关键词高亮:

:nohl

全词搜索

:/\<keyword\>
:?\<keyword\>

或者选中关键词,按 *, 或 #

设置搜索不区分大小写:

:set ignorecase

恢复区分大小写:

:set noignorecase

文本替换

文本替换是代码编写过程中经常要用到的操作,比如修改一个变量的名称,替换一个函数的名称等等。如果修改名称的变量或函数被使用的特别多,那么就需要有一种简单的方式来进行全文替换。VIM中的s命令可以用来做这件事情。

:%s/from/to/g : 将所有from都替换成to。

:%s/from/to/gc :将所有from都替换成to,但是每一次替换之前都 会询问请求用户确认此操作。

一般都会使用 g 参数,做全部替换;有的时候带上 c,对每一次替换进行确认,这样虽然不够装逼,但是更保险。

:10,20s/from/to/g : 对第10行到第20行的内容进行替换。

:1,$s/from/to/g :对第一行到最后一行的内容进行替换(即全部文本)。

:1,.s/from/to/g : 对第一行到当前行的内容进行替换。

:.,$s/from/to/g : 对当前行到最后一行的内容进行替换。

:'a,'bs/from/to/g :对标记a和b之间的行(含a和b所在的行)进行替换。 其中a和b是之前用m命令所做的标记。

清理行尾空格

:%s/\s\+$//g,这个操作常常做,行尾不要出现空格,也是一条古老的编程规范。\+是因为文本中本就有很多+号。

退出recording状态

没用过recording这种高级功能,有的时候不小心进入了recording状态,无法退出会让人抓狂。

退出recording:q (在非insert模式下)

检查配置

前面已经总结了好多Vim配置了,用下面的方式,可以查看具体的配置内容:

:set number?
:set cc?

即在后面加个问好查看配置。

拼写检查

:set spell
:set nospell

替换模式

所谓替换模式,是相对插入模式而言的。我们一般编辑都是使用插入模式,在光标处输入一个字符,这个位置后面的字符自动向后移动,即是插入效果。而替换模式不同,在光标处输入一个字符,直接替换光标处原来的字符,光标后买你的字符也不会移动。替换模式用的少一些,不过有的时候还是非常高效的。

VIM的rR可以让你使用它的替换模式。

r,按r,然后输入另一个字符,直接替换光标当前的字符;

R,大写R,进入替换模式,后面输入的所有字符都是替换光标所在位置的其它字符,Esc退出替换模式。

查看不可见字符

默认情况下,Vim是不会显示space,tabs,newlines,trailing space,wrapped lines等不可见字符的。我们可以使用list命令,来显示不可见字符:

:set list

这时,你会看到界面上多出了很多$符号,这表示每行的末尾。而制表符会被显示为^I

当$符号没有紧挨着最后一个可见字符的时候,就表示中间有trailing space存在。

关闭不可见字符的显示:

:set nolist

有的时候,检查一些语法错误,或者查看别人编辑的文件内容,也许可以试试这个命令。copy来自window平台的文件到linux环境,在vim中编辑,但是在git diff的时候,会看到很多^M符号。我遇到过这个问题。其实,在编辑的时候,使用set list看一下,就能看到这个符号。

多窗口操作技巧

VIM多窗口功能,使得我们可以在字符界面构造出一个看起来很专业的多窗口工作界面。

# 打开多个文件,水平分割窗口
$ vim -o file1 file2 ...
# 打开多个文件,垂直分割窗口
$ vim -O file1 file2 ...
# 打开一个水平分割的窗口
:sp <filename>
# 打开一个垂直分割的窗口
:vsp <filename>

:sp:vsp 这两个指令,如果后面不带文件,表示将当前文件再打开一份,这可以让我们同时查看同一份文件的不同部分;这两个指令后面也可以带一个新文件名,表示创建一个新文件。:sp等效于快捷键Ctrl+w,s:vsp等效于快捷键Ctrl+w,v

有了多窗口,我们就需要将光标在多个窗口之间切换,以及控制各个窗口的大小,使用下面介绍的指令:

Ctrl+ww:按照窗口打开的顺序,在多窗口间移动光标。

Ctrl+w+(h|j|k|l):使用hjkl方向控制键控制光标在各个窗口之间的移动。

:res[ize] [+|-]num,设置(增加或减少)当前窗口的行数。

:vertical res[ize] [+|-]num,设置(增加或减少)当前窗口的列数,貌似这是唯一能够调整窗口列数的操作。

Ctrl+w+(+),给当前窗口增加一行。

Ctrl+w+(-),给当前窗口减少一行。

Ctrl+w+(=),平分上下窗口的行数。

Ctrl+w+(_),让当前窗口的行数最大。

:xa:wqa,保存所有修改,退出关闭所有窗口。

:qa!,不保存修改,退出关闭所有窗口。

单一窗口多文件

一个窗口,多个文件切换。

$vim a b c

此时a显示,如果有不存在的文件,则新建;

:ls, 显示所有打开的文件,及对应的编号;

:b1~n, 切换至第n个文件,注意:切换之前先得保存文件更改;

:n, 下一个文件

:N, 上一个文件

Ctrl+6, 在最近的两个文件中交替显示

位置标记

VIM中的位置标记(mark),可以让我们快速定位某个代码位置,对提高个人编码效率很有效果。

例如:在命令模式下直接输入 mx,此时你什么效果都看不到,但是VIM已经记住当前光标所在的位置,并标记为x,以后当你想快速回到这个位置的时候,'x

标记可以是 a-z,26个小写字母,

标记也可以是 A-Z,26个大写字母。

它们的区别是:小写字母的标记,只有将拥有那个标记的文件打开后,才有效;而大写字母标记,在任何地方(不管打开的是哪个文件),都有效!所以,一般用小写字母在文件内做标记,用大写字母跨文件标记。

VIM记住的标记,marks,关闭文件后依然有效。

特殊标记:'' :回到光标跳转之前的位置。

查看标记::marks

删除表示::delmarks x

浏览文件夹

一个项目涉及很多文件,我们不一定都能记得住,在使用VIM编码的时候,有方法即不退出VIM,还能够浏览文件目录的所有内容,并选择文件打开。

$ vim <foldername>

打开文件夹后,使用 jk 来上下选择文件。

或者在Vim中,使用如下指令:

:Ex, 用当前窗口打开文件所在目录。

:Sex,水平分出一个窗口来显示文件目录。

:Vex,垂直分出一个窗口来显示文件目录。

与shell交互

:sh,临时离开vim,进入shell界面,然后在shell界面使用 exit,又可以重新回到vim。

在Vim中直接执行shell命令:

:!{cmd}
:!ls
:!pwd
:!python3 %  # run current python script

Ctrl+z可以临时挂起vim进程,回到shell界面,以便执行一些其它操作,然后再通过jobs和fg的方式,重新回到vim进程。

:his,看出使用过的历史vim命令

:之后,Ctrl+p表示前一条命令,Ctrl+n后一条命令,实现快速重复输入并执行命令。

文件比较

$ vim -d f1 f2 ...

在一行不同处,输入do可将另一个buffer的改动应用于当前buffer;

输入 dp 可将当前buffer的该行内容应用于另一个buffer;

输入 ]c 跳到下一个不同行;

输入 [c 跳到上一个不同行;

在修改一个或两个文件之后,vimdiff会试图自动来重新比较文件,来实时反映比较结果。但是也会有处理失败的情况,这个时候需要手工来刷新比较结果::diffupdate

导入文件内容

在VIM编辑代码的时候,我们可以很方便的将某个文件的内容,追加到当前文件的某个位置。

:r file,将file文件的内容,追加到当前文件的光标后面。

:9r file,将file文件的内容,追加到当前文件的第9行后面。

以只读方式打开文件

$ vim -R <filename>

或者,直接使用view命令更好!

Recovery

显示出所有的swap文件,以及它们的recovery信息:$ vim -r

$ vim -r {file},Recovery mode. The swap file is used to recover a crashed editing session. The swap file is a file with the same filename as the text file with ".swp" appended. See ":help recovery".

输入Tab

本文最开始,我的vim配置,里面设置了 :set expandtab 指令,这个指令使输入的tab变成空格。但是,当我们需要编辑makefile的时候,就必须要输入真正的tab,此时可以临时去掉tab变空格的设置,使用 :set noexpandtab 即可!

另外两个与Tab有关的Vim配置,应该都是在 noexpandtab 模式下才有意义:

set tabstop=4:表示一个Tab键显示出来多少个空格的长度,默认是8,这里设置为4;

set softtabstop=4:表示在编辑模式下按退格键时候退回缩进的长度,设置为4。

Vim能够感知到当前编辑的文件是makefile,如果没有设置noexpandtab,那一行command会提示错误。用cat命令查看makefile的内容,tab符号是8个空格的长度。

自定义缩写扩展

比如有一些比较长的字符串,在编码的时候要反复输出,这个时候,我们就可以定义一个缩写扩展(abbreviation),以后只要每次输入缩写,空格,vim自动替换为完整的内容:

定义缩写::ab <abb_name> <your_long_string_space_is_accepted>

删除缩写::una <abb_name>

自动补全

vim有很多种自动补全。

Ctrl+NCtrl+P这两是当前文档内的关键字补全!前者向下选择,后者向上选择,选择某个补全,反复输入这两者!

Bill Joy (vi作者)

威廉·纳尔逊·乔伊(William Nelson Joy,1954年11月8日-),通称比尔·乔伊(Bill Joy),美国计算机科学家。与Vinod Khosla、Scott McNealy和Andy Bechtolsheim一起创立了太阳微系统公司,并作为首席科学家直到2003年。后来经营自己的风险投资公司HighBAR Ventures,也是知名投资公司Kleiner Perkins的合伙人。

主要成就:乔伊的童年是在密歇根州的乡村长大的,在密歇根大学获得电气工程学士学位之后,于1979年在加州大学伯克利分校获得电气工程与计算机科学硕士学位。学生期间,他开发了BSD操作系统。其他人以BSD为基础发展出了很多现代版本的BSD,最著名的有FreeBSD、OpenBSD和NetBSD,苹果电脑的Mac OS X操作系统也在很大程度上基于BSD。1986年,乔伊因他在BSD操作系统中所做的工作获得了Grace Murray Hopper奖。

除了BSD之外,他引人注目的贡献还包括TCP/IP、vi(vim是后人继续升级维护的结果)、NFS和C shell,如今这些软件都已经广泛的使用在Solaris、BSD、GNU/Linux等操作系统中,而且开放源代码给其他人无偿使用、改进,为自由软件的发展作出了极大的贡献。

Bill Joy其貌不扬的瘦高个,凌乱的亚麻色头发,这就是被《财富》杂志誉为“网络时代的爱迪生”的Bill Joy。他曾是Sun的创始人之一,并在Sun担任首席科学家长达二十一年。他是一位令人崇敬的软件天才,同时也是一个标准的技术狂人——在记载英雄的历史中,我们注意到,天赋和近乎疯狂的偏执这两者总是结伴出现,并在英雄的身上达到一种交融的境界。

然而,软件英雄史诗令人遗憾地忽略了Bill Joy的另一面——作为一名以追求公民社会正义和道德为己任的公共知识分子。他也曾多次尝试,希望通过自己的独立思考,并以个人言论的方式来影响社会,推动社会进步和解决公共问题。

话说当年,AT&T在反垄断法的判决下,不得已放弃了从Unix开发和支持中获利的念头,从而专心致志地开始卖Unix的源代码许可证。当时,Bill Joy所在的Berkeley计算机科学系就在贝尔实验室所发布源代码的基础上,开始了他们的Unix研究——可能当时所有人都没有意识到,这一行为对后来的世界产生了多大的影响。在Berkeley持续不断的研究中,Unix具备了如此多的现代操作系统特征:基于分页的虚存系统、统一的文件系统、强大而完善的脚本、网络……

最早基于分页的虚存系统就是由Bill Joy加入到Unix内核中的,这使得Unix得以打败DEC的VMS操作系统而成功获得DARPA的支持。国防部雄厚的资金成为Bill Joy和他的伙伴们强有力的支柱,让他们能够源源不断地挥发灵感,继而完成了csh、vi、TCP/IP等等。csh(C Shell)以其强大的功能获得了广大程序包括各种不同版本的Unix和Linux;至于TCP/IP就更不用说了,您能在遥远的中国了解到Bill Joy的英雄历程,正是基于TCP/IP的互联网所赐。1984年,Bill又发布了NFS网络文件系统,其后则是在此基础上的PC-NFS。

在成立Sun微系统公司后,Bill Joy又担当设计了Sparc微处理器最关键的一部分电路。每年Sun公司靠Sparc服务器和工作站的生意能赚到上百亿美元。而Java虽然是由Sun的James Gosling所写,却也是因为他的全力支持,从而走到台前,从一种编程语言演变成为今天流行的开发平台。

在Java之后,Bill Joy还主持了Jini——一种连接分布式计算机系统的技术的开发。任何联网的小装置(数码相机、电视机、打印机等)都可以由包含有Java写成的简单程序实现自己的功能,并且供其他设备使用;还有Jxta,这是一套开放的P2P协议,允许任何互联网上相连的设备(如手机与PDA,个人电脑与服务器)交流和协作。

在短短的二十年内,Bill Joy创造出了那么多令人心动的软件,不得不令人折服。可提到哪一个对程序员的影响最大呢?人们众说纷纭。也许小小的Vi编辑器的影响是最持久的。正如Reg网络杂志做的调查,大多数程序员都评论说:“没有NFS、Java和其他的技术还能活;但是如果没有Vi,简直没法活了!”

Bill Joy能在IT圈外广为人知,不仅因为他是个技术天才,也不仅因为他是个人人羡慕的亿万富翁,主要还是因为2000年他在《连线》杂志上发表的一篇文章《未来还需要我们吗》。他宣称生物技术和纳米技术的轻率进展也许会给人类带来灭顶之灾,也许未来不再需要人类。

Joy的这篇跨越其专业的文章引来了很大争议。有人认为,Joy只是个程序员,并没有资格谈论生物技术的复杂性。就算是IT界的同仁尼葛洛庞帝在接受采访时也说:“Bill Joy当年写这篇文章时,正处在中年危机之中。我正好知道这一点。因此其文反映了他那段时间的失意。”

难道只有所谓的专业人士才有资格评说技术灾难吗?难道公众就缺乏基本的分析与判断吗?所以,Bill Joy面对这些非难并不放在心上,他认为提出这个命题的目的不是危言耸听,而是要让公众都关心技术危害的问题,思考我们应该做些什么来避免不想见到的未来。这就是一个知识分子的公共良知。

此外,他还陆续发表了《为数字革命而设计》等多篇涉及技术的文化影响的文章,引起了广泛的注目。

2003年9月,Bill Joy离开Sun。当时Sun公司的股票也应声下跌了3.2%。后来,Bill Joy在接受《连线》杂志的采访时高兴地说“嗨,我辞职了!”。可是这并不意味着他的职业生涯就此结束。除了每天在家中面壁沉思外,他还在考虑着未来的技术。说不定哪一天这个网络的爱迪生又会带给我们新的惊喜。

Bram Moolenaar(已故vim作者)

2023年8月3号,Vim之父Bram Moolenaar辞世,年仅62岁。

:wq

本文链接:https://cs.pynote.net/sf/202110085/

-- EOF --

-- MORE --