在我的.vimrc文件中,我想配置一个简约功能来执行智能选择。 例如,尝试选择inner(),如果选择为空则尝试inner [],如果仍为空则尝试内部{}等。 但是我一开始就陷入困境:调用/执行命令/表达式来从函数中选择文本。
function! SelectInnerBrackets():
" failed attempts
call visualmode()
execute "vi("
execute "visual! i("
endfunction
Fyi:我实际上使用neovim,但它可能对这个问题没有影响。
编辑:基于@Ingo Karkat提出的解决方案,我分享了我的最后一段代码。请注意,它不能与交叉嵌套分隔符完美配合。function! SelectInner(delimiter)
" We have to switch to normal mode to compare positions
execute "normal! vi".a:delimiter."\<C-\>\<C-n>"
return getpos("'<") != getpos("'>")
endfunction
function! TrySelectInner(delimiters)
for delimiter in a:delimiters
if SelectInner(delimiter)
normal! gv
break
endif
endfor
endfunction
" quickly select a word, expression or brackets content
nnoremap W viw
nnoremap E :call TrySelectInner(["'", '"'])<CR>
nnoremap R :call TrySelectInner(['(', '[', '{'])<CR>
答案 0 :(得分:2)
如果您阅读:help visualmode()
,您会注意到(非参数版本的)函数是一个没有副作用的查询。只是:call
没有任何好处,并且您不需要当前/以前的可视模式,因为您自己构建选择。
vi(
之类的命令是普通模式命令。要从Vimscript函数调用它们,您需要:normal!
命令。 :execute
用于Ex命令,以便插入变量值(在许多其他语言中称为eval()
),或使用特殊:help key-notation
(稍后我们将使用它)。< / p>
为了测试是否进行了选择,Vim方便地有两个特殊标记('<
和'>
)来指定选择的边界。不幸的是,它们仅在视觉模式被保留后(通过操作或通过<Esc>
)设置。在插件中,最好使用<C-\><C-n>
键而不是<Esc>
;它也将返回正常模式,但如果我们已经处于正常模式,则不会发出蜂鸣声。我使用单独的:normal!
命令(:execute
使用特殊键符号)以确保它在前一个命令序列中止时也会执行,因为不能进行这样的选择。
总之,这是您尝试的更正版本:
function! SelectInnerBrackets()
echomsg "trying (...)"
normal! vi(
execute "normal! \<C-\>\<C-n>"
if getpos("'<") != getpos("'>") | return 1 | endif
echomsg "trying [...]"
normal! vi[
execute "normal! \<C-\>\<C-n>"
if getpos("'<") != getpos("'>") | return 1 | endif
echomsg "trying {...}"
normal! vi{
execute "normal! \<C-\>\<C-n>"
if getpos("'<") != getpos("'>") | return 1 | endif
echomsg "nothing found"
return 0
endfunction
要重新选择,您可以在之后使用gv
,例如通过这种映射:
nnoremap <Leader>V :if SelectInnerBrackets() <Bar> execute "normal! gv" <Bar> endif<CR>