使用 Vim,我经常想用我刚刚拉出的代码块替换代码块。
但是,当我删除要替换的代码块时,该块本身会进入寄存器,从而擦除我刚刚拉出的块。所以我养成了拉动,然后插入,然后删除我不想要的东西的习惯,但是对于大块代码,试图将插入的块和要删除的块分开会变得很混乱。
那么在 Vim 中替换文本最灵巧、最快捷的方法是什么?
- 有没有办法删除文本而不将其放入寄存器?
- 有没有办法说,例如“替换下一个单词”或“替换到下一段”
- 还是以某种方式使用多寄存器功能的最佳方法?
使用 Vim,我经常想用我刚刚拉出的代码块替换代码块。
但是,当我删除要替换的代码块时,该块本身会进入寄存器,从而擦除我刚刚拉出的块。所以我养成了拉动,然后插入,然后删除我不想要的东西的习惯,但是对于大块代码,试图将插入的块和要删除的块分开会变得很混乱。
那么在 Vim 中替换文本最灵巧、最快捷的方法是什么?
要删除某些内容而不将其保存在寄存器中,您可以使用“黑洞寄存器”:
"_d
当然,您也可以使用任何其他不包含您感兴趣的任何内容的寄存器。
是的。它比首先删除“旧”文本稍微复杂一些,但是:
我从..
line1
line2
line3
line4
old1
old2
old3
old4
I shift+v选中第1行、第2行、第3行和第4行,用d命令删除
然后我以同样的方式删除旧的 1-4 行。
然后做
"2p
这将粘贴倒数第二行(第 1-4 行)。"3p
将做倒数第三个,依此类推..
所以我最终得到
line1
line2
line3
line4
参考: 编号寄存器上的 Vim 文档
VIM 文档:编号寄存器 0 包含来自最近的 yank 命令的文本,除非该命令用 ["x] 指定了另一个寄存器。
例如,我们拉出“foo”并删除“bar”——注册表 0 仍然包含“foo”!因此“foo”可以粘贴使用"0p
有一个简单的映射很方便,它可以让你用缓冲区替换当前的选择。
例如当你把它放在你的 .vimrc
" it's a capital 'p' at the end
vmap r "_dP
然后,在将某些内容复制到寄存器后(即使用“y”),您只需选择要替换的文本,然后在键盘上按“r”即可。选择将替换为您当前的寄存器。
解释:
vmap - mapping for visual mode
"_d - delete current selection into "black hole register"
P - paste
我将以下内容放入我的 vimrc 中:
noremap y "*y
noremap Y "*Y
noremap p "*p
noremap P "*P
vnoremap y "*y
vnoremap Y "*Y
vnoremap p "*p
vnoremap P "*P
现在我从剪贴板寄存器中拉出和放入,不必关心默认寄存器会发生什么。另一个好处是我可以轻松地从其他应用程序粘贴。我知道我失去了一些功能(我不再能够为剪贴板寄存器和默认寄存器管理不同的复制信息),但无论如何我都无法跟踪多个寄存器/剪贴板。
默认情况下,所有 yank 和 delete 操作都会写入未命名的寄存器。但是,最近的 yank 和最近的删除总是(单独)存储在编号的寄存器中。寄存器0
保存最新的 yank。寄存器1-9
保存 9 个最近的删除(1
最近的)。
换句话说,删除会覆盖未命名寄存器中最近的 yank,但它仍然存在于0
寄存器中。其他答案中提到的黑洞寄存器技巧("_dd
)有效,因为它可以防止覆盖未命名的寄存器,但这不是必需的。
您使用双引号引用寄存器,因此可以像这样粘贴最近提取的文本:
"0p
这是一个很好的参考:
对于您给出的具体示例,如果我理解这个问题,那么这可能会起作用:
*Highlight what you want to put somewhere else
*delete (d)
*Highlight the code that you want it to replace
*paste (p)
强调EBGreen 所说的:
如果在选择文本时粘贴,则所选文本将替换为粘贴的文本。
如果要复制一些文本,然后将其粘贴到多个位置,请使用"0p
粘贴。编号寄存器 0 包含来自最近的 yank 命令的文本。
此外,您可以列出所有寄存器的内容:
:registers
在执行类似dbr's answer 之类的操作时,该命令可以更轻松地确定您想要的寄存器。您还将看到 /,%,# 寄存器。(另见:help registers
)
最后,检查cW
并cW
更改包含和不包含尾随空格的单词。(使用大写W
包括标点符号。)
如果您使用的是 Vim,那么您将拥有可视模式,就像选择一样,但分离模式是 vi/vim 的基础。
您要做的是使用可视模式选择源,然后拉动,然后再次使用可视模式选择目标范围,然后从默认缓冲区粘贴到文本。
例子:
在一个文本文件中:
1| qwer 2| 自卫队 3| zxcv 4| 呸呸呸
使用以下顺序:ggVjyGVkp
您将以以下方式结束:
1| qwer 2| 自卫队 3| qwr 4| 自卫队
解释:
gg
: 转到第一行V
:以整行启动视觉模式j
:向下一行(选择从前一行开始,这会使选择向下一行)y
: 拉到默认缓冲区(两条选定的行,它会自动退出可视模式)G
: 转到最后一行V
: 启动视觉模式(和之前一样)k
: 上一行(和以前一样,启用可视模式,这会将选择增加一行)p
:粘贴(在最后两行上进行选择,它将用缓冲区中的任何内容替换这些行——在这种情况下是前两行)这有点不方便将最后一个块放在缓冲区上,所以它在某种程度上不希望重复粘贴相同的东西,所以你需要将源保存到一个命名缓冲区,比如"ay
(到一个名为“a ") 并粘贴类似的东西"ap
(但是如果你正在编程,你可能不想粘贴几次,而是创建一个函数并调用它,对吧?对吗?)。
如果你只使用vi,那么你将不得不使用隐形标记而不是视觉模式,:he mark
关于这一点,我很抱歉,但我对这个隐形标记不是很好,我被视觉模式污染了。
对于“替换单词”,请cw
在正常模式下尝试。
cap
对于“替换段落”,请在正常模式下尝试。
针对懒人的微创解决方案:
寄存器0
总是包含最后一个 yank(正如Rafael、alex2k8和idbrii已经提到的)。不幸的是0
,一直选择注册会很烦人,所以如果默认p
使用会很好"0
。这可以通过将以下几行放入您的 中来实现.vimrc
:
noremap p "0p
noremap P "0P
for s:i in ['"','*','+','-','.',':','%','/','=','1','2','3','4','5','6','7','8','9','a','b','c','d','e','f','g','h','i','j','k','l','m','n','o','p','q','r','s','t','u','v','w','x','y','z']
execute 'noremap "'.s:i.'p "'.s:i.'p'
execute 'noremap "'.s:i.'P "'.s:i.'P'
endfor
第一行将每个p
笔划映射到"0p
. 但是,这会阻止p
访问任何其他寄存器。因此p
,具有显式选择寄存器的所有笔划都映射到 for 循环内的等效命令行表达式。对P
.
这种方式保留了标准行为,除了隐式p
和P
笔画,它们现在0
默认使用寄存器。
提示 1: cut 命令现在"0d
不再只是d
. 但是由于我很懒,这对我来说太长了;)因此我使用了以下映射:
noremap <LEADER>d "0d
noremap <LEADER>D "0D
前导键是默认设置的,因此您可以通过键入或\
轻松剪切文本。\d
\D
提示 2:多键映射的默认超时时间非常短。您可能希望增加它以在选择寄存器时有更多时间。有关详细信息,请参阅:help timeoutlen
,我正在使用:
set timeout timeoutlen=3000 ttimeoutlen=100
好吧,首先执行以下命令:
:h d
然后你会意识到你可以删除到一个特定的寄存器。这样您就不会更改默认寄存器中的内容。
我的情况:在Normal
模式下,当我使用x
按键删除字符时,这些删除会覆盖我最新的寄存器——使我想删除字符的编辑复杂化,x
并粘贴我最近的寄存器中的内容(例如,在两个或两个位置粘贴相同的文本)更多的地方)。
我尝试了已接受答案 ( "_d
) 中的建议,但没有奏效。
但是,从https://vi.stackexchange.com/questions/122/performing-certain-operations-without-clearing-register上接受的答案/评论中,我将此添加到 my~/.vimrc
中,它有效(您可能必须重新启动 Vim ):
nnoremap x "_x
也就是说,我现在可以执行正常的 yank ( y
)、delete ( d
) 和 paste ( p
) 命令——我删除使用的字符x
不再填充最新的寄存器。
Vim 偶尔偏爱复杂性而不是实用性,这给用户带来了应用寄存器来复制/删除操作的负担——通常情况下,人们只想粘贴复制的内容并“忘记”删除的内容。
但是,与其与 vim 的复杂寄存器作斗争,不如让它们更方便:选择一个“默认”寄存器来存储您最近的删除。例如,将删除发送到 d 寄存器(让 ac 打开以供临时使用;d 是一个很好的助记符):
nnoremap d "dd "send latest delete to d register
nnoremap D "dD "send latest delete to d register
nnoremap dd "ddd "send latest delete to d register
nnoremap x "_x "send char deletes to black hole, not worth saving
nnoremap <leader>p "dp "paste what was deleted
nnoremap <leader>P "dP "paste what was deleted
这种方法可以防止删除破坏 yanks 但不会放弃注册删除 - 可以粘贴(返回)已删除的内容,而不是将其丢失在黑洞中(如已接受的答案中所示)。在上面的示例中,这种召回是通过两个领导者 p 映射完成的。这种方法的一个好处是,它使您能够选择要粘贴的内容:(a) 刚刚拉出的内容,或 (b) 刚刚删除的内容。
在插入模式下删除的文本不会进入默认寄存器。
我在正确的上下文中使用的两种解决方案是:
VISUAL
的内容,然后粘贴寄存器。我使用这个主要是出于习惯,因为我很久以后才找到第二个解决方案,例如
yiw " yank the whole word
viwp " replace any word with the default register
<ctrl>+<p>
将先前编号的寄存器替换为您刚刚粘贴的寄存器。基本上你可以随意粘贴,但是当你意识到你已经覆盖了默认寄存器从而丢失了你真正想要粘贴的内容时,你可以<C-P>
从 YankRing 历史记录中查找和替换!
其中之一必须有插件...
我为您的目的找到了一个非常有用的映射:
xnoremap p "_dP
删除的文本被放入“黑洞寄存器”,而被抽出的文本仍然存在。
来源:http: //vim.wikia.com/wiki/Replace_a_word_with_yanked_text
在windows 版本中(也可能在Linux 中),您可以使用"*y
(即在您的yank 命令前加上双引号和星号)来拉入系统的复制/粘贴缓冲区。
然后,您可以正常删除可替换行并使用 粘贴复制的文本"*p
。
我经常犯错误,当我按照命令 'y'ank 然后 '"_d'elete into a black hole 然后 'p'aste 0 寄存器,这是最后复制的文本被推送到的地方。
对于 Dvorak 用户,一种非常方便的方法是将不需要的文本删除到“1 寄存器而不是”_黑洞寄存器,如果只是因为您可以使用相同的 shift 按和快速的小指动作按“+1”,因为 1 是Dvorak 中 " 正上方的键(另一方面,加号 d 使整个命令快得不得了)。
当然,“1 寄存器可以用于其他用途,因为它很方便,但除非你有比替换文本更常见的目的,否则我会说这是一个很好的寄存器用途。
对于 emacs-evil 用户,(evil-paste-pop)
可以在粘贴后触发该功能,并循环遍历 kill-ring 中的先前条目。假设您将其绑定到<C-p>
(Spacemacs 中的默认设置),您将根据需要p
依次点击<C-p>
。
对于那些将 JetBrans IDE(PhpStorm、WebStorm、IntelliJ IDEA)与 IdeaVim 一起使用的人。您可能在重新映射nnoremap d "_d
和使用它删除一行时遇到问题dd
。可能的解决方案:nnoremap dd "_dd
youtrack 上有问题,请投票给他们: https ://youtrack.jetbrains.com/issue/VIM-1189 https://youtrack.jetbrains.com/issue/VIM-1363
对于那些对通过虚拟选择和粘贴替换文本时不覆盖未命名寄存器感兴趣的人。
您可以使用以下简单且最适合我的解决方案:
xnoremap <expr> p 'pgv"'.v:register.'y'
它来自这里的答案(和评论): 如何粘贴而不覆盖寄存器
它首先通过选择,然后再次选择带有新文本的选择(gv)。现在是最后在可视模式下使用的寄存器(通常是未命名的寄存器,但如果您使用另一个寄存器进行粘贴,也可以无副作用)。然后再次将新值拉到寄存器中。
PS:如果您需要一个更简单的变体,它也可以与 intellj idea 插件 vim-simulation 一起使用,您可以使用这个(缺点:即使给出另一个寄存器用于粘贴,也会覆盖未命名的寄存器):
vnoremap p pgvy
寄存器 0 到 9 是您拉动或剪切的最新内容等,并且不包括已删除的内容等。因此,如果您拉动/剪切某些内容,它也在寄存器 0 中,即使您在那之后整天都说删除的东西,请注册 0仍然是你拉/切的最后一个东西。
yiw #进入默认寄存器和寄存器0
"0p #放寄存器0的内容
ctrl-r 0 #放入寄存器0的内容
我还有一个朋友总是拉/切注册 x 大声笑。
下面的 vscode 设置应该允许例如 dd 和 dw 变成 "_dd 和 "_dw,它们现在可以在我们的重映射器中正常工作。
{
"vim.normalModeKeyBindingsNonRecursive": [
{
"before": ["d"],
"after": [ "\"", "_", "d" ]
}
]
}
您可以使用以下命令制作一个简单的宏:
q"_dwq
现在要删除下一个单词而不覆盖寄存器,您可以使用@d
主要问题是p
在可视模式下使用。在您以可视模式粘贴内容后,以下功能将恢复未命名寄存器的内容。
function! MyPaste(ex)
let save_reg = @"
let reg = v:register
let l:count = v:count1
let save_map = maparg('_', 'v', 0, 1)
exec 'vnoremap _ '.a:ex
exec 'normal gv"'.reg.l:count.'_'
call mapset('v', 0, save_map)
let @" = save_reg
endfunction
vmap p :<c-u>call MyPaste('p')<cr>
vmap P :<c-u>call MyPaste('P')<cr>
用法和以前一样,寄存器"的内容没有改变。
我发现一开始就拉入“p”缓冲区更容易。
# highlight text you want to copy, then:
"py
# delete or highlight the text you want to replace, then:
"pp
优点(与删除到特定寄存器相反):
"pp
很容易用手指noremap mm m
和
noremap mx "_x
这就是我的处理方式。