假设我有以下文本文件
name: John Doe
description: My name is John Doe and I'm really good at vim!
name: John Doe
description: My name is John Doe and I'm really good at vim!
name: John Doe
description: My name is John Doe and I'm really good at vim!
name: John Doe
description: My name is John Doe and I'm really good at vim!
有没有办法录制执行以下操作的宏:
从第一个John
开始:
cw
但允许运行宏的用户在此处提供输入
是js<is>w
偷偷把这个词放在后面.
将 John 替换为给定的输入- 重复
理想情况下,我想在第一行输入以下击键:
@qJane
并具有:
name: Jane Doe
description: My name is Jane Doe and I'm really good at vim!
@qJim
name: Jim Doe
description: My name is Jim Doe and I'm really good at vim!
获取用户输入的最简单方法是使用input()
函数,该函数允许您提示输入名称并在表达式中使用它。
不幸的是,您不能真正从宏中使用它,因为宏也会记录您对提示的回答(重播您构建的答案会遇到类似的问题。
不过,您可以从函数中使用它,并将该函数绑定到键映射:
function! ChangeName()
let newname = input('Name? ')
return '0/<John>'."<cr>cw".newname."<esc>n."
endfunction
nnoremap <expr> <leader>cn ChangeName()
然后,您可以键入cn
,这将提示您输入新名称。键入新名称并按 Enter 后,它将用新名称替换出现的前两次John
。
该函数返回映射的扩展,使用 map 命令中的<expr>
使其使用函数的返回值。(让函数发出带有:execute
的:normal!
命令也是一种可能的方法。
您提到按@qJim
或@qJane
,那里没有提示,新名称"感觉"像命令的一部分。通过在映射背后的函数循环中使用getchar()
,可以更接近类似的东西。您仍然需要决定如何终止名称,您会在最后使用 ENTER 吗?你会使用时间来决定命令何时结束(需要快速键入吗?如果您使用getchar()
,您可能还需要处理退格键和取消命令。使用input()
当然更容易,并且可能足够,具体取决于您的特定用例。
尽管q
经常与术语宏一起使用,但其 目的是简单地记录和重复一系列 字符。在这里重复关键 - 如果你的意图是 不重复相同的确切顺序,那么q
可能是 不是理想的解决方案。
您应该能够通过地图轻松实现此目的 (请注意,:h macro
会指向:map
(。您可以使用:execute
构建一个替换第一个的命令约翰在当前行和之后的行中的出现次数 无论input()
有什么回报。后者负责 用于提示用户。
下面是一个实现映射到,n
的小示例:
:nnoremap ,n :exe ',+s/John/' . input('Name: ')<CR>
如果您不知道要替换的名称,可以要求 那也是:
:nnoremap ,n :exe ',+s/' . input('Old name: ') . '/' . input('New name: ')<CR>
或者使用正则表达式来捕获"name"后的第一个单词 忽略":"或"是":
:nnoremap ,n :exe ',+s/vname(: | is )+zsw+/' . input('New name: ')<CR>