vim 从 vmap 内部调用函数 [英] vim call a function from inside a vmap
问题描述
我创建了一个 vmap 文本对象,用于选择单个 LaTeX \item 的文本:
I have created a vmap text object for selecting the text of a single LaTeX \item:
vmap im ?\\item<CR>o/\\item\\|\\end{itemize}<CR>b$
但这有一个令人讨厌的功能,我会丢失当前的搜索词.我已经读过当搜索发生在函数调用中时,搜索词会被恢复,所以我想将地图转换为只调用一个可以进行搜索的函数:
But this has the annoying feature that I lose my current search term. I have read that search terms are restored when the search happens inside a function call, so I wanted to convert the map to just call a function that would do the searches:
function! ItemizeTextObject()
?\\item
normal o
/\\item|\\end{itemize}
normal b$
endfunction
vmap in :call ItemizeTextObject()<CR>
不幸的是,这不起作用:我收到一个错误(找不到模式:\item|\end{itemize}"),根本没有选择任何文本,并且在我的光标所在的行下方插入了一个新行在.我尝试了几种变体,但都没有成功.
Unfortunately, this does not work: I get an error ("Pattern not found: \item|\end{itemize}"), no text at all is selected, and a new line is inserted below the line my cursor is on. I tried several variations of this, and had no success.
我认为基本问题是调用函数时必须保留可视模式(命令中的 o
应该切换到选择的另一端,但它插入了一个新行相反),但我不知道如何.
I think the basic problem is that I have to preserve the visual mode when calling the function (the o
in my command should switch to the other end of the selection, but it inserts a new line instead), but I don't know how.
更新:
我尝试获得以下行为:在这样的文本中:
I try to get the following behaviour: In a text like this:
\begin{itemize}
\item lorem ipsum...
\item piece of text I want to select,
the *CURSOR* is here, and there is more text
that follows
\item lorem ipsum...
\end{itemize}
我要打vin
,然后中间的文本块要选中:
I want to hit vin
, and then the text block in the middle should be selected:
\item piece of text I want to select,
the *CURSOR* is here, and there is more text
that follows
表示从前一个 \item
开始的文本,直到但不包括下一个 \item
或 \end{itemize}
>.
that means the text from the beginning of the previous \item
, until but not including the next \item
or \end{itemize}
.
推荐答案
我已经使用了 operatorfunc
上的文档提出了以下内容,这应该是(接近)您想要的1:
I've used the doc on operatorfunc
to come up with the following, which should be (close to) what you want1:
function! ItemizeTextObject(type, ...)
let sel_save = &selection
let &selection = "inclusive"
let reg_save = @@
if a:0 " Invoked from Visual mode, use '< and '> marks.
silent! 1,+1?\\item
norm v | " use V for linewise visual mode
"" use V for linewise visual mode:
"norm V
silent! /\\item\|\\end{itemize}
"elseif a:type == 'line'
"elseif a:type == 'block'
else
silent! 1,+1?\\item
norm v
silent! /\\item
endif
norm b$
let &selection = sel_save
let @@ = reg_save
endfunction
silent! unmap in
xnoremap <silent> in :<C-U>call ItemizeTextObject(visualmode(), 1)<CR>
如果你想在 visual 和 select 模式下映射,你应该使用 vnoremap
If you want the mapping in both visual and select modes, you should use vnoremap
注意事项:
- 您现在可以从其他模式实现运动(填写函数中的分支)
- 如果
wrapscan
开启,没有搜索应该换行(也许临时设置nowrapscan
?) - 您可能希望重复操作符,以便您可以扩展选择,方法是说
vininin
(请参阅https://stackoverflow.com/a/7292271/85371 示例) - 看起来您想要逐行"行为(由于
b$
?)- 考虑使用
norm V
(见评论)
- you can now implement the motion from another mode (fill in the branches in the function)
- if
wrapscan
is on, no search should wrap (perhaps temporarily setnowrapscan
?) - you might want to make the operator repeating so you can extend the selection by saying
vininin
(see https://stackoverflow.com/a/7292271/85371 for an example) - it looks like you want 'linewise' behaviour (due to
b$
?)- consider using
norm V
(see comment)
编辑我将行为与这个简单的映射进行了比较:
Edit I compared the behaviour with this simple mapping:
xnoremap <silent>in ?\\item<CR>o/\\item\\|\\end{itemize}<CR>b$
<小时>
<子>1 免责声明:我不知道 LateX
1 Disclaimer: I don't know LateX
这篇关于vim 从 vmap 内部调用函数的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!
- consider using
- 考虑使用