1

I have a mapping that looks like this:

nnoremap <expr> <c-x>b ":call MyFunction(" . v:count . ")\<cr>"

I also tried to instead define function with range, but the effect is the same.

The point is to be able to press a number, followed by the mapping, e.g. 30<c-x>b. The problem is, it fails if the number of remaining lines in the file is less than count I input. The function actually don't do any line operations, so I don't care about actual number of lines. How can I make a mapping or a function that accepts count and isn't dependent on number of lines in open file?

Edit:

Here's my final version, with working solution:

nnoremap <expr> <c-x>b ":\<c-u>call MyFunction(" . (v:count ? v:count . ")\<cr>" : ")\<left>")

With this, if I press <number><c-b>x, the function is called immediately, or if I press just <c-b>x, I go into command prompt and can enter number manually (using v:count1 by default isn't suitable for my case).

  • Couldnt you just use v:count in MyFunction, and not go through the expr hoops? – D. Ben Knoble Oct 11 at 0:08
  • @D.BenKnoble I agree, range makes more sense. It's just, as I stated in my question, I initially tried both approaches to see which one work. Now, with the solution, I'll revert back to range. – Thunderbeef Oct 11 at 11:40
  • 1
    @D.BenKnoble Actually, scratch that. I though that range attribute is required to see v:count in function scope, but apparently it's not, and I can access v:count right away. – Thunderbeef Oct 11 at 11:42
6

The answer is actually not as complicated as you might think. A trick that I have found very useful in situations similar to this is to remove the <cr> from the end of your mapping and see what comes up. If I do that and run 30<C-x>b, this pops up in the command line:

:.,.+29call MyFunction(30)

This is because it's basically like you typed 30:call MyFunction(30), and putting a count before : will always insert a range. (Try it!)

To fix this, you just use <C-u> to clear the command line before typing in "call MyFunction(30)"

nnoremap <expr> <c-x>b ":\<C-u>call MyFunction(" . v:count . ")\<cr>"

From :h c_<C-u>

                            *c_CTRL-U*
CTRL-U      Remove all characters between the cursor position and
        the beginning of the line.  Previous versions of vim
        deleted all characters on the line.  If that is the
        preferred behavior, add the following to your .vimrc: >
            :cnoremap <C-U> <C-E><C-U>
  • It is worth mentioning that without <C-U> call MyFunction(30) (unless it has range attribute) will be executed 30 times in a row. So in most cases <C-U> is a must. – Matt Oct 10 at 19:20
  • Thanks. The idea to remove <cr> is simple and great. As for you solution, it works, BUT pressing the mapping now also scrolls half-screen up, as if I pressed <c-u> in normal mode. Do you know how to remove this side effect? – Thunderbeef Oct 11 at 11:23
  • Nevermind, I placed <c-u> before : – Thunderbeef Oct 11 at 11:29

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.