你能在vim中创建交互式宏或录制吗?

7
我希望您能定义一个vim宏,以便在特定时间点为用户输入而中断,这是可能的吗?
编辑:事实证明我所指的是录制(q),而不是宏。
在录制中使用input命令是可行的,但是这比它值得的麻烦多了。
我首先将插入输入逃脱键映射到一个键上。
:map <F2> a<C-R>=input('input: ')<CR>

然后我将这个记录保存在 q 寄存器中。
name: 

将其复制并粘贴到一个新标签页中

iname: ^[

在最终逃脱之后,我按下了<C-V><F2>,使得该行变成:

iname ^[^[OQ

我将其拉回到q缓冲区,然后使用宏,让我可以使用输入函数。虽然可行,但效果很差。

4个回答

3
是的。请看函数input({prompt}, [, {text} [, {completion}] ])。甚至还有一个inputdialog({prompt} [, {text} [, {cancelreturn}]]),用于弹出对话框。

vim 真是太棒了!有没有像“我能在 vim 中做 xxx 吗?”这样的问题,回答是否定的呢? :) - moritz
input() 在宏中似乎不可用(甚至通过 Ctrl-R=input('prompt: ') 也不行),但如果您可以使用普通映射或函数,它将很好地完成工作。 - mogelbrod
@fork0:你是怎么做到的?qq i<C-R>=input('>')<CR>test<CR><ESC>q 当播放时会插入 test,因为它是宏的一部分 :(编辑:结果发现我所谓的宏在Vim中被称为录制,我的错 :) - mogelbrod
我也在考虑录制(q)。映射仍然可以完成工作,但不幸的是,在创建效果时无法观看它。 - everett1992
@moritz 的第一条评论。(这是个玩笑)好吧,你不能问“我能用只有5个字符的vim在脑海中完全正确地编写所有代码吗?”然后得到一个答案 :) - Dimitar Slavchev
显示剩余2条评论

2
如果您在映射或宏内部使用input(),剩余的字符将被视为输入,这不是您想要的。Vim提供了inputsave()inputrestore()函数来暂时挂起从映射字符流中读取。
根据mogelbrod的答案,这种方法行不通;itest会被读入作为输入:
oBEFORE ^R=input('prompt> ')^Mitest

但是这个可以:
function! Input()
    call inputsave()
    let text = input('prompt> ')
    call inputrestore()
    return text
endfunction
oBEFORE ^R=Input()^Mitest

很不幸,由于<C-R>需要一个表达式,我们不能将命令放在行内,而必须定义一个单独的Input()函数。


嗨,我认为这个不再起作用了。输入仍然保存在宏寄存器中。 - Liarokapis Alexandros
@LiarokapisAlexandros:我还在这里工作,使用的是Vim 8.2.1719版本。如果无法实现此功能,则会是Vim中的一个错误,因为inputsave()等函数专门用于此目的。 - Ingo Karkat
vim 8.0 在这里,有点好奇的是,在输入提示时输入的文本实际上包含在宏缓冲区中,因此它将文本附加到下一个重复输入的文本中。我还需要检查映射。 - Liarokapis Alexandros

1

很遗憾,似乎不可能。您可以在宏中触发input(),但之后似乎无法继续进行,因为记录的任何其他输入都会插入到输入提示符中。

将该行复制到命名寄存器("qY)中并运行它(@q)以尝试它。
注意:使用Ctrl-V Ctrl-R/M替换^R^M(请参见:help i_CTRL-V)。

  • oBEFORE ^R=input('prompt> ') - 可行
  • oBEFORE ^R=input('prompt> ')^Mitest - 可行,但将itest插入到提示符中
  • oBEFORE ^R=input('prompt> ')<CR>test - 失败

我注意到了同样的事情。如果能够实现这个功能就太好了。 - everett1992
@everett1992:可以通过使用 "inputsave()" 和 "inputrestore()" 函数来实现;请查看我的回答。 - Ingo Karkat

0

我从这个和其他的帖子中收集了信息,并编写了这个脚本:

function! MacroInterrupt()
    "call inputsave()
    if strlen(reg_recording()) == 0
        if mode() == 'n'
            call inputsave()
            let tmp_col = col('.')
            let tmp_line = line('.')
            let text = input('input:')
            let line = getline('.')
            call setline('.', strpart(line, 0, col('.') - 1) . text . strpart(line, col('.') - 1))
            call cursor(tmp_line, tmp_col + strlen(text))
            call inputrestore()
            return text
        else
            call inputsave()
            let text = input('input:')
            call inputrestore()
            return text
        endif
    else
        echo "Interrupt added to macro"
        call setreg(reg_recording(), getreg(reg_recording()) . "\<F2>")
        "echo getreg("q")
    endif
    "call inputrestore()
endfunction

map <F2> :call MacroInterrupt() <CR>
inoremap <buffer><expr> <F2> MacroInterrupt()

我希望这可以帮助那些尝试相同事情的人。


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