VIM 命令或表达式到 select 函数中的文本
VIM command or expression to select text from a function
在我的 .vimrc 文件中,我想配置一个极简函数来执行智能 selection。
例如尝试selectinner(),如果selection为空则尝试inner[],如果仍然为空则尝试inner{}等。
但我一开始就卡住了:从函数调用/执行命令/表达式到 select 文本。
function! SelectInnerBrackets():
" failed attempts
call visualmode()
execute "vi("
execute "visual! i("
endfunction
仅供参考:我实际上使用 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>
如果您阅读 :help visualmode()
,您会注意到(非参数版本的)函数是一个没有副作用的查询。只是 :call
ing 没有任何好处,你不需要当前/以前的视觉模式,因为你自己构建 selection。
像vi(
这样的命令是普通模式命令。要从 Vim 脚本函数调用它们,您需要 :normal!
命令。 :execute
用于 Ex 命令,以插入变量值(这在许多其他语言中称为 eval()
),或使用特殊的 :help key-notation
(我们稍后会用到)。
为了测试select离子是否被制成,Vim方便地有两个特殊标记('<
和'>
)指定select的边界=40=]离子。不幸的是,它们仅在离开视觉模式后设置(通过对其进行操作,或通过 <Esc>
)。在插件中,最好使用 <C-\><C-n>
键而不是 <Esc>
;它也会 return 进入正常模式,但如果我们已经处于正常模式则不会发出哔哔声。我为此使用了一个单独的 :normal!
命令(使用 :execute
以使用特殊的键符号)以确保它也将在前一个命令序列中止时执行,因为没有这样的 selection 可以制作。
综合来看,这是您尝试的更正版本:
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
为了重新select,你可以在之后使用gv
,例如通过这个映射:
nnoremap <Leader>V :if SelectInnerBrackets() <Bar> execute "normal! gv" <Bar> endif<CR>
在我的 .vimrc 文件中,我想配置一个极简函数来执行智能 selection。 例如尝试selectinner(),如果selection为空则尝试inner[],如果仍然为空则尝试inner{}等。 但我一开始就卡住了:从函数调用/执行命令/表达式到 select 文本。
function! SelectInnerBrackets():
" failed attempts
call visualmode()
execute "vi("
execute "visual! i("
endfunction
仅供参考:我实际上使用 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>
如果您阅读 :help visualmode()
,您会注意到(非参数版本的)函数是一个没有副作用的查询。只是 :call
ing 没有任何好处,你不需要当前/以前的视觉模式,因为你自己构建 selection。
像vi(
这样的命令是普通模式命令。要从 Vim 脚本函数调用它们,您需要 :normal!
命令。 :execute
用于 Ex 命令,以插入变量值(这在许多其他语言中称为 eval()
),或使用特殊的 :help key-notation
(我们稍后会用到)。
为了测试select离子是否被制成,Vim方便地有两个特殊标记('<
和'>
)指定select的边界=40=]离子。不幸的是,它们仅在离开视觉模式后设置(通过对其进行操作,或通过 <Esc>
)。在插件中,最好使用 <C-\><C-n>
键而不是 <Esc>
;它也会 return 进入正常模式,但如果我们已经处于正常模式则不会发出哔哔声。我为此使用了一个单独的 :normal!
命令(使用 :execute
以使用特殊的键符号)以确保它也将在前一个命令序列中止时执行,因为没有这样的 selection 可以制作。
综合来看,这是您尝试的更正版本:
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
为了重新select,你可以在之后使用gv
,例如通过这个映射:
nnoremap <Leader>V :if SelectInnerBrackets() <Bar> execute "normal! gv" <Bar> endif<CR>