在使用Vim时,我经常想用我刚拉出的代码块替换代码块。

但是当我删除要替换的代码块时,该代码块本身就会进入寄存器,它会擦除我刚刚删除的代码块。所以我已经养成了拉拽,然后插入,然后删除我不想要的东西的习惯,但对于大块的代码,这变得很混乱,试图保持插入的块和要删除的块分开。

那么,在Vim中替换文本的最灵活、最快的方法是什么呢?

是否有一种方法可以删除文本而不将其放入寄存器? 有一种说法吗?“替换下一个单词”或“替换到下一段” 还是使用多寄存器特性的最佳方式?


当前回答

Vim有时更倾向于复杂性,而不是实用性,这给用户带来了应用寄存器来复制/删除操作的负担——通常情况下,用户只想粘贴复制的内容,而“忘记”删除的内容。

但是,与其与vim复杂的寄存器作斗争,不如让它们更方便:选择一个“默认”寄存器来存储最新的删除。例如,发送删除到d寄存器(让a-c打开以供特别使用;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)刚刚删除的内容。

其他回答

对于那些主要感兴趣的人,当您通过虚拟选择和粘贴替换文本时,不覆盖未命名寄存器。

你可以使用下面的解决方案,这是简单的,最适合我:

Xnoremap <expr> p 'pgv"'.v:register.'y'

以下是回答(和评论): 如何粘贴而不覆盖寄存器

它首先经过选区,然后再次选择带有新文本的选区(gv)。现在是上次在可视模式下使用的寄存器(通常是未命名的寄存器,但如果使用另一个寄存器进行粘贴,也会产生副作用)。然后将新值再次拉入寄存器。

PS:如果你需要一个更简单的变种,它也适用于intellj idea插件vim-simulation,你可以采用这个(缺点:覆盖未命名的寄存器,即使另一个寄存器被给出粘贴):

Vnoremap p pgvy

好吧,首先执行以下命令:

:h d

然后你会发现你可以删除到一个特定的寄存器。这样就不会改变默认寄存器中的内容。

VIM文档:编号为0的寄存器包含来自最近yank命令的文本, 除非该命令指定了另一个["x]寄存器。

例如,我们删除“foo”和“bar”-注册表0仍然包含“foo”!因此“foo”可以使用“0p”来粘贴

下面的vscode设置应该允许dd和dw变成“_dd和”_dw,现在我们的remapper可以正常工作。

{
     "vim.normalModeKeyBindingsNonRecursive": [
        {
            "before": ["d"],
            "after": [ "\"", "_", "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>

用法和以前一样,register "的内容没有改变。