I have an operator function that yanks double quotes or single quotes, ciq works fine because I want to be inside the quotes but when I do yaq (yank a quote) I don't want to move to the place where the quote is at. Seems like an easy task to just get back to the previous cursor position after the yank? I have tried the following things:

  1. Tried setting the cursor position with an TextYankPost.
  2. Tried setting marks in the actual mapping, probably not allowed cause it's expecting a motion.
  3. Tried restoring cursor position from the function with setpos(). Probably don't work cause it's inside of the function.

This does not work maybe cause it's inside the function.

let saveCur=getcurpos()
execute "normal! mz"
call setpos('.',saveCur)
 exe "normal! `z"
if a:operator == 'y' | call setpos('.',saveCur)  | endif

Not too sure if a call back function would work. Jumps wont work cause exe "normal 12lv" is not a jump. This is the function. I know it's probably overkill when I could have just done exe normal! ?\% but I learned a lot of vimscript from it. Any suggestions are welcome. Thanks

function! QuoteTextObject(whole) abort

let char=a:whole ? 'a' : 'i'
let regex= '\v("|' . "').{-}".'("|' . "')" 
let res=matchstrpos(strcharpart(getline('.'),col('.')-1),regex)
let backRes=matchstrpos(strcharpart(getline('.'),0),regex)
let [start,stop]=copy(res)->remove(1,2)
let [bstart,bstop]=copy(backRes)->remove(1,2)
let offset=stop-start-1
let boffset=bstop-bstart-1

"if nothing was found forward or backward return
if res == ['',-1,-1] && backRes == ['',-1,-1] |call feedkeys("\e")| return 0 | endif

"find match backwards
if res == ['',-1,-1]  
    echom 'no match found forward'
    execute "normal! 0"
    let start=bstart | let offset=boffset

if char == 'a' | execute 'normal! '.start.'lv'.offset.'l' | return 0 |endif
let offset=  eval(offset-2) > 0 ? eval(offset-2).'l':''
let icmd='normal! '.eval(start+1).'lv'. offset
if char == 'i' | execute icmd | return 0 |endif


onoremap <silent> <Plug>QuoteOperatorWhole :<C-U> call QuoteTextObject(1)<CR>
onoremap <silent> <Plug>QuoteOperatorInner :<C-U>call QuoteTextObject(0)<CR>
omap iq <Plug>QuoteOperatorInner
omap aq <Plug>QuoteOperatorWhole

  • I wouldn't be surprised if the operator execution context is independent from the calling context. If you save position from within the function in a global variable and restore from that upon return the result is as expected so maybe there's a solution based on that. BTW, I recommend winsaveview() and winrestview() for state save/restore. – B Layer Jan 14 at 1:58
  • (Or save the state before calling the function. I suspect, though, that there's an even better way to do this. If I can't think of it someone else surely will.) – B Layer Jan 14 at 2:12
  • @BLayer How do I winrestview(g:saveCur) from outside of the function or outside the mapping calling it ? Unless I set a timer or something in the function that would later call another function. I don't think I could include the call in the mapping. Like timer_start() or something. – ritchie Jan 14 at 2:13
  • Perhaps you can't. I was basically thinking out loud and I assumed there was a context switch at the function call (which, in retrospect, isn't a good theory). But if the scope of the switch is wider (or there's an additional switch around mapping) then, indeed, that's a higher mountain to climb. Your timer idea would probably work but let's hope there's a cleaner solution to be had. – B Layer Jan 14 at 2:46
  • @BLayer yea the timer does work thanks. I kinda like it like that cause I can see that it actually yanking something, I have it set to 1ms. The worst thing that can happen at 1ms is that I won't get back to my position. – ritchie Jan 14 at 2:57

What took care of it was calling a call back with timer_start() with a 1ms delay to restore the cursor position.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.