0

I have a mapping in my .vimrc.

It is the following:

nnoremap q; :call Add_comment_css()<CR>

And then I can run, say 10q;

And then it will run 10 times.

But my problem is that the cursor always moves as well.

I want the cursor to stay in place.

I have tried all the solutions here:

https://stackoverflow.com/questions/10468324/how-to-run-a-search-and-replace-command-without-cursor-moving-in-vim

None of them works on my computer. Don't know why.

I have also tried having a variable that iterates. Then store that variable in a register on each iteration. Then afterwards I could somehow go back if I could figure out how to travel by line numbers, relative to current line, using a variable or register.

But that's just a hack.

What I really want, is to not travel when I apply the substitution.

My function is the following:

function! Add_comment_css()
    " Add At Beginning.
    s/^/\/\*
endfunction

Does anybody know how to do that?

3
  • Does this answer your question? How to restore cursor position after the document is reformatted?
    – Matt
    Commented Feb 9, 2023 at 16:34
  • I get error, E481: No range allowed
    – john-jones
    Commented Feb 9, 2023 at 16:55
  • Note that the reason 10q; works is that it becomes :.,.+9call Add…(), which calls the function once for each line in the range since the function is not declared to handle the range itself.
    – D. Ben Knoble
    Commented Feb 9, 2023 at 16:58

2 Answers 2

2

You could do:

function! Add_comment_css(range, line1, line2)
  let l:pos = winsaveview()

  " Add At Beginning.
  if a:range == 2
    let command = a:line1 ."," . a:line2 .'s/^/\/\*'
    " echo command
    execute command
  elseif a:range == 0
    s/^/\/\*
  endif

  call winrestview(l:pos)
endfunction

command! -range=% AddCommentCss call Add_comment_css(<range>, <line1>, <line2>)
nnoremap q; :AddCommentCss<CR>

An alternative using pure function:

function! Add_comment_css() range
  let l:pos = winsaveview()

  " Add At Beginning.
  let command = a:firstline ."," . a:lastline .'s/^/\/\*'
  execute command

  call winrestview(l:pos)
endfunction

nnoremap q; :call Add_comment_css()<CR>
18
  • Now all the substitutions happen on the same, first line.
    – john-jones
    Commented Feb 9, 2023 at 16:34
  • I updated the question, now it contains the function itself. Which always runs on the same line, as is.
    – john-jones
    Commented Feb 9, 2023 at 16:35
  • 1
    I would not use mkview for this; IIRC it creates a file on disk. winsaveview &co. (or whatever it's called) should be sufficient.
    – D. Ben Knoble
    Commented Feb 9, 2023 at 16:57
  • And how would you use winsaveview?
    – john-jones
    Commented Feb 9, 2023 at 16:58
  • 1
    I was on the verge of becoming super depressed over this. but now its 17 o'clock and I just got that thing to work as im finishing the workday. So tmrw I can move it forward so I'm allright.
    – john-jones
    Commented Feb 9, 2023 at 17:17
3

First, it is important to understand why the substitution is applied on [count] lines when you do [count]q;.

10q; doesn't execute q; 10 times. It prepends 10 to the stream of inputs taken from the right-hand-side of your q; mapping. In some cases it might behave like if you repeated your mapping 10 times:

nnoremap <key> dd
10<key>              " same as 10dd

but, in your case, 10 is prepended to :call and, as explained under :help N:, a count before : is automatically transformed into a range. But you are not done yet, :help :call has this to say about [count]:

[…]
When a range is given and the function doesn't handle it
itself, the function is executed for each line in the range,
with the cursor in the first column of that line.  The cursor
is left at the last line (possibly moved by the last function
call).  The arguments are re-evaluated for each line.
[…]

So this is your chain of transformations:

10q;
10:call Add_comment_css()<CR>
:.,.+9call Add_comment_css()<CR>

which explains why you end up calling that function on 10 lines.

From there, the next thing to decide is what meaning you want to give to 10 in 10q;:

  • Do you want it to express the number of lines you want to cover (current behavior)?
  • Do you want it to be ignored?
  • Do you want it to express the number of leading comments you add to the line?

If you want [count] to be ignored, then you should probably avoid giving a count to begin with. That's extra work that you want to have no effect so why bother?

If the count is accidental (it happens), then you could simply use the old :help c_ctrl-u technique:

nnoremap q; :<C-u>call Add_comment_css()<CR>

where <C-u> removes any accidental range before call…, or its more modern :help <Cmd> alternative:

nnoremap q; <Cmd>call Add_comment_css()<CR>

If you want [count] to express the number of leading comments you add to the line, then you will have to disable its native implicit handling first, then handle it explicitly:

function! Add_comment_css()
    for i in range(v:count1)
        silent s/^/\/\*
    endfor
endfunction
nnoremap q; <Cmd>call Add_comment_css()<CR>

If you are still using an older Vim without <Cmd>, use this mapping instead:

nnoremap q; :<C-u>call Add_comment_css()<CR>

See :help :for, :help range(), and :help v:count1.

20
  • Thanks Romain. Very interesting :-) Commented Feb 10, 2023 at 8:04
  • What concepts are you struggling with? The snippet at the bottom is tested and working in Vim 9.
    – romainl
    Commented Feb 16, 2023 at 10:30
  • If I copy the bottom paragraph into my code, nothing works if I have the <Cmd>. But if i have : instead of it. Then if I do 3q; it implements everything 3 times for the next 3 lines. So it's either nothing or 3 squared. I can fix it by removing the for i in range. but the cursor is always moving with the operation. I have tried fixing that by adding the winsaveview above and below as in the other example but it doesn't work. So I'm not able to get this to work.
    – john-jones
    Commented Feb 16, 2023 at 11:16
  • I'm using Vim 8.1. Do you think that's the problem? I am trying to update to 9.x. apt update and upgrade doesn't work. I am trying to see how it's done on miscellaneous places. Most of them seem to not work and some are warning the newest versions may be unstable. Do you have any recommendation as to how to go about upgrade to some stable 9.x?
    – john-jones
    Commented Feb 16, 2023 at 12:03
  • It seems like Vim 9 is still cutting edge and still not available in the default repository on linux. itsfoss.com/install-latest-vim-ubuntu I would really like to just chill with upgrade until its in the default repository. But then this example doesn't work. And then I can't fix my problem.
    – john-jones
    Commented Feb 16, 2023 at 12:41

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

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