Vim 中你母亲从未告诉你的黑暗角落是什么?

829

有很多人在讨论常见技巧,特别是“Vim+ctags 技巧”。

然而,我不是指那些新手会觉得很酷的常用快捷键。我指的是经验丰富的 Unix 用户(无论是开发者、管理员还是两者兼备等),他们认为自己知道一些我们中绝大部分人从未听说或梦想过的东西。这些不仅能够使他们的工作更轻松,而且还很炫酷和有技巧性。毕竟,Vim 是运行于全球最黑暗角落的操作系统之一,因此它应该有一些只有少数特权人士知道并愿意与我们分享的复杂技巧。


12
分割窗口并打开集成文件浏览器(水平分割)。 - user3218088
3
这个问题似乎非常有益 - 从点赞数来看...,我投票支持重新开放 - 或许会有更棒的答案出现 - 如果有用的话可以被点赞 - 因此为 SOF 带来更多价值。通过按照得票数排序的答案,我在短短5分钟内学到了很多酷炫的东西...这里真的有很有价值的东西,为什么要关闭这么有价值的东西呢?这不是很有益吗? - jhegedus
7
很荒谬这个问题被关闭了。谈论法律主义。 - Lepidopterist
3
我认为这个问题非常有建设性,但更适合在 Quora 上讨论。 - Diogo Melo
3
为什么现在有两个投票要删除这个问题?这样做有什么好处吗? - Akavall
显示剩余4条评论
70个回答

803

可能并不是99%的Vim用户都不知道的技巧,但它是我每天都使用的东西,任何Linux+Vim高级用户都必须掌握。

这是一个基本命令,但非常有用。

:w !sudo tee %

我经常忘记在编辑没有写入权限的文件前使用sudo,当我保存该文件时遇到权限错误时,我会直接执行vim命令以无需将其保存到临时文件并再次复制的方式来保存该文件。

显然,你必须在安装了sudo并拥有sudo权限的系统上才能这样做。


122
可以说,这甚至比以 root 用户身份运行 vim 更好!点赞! - Arafangion
27
对于新手来说,tee命令到底是做什么的?有人可以帮我解释一下这个命令吗? - AndyL
42
cmap w!! w !sudo tee % - clt60
65
永远不要运行 sudo vim。相反,您应该将 EDITOR 导出为 vim 并运行 sudoedit - Gerardo Marset
9
vim会将%替换为当前缓冲区/文件的名称。 - migu
显示剩余14条评论

634

最近我发现了一些非常酷的东西:

:earlier 15m

将文档恢复到15分钟前的状态。可以使用不同的参数来确定要回滚的时间量,这取决于撤消级别。可以通过相反的:later命令撤销。


6
如果您在撤销之后对已撤销的状态进行进一步更改,那么您将失去重做历史记录。这样可以使您返回到不再存在于撤销堆栈中的状态。 - ephemient
39
非常有用的是g+和g-,可以在时间轴上前后移动。这比撤销/重做堆栈更强大,因为当您在撤销之后做一些事情时,您不会丢失历史记录。 - Etienne PIERRE
9
如果您在撤销之后进行更改,重做历史记录并不会丢失,只是不容易访问。有一些插件可以帮助您可视化这些历史记录,比如 Gundo.vim。 - Ehtesh Choudhury
589
哇,现在我只需要输入 :later 8h 就可以结束今天的工作了吗? :P - Igor Popov
8
您的命令假定用户至少要在 vim 中花费15分钟的时间! - Déjà vu
显示剩余3条评论

423

:! [command]用于在Vim中执行外部命令。

但是,在冒号后面加一个点,:.! [command],它将把命令的输出转储到当前窗口。也就是说: . !

例如:

:.! ls

我经常用这个功能来为我正在打字的文档添加当前日期:

:.! date

75
这与:r!非常相似!据我所知,唯一的区别是:r!打开一个新行,而:.!则覆盖当前行。 - saffsd
7
除了使用 :.!date 命令外,另一个选择是在一行中输入 "date",然后运行 !$sh(或者在命令后面加一个空行,然后运行 !jsh)。这将把该行通过管道传递给 "sh" shell,并用命令输出进行替换。 - hlovdal
45
:%! 实际上是 :{range}! 的一种特殊情况,它通过一个命令过滤一系列行(当范围为.时表示当前行),并用输出替换这些行。我发现 :%! 在过滤整个缓冲区时非常有用。 - Nefrubyr
5
还要注意,'!' 就像 'y'、'd'、'c' 等等。例如:你可以这样做:!!、number!!、!motion(例如:!Gshell_command<cr> 用 shell_command 的输出替换从当前行到文件末尾的内容 ('G'))。 - aqn
3
你知道吗,你可以使用双感叹号(!!)来自动填充 :.! 吗?当你不想输入所有这些内容时,这非常方便。在 vim -u none 中也适用。 - Braden Best
显示剩余4条评论

319

并不是很难理解,但是有一些非常有用的“删除”命令,例如:

  • diw 删除当前单词
  • di( 删除当前括号内的内容
  • di" 删除引号之间的文本

其他命令可以在:help text-objects中找到。


8
dab表示删除括号内的内容,daB表示删除花括号内的内容,t表示删除XML标签,与普通命令的组合如cib/yaB/dit/vat等都符合预期。 - sjh
15
@Masi:yi(va(p 只删除括号。 - Don Reba
43
这可能是我坚持使用 Vim 的最大原因,还有它等效的“修改”命令:ciw、ci(、ci",以及 dt<空格> 和 ct<空格>。 - thomasrutter
4
为什么不用dW/cW来代替dt<空格>? - Roger Pate
9
使用环绕插件:ds(. - Roger Pate
显示剩余4条评论

244

de 想删除单词末尾的所有内容,只需按下“.”即可。

ci(xyz[Esc] -- 这是一个奇怪的命令。这里,“i”不表示插入模式,而是表示括号内部。因此,这个命令可以剪切当前所在括号内的文本,并用“xyz”替换它。它也适用于方括号和花括号——只需分别使用ci[或ci{即可。如果你只想删除所有文本而不输入任何内容,则可以使用di。如果你想同时删除括号和其中的文本,而不仅仅是文本,则可以使用a代替i

ci" - 剪切当前引号内的文本

ciw - 剪切当前单词。这个命令与前面的命令类似,只是将(替换为w

C - 剪切光标所在位置到行尾的所有内容,并进入插入模式。

ZZ -- 保存并关闭当前文件(比使用Ctrl-F4关闭当前选项卡要快得多!)

ddp - 将当前行向下移动一行

xp -- 将当前字符向右移动一个位置

U - 大写,所以viwU将单词大写

~ - 切换大小写,所以viw~将整个单词的大小写颠倒

Ctrl+u / Ctrl+d 滚动页面半屏幕向上或向下。这似乎比通常的全屏翻页更有用,因为它使得更容易看到两个屏幕之间的关系。对于那些仍然想要一次滚动整个屏幕的人,可以使用Ctrl+f向前和Ctrl+b向后。Ctrl+Y和Ctrl+E每次向下或向上滚动一行。

非常疯狂但非常有用的命令是zz -- 它滚动屏幕使得这一行出现在中间。这对于将你正在工作的代码放在你的注意力中心非常有用。类似的命令--zt和zb--将这一行变成屏幕上面或下面的一行,这不太有用。

% 查找并跳转到匹配的括号。

de -- 从光标删除到单词结尾(也可以使用dE删除到下一个空格)

bde -- 从左到右删除当前单词

df[space] -- 删除直到包括下一个空格

dt. -- 删除直到下一个句点

dd -- 删除整行

ye (或 yE) -- 复制从此处到单词结尾的文本

ce - 剪切至单词结尾

bye -- 复制当前单词(让我想知道“hi”是什么意思!)

yy -- 复制当前行

cc -- 剪切当前行,您也可以使用S。还有小写字母s,它会剪切当前字符并切换到插入模式。

viwy 或 viwc。复制或更改当前单词。多次按w以继续选择每个后续单词,使用b向后移动

vi{ - 选择大括号内的所有文本。va{ - 选择包括{}在内的所有文本

vi(p - 高亮显示()内的所有内容,并用粘贴的文本替换

b和e按单词移动光标,类似于Ctrl+箭头键的操作方式。不过,单词的定义略有不同,因为多个连续的分隔符被视为一个单词。如果从单词中间开始,按b将始终将光标移到当前单词的开头,每次连续按b都会跳到下一个单词的开头。同样地,容易记住,e将光标移到当前单词的末尾,每次连续按e都会跳到下一个单词的末尾。

b/e类似,大写字母BE只使用空格作为分隔符来按单词移动光标。

大写字母D(深呼吸)删除光标右侧的整行剩余部分,与普通编辑器中的Shift+End/Del相同(注意是2个按键--Shift+D--而不是3个)


16
如果你在函数或类定义的开头使用zt,它会非常有用。 - Nick Lewis
9
"vity" 和 "vitc" 可以分别缩写为 "yit" 和 "cit"。 - Nathan Fellman
33
你所称之为“剪切”的所有操作其实都是“修改”。例如:在行尾之前,将C视为修改。Vim中类似于“剪切”的操作是使用d/D进行的“删除”。更改和删除的主要区别在于删除后会保持正常模式,而更改会进入一种插入模式(尽管你仍然处于更改命令中,这很方便,因为整个更改可以用“.”重复执行)。 - Laurence Gonsalves
11
我认为这是列出很少有人知道的事情清单。yy非常普遍,我原以为大家都知道。 - Almo
19
当您位于单词的第一个字符时,“bye”无法使用。但“yiw”总是有效的。 - Andrea Francia
显示剩余12条评论

213

在大多数Vim教程中很少见到的一点是,但它非常有用(至少对我来说),那就是使用

g;和g,

通过更改列表向前或向后移动。

让我展示如何使用它。有时候我需要复制粘贴一段代码或字符串,比如CSS文件中的十六进制颜色代码,所以我搜索、跳转(不关心匹配项在哪里)、复制它,然后跳回(g;)到我正在编辑代码的位置,最后进行粘贴。不需要创建标记。更简单了。

只是我的个人意见。


32
类似地,'.将跳转到最后编辑的行,而\.`将跳转到最后编辑的位置。 - aehlke
8
Ctrl-O 和 Ctrl-I (tab) 有些类似,但并不完全相同。它们在“跳转列表”中向后或向前移动,你可以通过输入 :jumps 或者 :ju 来查看跳转列表。如需了解更多信息,请输入 :help jumplist。 - Kimball Robinson
20
可以通过执行命令:changes来列出更改列表。 - Kimball Robinson
哇塞,这太有用了。我一直都在使用 <C-o>/<C-i> - 或者标记我的位置。 - Wayne Werner

189
:%!xxd

将vim转化为十六进制编辑器。

:%!xxd -r

还原。

警告:如果您不使用二进制(-b)编辑,可能会损坏文件。 - 评论中的Josh Lee。


9
如何将其还原回去? - Christian
40
:!xxd -r // 用于从HEX还原回来 - Naga Kiran
21
我认为正确的操作是 :%!xxd -r,以将其还原回去。 - Andreas Grech
@JoshLee:如果小心不遍历换行符,那么不使用-b选项是安全的吗?我问这个问题是因为有时候我想进行十六进制更改,但又不想关闭并重新打开文件。 - dotancohen
4
如果您不想关闭/重新打开文件,则可以执行以下操作::set binary - Bambu
显示剩余2条评论

138
gv

重新选择上次的可视化选区。


123

有时候你在.vimrc中设置的选项会被插件或自动命令覆盖。为了调试这个问题,一个有用的技巧是将:verbose命令与:set命令结合使用。例如,要找出cindent是在哪里被设置/取消设置的:

:verbose set cindent?

这将输出类似以下内容:

cindent
    Last set from /usr/share/vim/vim71/indent/c.vim

这也适用于地图和高亮显示。(感谢joeytwiddle指出这一点。)例如:

:verbose nmap U
n  U             <C-R>
        Last set from ~/.vimrc

:verbose highlight Normal
Normal         xxx guifg=#dddddd guibg=#111111 font=Inconsolata Medium 14
        Last set from ~/src/vim-holodark/colors/holodark.vim

8
非常好的提示 - 正是我今天正在寻找的。 - Artem Russakovskii
厉害的提示!你是怎么了解这些极客的东西的? - Rafid
1
:verbose 也可以在 nmap lhighlight Normal 前使用,以查找上次定义 l 键映射或 Normal 高亮的位置。非常有用于调试! - joeytwiddle
@joeytwiddle 謝謝!我已經將該信息添加到答案中。 - Laurence Gonsalves
当你开始创建自定义映射时,这将会在很多时候帮助到你,可能是最有用的一个(在我看来)! - SidOfc

103

:%TOhtml

创建当前文件的HTML渲染。


3
好的,我会尽力为您翻译。需要翻译的内容是:Related: How to convert a source code file into HTML? at Vim SE - kenorb
这太棒了。顺便说一下,是不必要的,因为默认参数是当前缓冲区。:help TOhtml - JDG

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接