8

I find that if you enter a numeric prefix prior to executing an ex command, the convention that it applies is to set up the command to prep an operation across a line range. It is explained in the documentation,

A NUMBER OF LINES

When you know how many lines you want to change, you can type the number and then ":". For example, when you type "5:", you will get:

    :.,.+4

Now you can type the command you want to use. It will use the range "." (current line) until ".+4" (four lines down). Thus it spans five lines.

Now what I am dealing with is a custom function of mine, this one:

function! MyAmazingEnhancedDot()
    if v:hlsearch == 1
        :normal! .n
    else
        :normal! .j
    endif
endfun

This is just a way to streamline repetitive tasks that include repeating an operation on a range of lines or over a series of search matches.

This function is bound to a hotkey. Such as Alt+. or whatever.

My aim is to be able to do something very powerful: I should be able to type /varName<CR>ciwnew-var<ESC>n9<Alt+.> to achieve renaming 10 instances of varName to new-var.

What actually happens if I do this is that it does not perform the renaming and the 9 lines are manipulated with my .-saved edit operation from column 0.

I can only assume that Vim is interpreting my keystrokes thus: :.,.+8 normal! .n.

On the glass-half-full side, the :normal! .j case of the bind actually works, because the j motion having no effect is of no consequence in this situation. (I still need the j to make it work in a non-numeric-prefixed interactive use case).

So my question is how can I override the line-expansion behavior that Vim applies to my bind? What would be fantastic is if I can read in the numeric prefix as an argument or something like that.

7

By default vim treats all functions as if they are default ex commands, i.e. any prefixed numbers are used as {range}. To change this you need to modify your function and your map to use a count.

Map with count

Maps can take a count and are made available via v:count and v:count1. The first contains 0 if no count is provided and the later contains 1 as the default. You can create a map to your function:

nnoremap <M-.> :<C-u>call MyAmazingEnhancedDot(v:count1)<cr>

For more info :h v:count

Commands with count

Commands can have the option of either a {range} or a count as a prefix. When creating the command the flag -count disables the range option and defaults the <count> variable to 0. Optionally a default value can be provided -count=N. The prefix value is then available via the variable count in your function.

A command using count would look like this:

:command -count=1 EDot call MyAmazingEnhancedDot(<count>)

Now when you call 9EDot your function is called with the count of 9 instead of a range.

For more info see :h command-count

Both examples

Here is your code:

function MyAmazingEnhancedDot(count)
  let c = a:count
  while c > 0
    if v:hlsearch == 1
      :normal! .n
    else
      :normal! .j
    endif
    let c -= 1
  endwhile
endfunction

command -count=1 EDot call MyAmazingEnhancedDot(<count>)

nnoremap <M-.> :<C-u>exe v:count1 . "EDot"<CR>

Now you can do your example

/varName<CR>ciwvar-name<esc>n9<M-.>
  • 1
    Cool. Now there seems to be too many ways to solve my problem! I understand that you combined both mechanisms in the example you gave in order to illustrate how to use them. But I wonder if it isn't sufficient to just use nnoremap <M-.> :<C-u>call MyAmazingEnhancedDot(v:count1)<cr> and skip the command -count=1 EDot call MyAmazingEnhancedDot(<count>)? – Steven Lu May 7 '15 at 4:01
  • Skipping the command option is fine. The only benefit you get from the command option is being able to call it from ex commands such as :9EDot. If you don't use ex commands a lot then skip it. – jecxjo May 7 '15 at 4:16
  • Awesome. Now your perfect answer is complete! – Steven Lu May 7 '15 at 20:31

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.