Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Welcome To Ask or Share your Answers For Others

Categories

0 votes
718 views
in Technique[技术] by (71.8m points)

vim call a function from inside a vmap

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>

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.

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.

Update:

I try to get the following behaviour: In a text like this:

egin{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}

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

that means the text from the beginning of the previous item, until but not including the next item or end{itemize}.

See Question&Answers more detail:os

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome To Ask or Share your Answers For Others

1 Reply

0 votes
by (71.8m points)

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>

If you want the mapping in both visual and select modes, you should use vnoremap

Notes of things to address:

  • 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 Disclaimer: I don't know LateX


与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
OGeek|极客中国-欢迎来到极客的世界,一个免费开放的程序员编程交流平台!开放,进步,分享!让技术改变生活,让极客改变未来! Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Click Here to Ask a Question

...