vim 从 vmap 内部调用函数 [英] vim call a function from inside a vmap

查看:26
本文介绍了vim 从 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>

如果你想在 visualselect 模式下映射,你应该使用 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 set nowrapscan?)
    • 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屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆