The main question is in the title, that is, I have a function, which is invoked by the user and it should 'remember' necessary stuff between invocations, so the next time the user calls it (like, presses the mapping) the function should be aware of certain data.

So if anyone could suggest how can I better achieve this, it'd great.

But I also have the current attempt, which is trying to make this through a mapping and storing values inside a variable of a higher scope. And it doesn't work, for some reason it works only for the odd calls. That is, I source the script, go to the insert mode, invoke the mapping 10 times, then :echo b:var and it's 5. If I press the mapping 9 times it also equals to 5. If I press 11 times, it's 6.

let b:var = 0

function! Foo(arg)
  return a:arg + 1

inoremap a <Esc>:let b:var = Foo(b:var)<CR>

Could someone explain, what's happening here, please?

I'd rather use return values, than directly setting b:var inside the function, since it should be easier to make automated tests.

2 Answers 2


When I need to do that, I do it within the function: I assume that I'm not writing a re-entrant function. I prefer the mapping to be as simple as possible.

Also, I use:

  • script local variables (s:) to store global data -- i.e. independently of the current buffer.
  • buffer local variables (b:), or a script local dictionary (s:) indexed by buffer numbers when I don't want to invade b: dictionary.

BTW, I see you use a buffer local variable. If you initialize it to 0 in your script, that could work correctly only within a ftplugin file. With autoload plugin files, or plugin files, this won't work correctly as they are loaded only once for the whole Vim execution.

PS: Is your test something like: iaaaaa? If that the case, it:

  1. goes into insert mode
  2. executes the mapping and leave insert mode
  3. returns into into mode
  4. executes the mapping and leave insert mode
  5. returns into into mode2.
  6. executes the mapping and leave insert mode

Having the function called once every two a seems normal to me.


This is what happens:

  • i - enter insert mode
  • a - call func -> var = 1, but you left insert mode!
  • a - executed in normal mode -> append -> you are back in insert mode
  • a - call func -> var = 2, but you left insert mode!
  • a - executed in normal mode -> append -> you are back in insert mode


You might want to try

inoremap a <c-o>:let b:var = Foo(b:var)<CR>

The <c-o> leaves insert mode just for one command and the returns to insert mode.

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.