如何通过Vim中的外部命令过滤不跨越整行的可视选择内容?

9
我想通过命令在Vim中筛选视觉选择。我所了解的过滤方式总是过滤视觉选择延伸的整行:
在行中选择代码a test
this is a test

打字

:'<,'>!echo "the result"

会导致
the result

但是我想要:

this is the result

2个回答

3
考虑以下映射,符合行为 ! 行过滤命令(见:helpg \*!\*:help v_!)。
nnoremap <silent> <leader>! :set opfunc=ProgramFilter<cr>g@
vnoremap <silent> <leader>! :<c-u>call ProgramFilter(visualmode(), 1)<cr>
function! ProgramFilter(vt, ...)
    let [qr, qt] = [getreg('"'), getregtype('"')]
    let [oai, ocin, osi, oinde] = [&ai, &cin, &si, &inde]
    setl noai nocin nosi inde=

    let [sm, em] = ['[<'[a:0], ']>'[a:0]]
    exe 'norm!`' . sm . a:vt . '`' . em . 'x'

    call inputsave()
    let cmd = input('!')
    call inputrestore()

    let out = system(cmd, @")
    let out = substitute(out, '\n$', '', '')
    exe "norm!i\<c-r>=out\r"

    let [&ai, &cin, &si, &inde] = [oai, ocin, osi, oinde]
    call setreg('"', qr, qt)
endfunction

非常好!很抱歉我的问题不够精确(kev也是如此)。实际上,我想要处理的是最一般的情况,即我想同时做到以下两点:1)将可视选择传递给命令;2)使用短命令在vim中指定该命令。也就是说,vim命令应该将你示例中的“base64 --decode”作为参数。 - highsciguy
换句话说,它应该有效地执行与过滤命令!相同的操作,只针对可视选择,而不是完整的行。 - highsciguy
现在我明白了。请查看更新的答案,其中列出了尝试实现过滤命令的映射。 - ib.
@user429540:Leader 是一个可配置的键,方便创建映射(参见 :help mapleader);默认情况下,它是反斜杠字符。上面的映射应该与默认的 ! 过滤方式一样使用:在可视模式下选择一段文本,然后按下您的 Leader 键(默认为反斜杠),然后再按 !;或者不选任何内容,按下这个键组合,然后使用运动命令(例如 wW) 等)。 - ib.
我明白了。我打字太慢了。! 命令应该紧跟在 leader 键后面。我仍然看到的唯一奇怪的行为是,在可视模式选择之前的空格被命令输出替换了。 - highsciguy
显示剩余2条评论

3
你可以使用\%V来匹配视觉区域内的内容:
:'<,'>s/\%V.*\%V/\=system('echo -n "the result"')

谢谢,这个有效,但有点长。请问一个以 shell 命令作为参数的 vmap 会是什么样子? - highsciguy
1
当然,在我的示例中,命令并不依赖于可视选择,这在一般情况下可能是成立的。那么如何将可视选择作为参数传递给命令呢? - highsciguy

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