3

I'm trying to reverse engineer how a .vimrc file works. One of the lines is this:

autocmd BufEnter *.p[lm] nmap <buffer> ;t :call RunPerlTests()<CR>

The only part I'm unclear on is the nmap <buffer> ;t bit. So I'm not sure what will trigger a call to the function.

1 Answer 1

4

It seems to be an autocmd listening to the BufEnter event, and is only fired for a file whose extension is .pl or .pm (for more info about the syntax, see :h file-pattern).

Whenever this event occurs, the autocmd should install the following mapping:

nmap <buffer> ;t :call RunPerlTests()<CR> 

This mapping is not global, but local to the current buffer (the one where the autocmd was fired), thanks to the argument <buffer> which was passed to the :nmap command.

The {lhs} of the mapping is ;t, and the {rhs} is :call RunPerlTests()<CR>.
It means that whenever you will hit ;t in normal mode, Vim should execute the Ex command :call RunPerlTests()<CR>. This last command should call the custom function RunPerlTests().


autocmd BufEnter *.p[lm] nmap <buffer> ;t :call RunPerlTests()<CR> " | | | | | | " | | | | | +-- `{rhs}` of the mapping " | | | | +-- `{lhs}` of the mapping " | | | +-- argument to pass to `:nmap`; limits the scope of the mapping to the current buffer " | | +-- mapping command to execute " | +-- pattern to limit the scope of the autocmd to certain filetypes " +-- event of the autocmd 

You probably want to replace the :nmap command, which is recursive, with the non-recursive version :nnoremap. You only want the recursiveness, when you need all or a part of the {rhs} to be replaced using another mapping, which doesn't seem to be the case here.

And you could prefix the Ex command :call with the keycode <C-u>, to delete a possible range which could be inserted by accident on the command-line if you hit a number before ;t.

It would give:

autocmd BufEnter *.p[lm] nnoremap <buffer> ;t :<C-U>call RunPerlTests()<CR> 

To understand why <C-U> could be useful, in normal mode hit 3:. On the command-line you should see :.,.+2. This is a range, which can be read as from the current line down to the 2nd line after the current one.

If you pass a range to the :call command, by default Vim should call the function as many times as there are addresses inside the range.

Example:

fu! MyFunc() echo 'hello' endfu nno cd :call MyFunc()<CR> 

Now, hit 3cd. Because you hit 3 before the {lhs} of your custom mapping cd, Vim will automatically inserts the range .,.+2, which will give on the command-line:

:.,.+2call MyFunc()<CR> 

This will call MyFunc() 3 times, because there are 3 addresses inside the range .,.+2, and you should see hello 3 times.

As said earlier, if you want to avoid this, you could prefix the :call command with the <C-U> keycode (see :h c^u). It will make sure that nothing is inserted before :call.

Note that if your custom function RunPerlTests() was defined with the range attribute, then it probably expects a range. In this case, don't add <C-U>.


If you haven't done it already, you also probably want to wrap your autocmd inside an augroup and clear the latter with the autocmd! command:

augroup YourAugroup autocmd! autocmd BufEnter *.p[lm] nnoremap <buffer> ;t :<C-U>call RunPerlTests()<CR> augroup END 

The reason for this is to avoid that your autocmd is duplicated every time you source your vimrc file. See this question for more info.

5
  • 1
    Thank you. I'm not sure I understand the :nmap vs. :nnoremap but I'll look that up. Regarding the insertion of the Ex command, are you saying if I don't do that and I accidentally type something like 20;t it will call the function 20 times? Commented Feb 12, 2017 at 4:30
  • 2
    @StevieD Yes I think you're right, I'm going to edit my answer because what I said about the range is not correct. I'm also going to try to add an example and a link about :nmap vs :nnoremap. Commented Feb 12, 2017 at 4:36
  • OK, the function does not have a range attribute. I'm not sure what that is but I will learn when the time comes. I will add in the <C-U> bit as you suggest. I read up on recursive vs. non-recursive. I get that now, too, though I'm not quite clear on what you mean when you say "when you need all or a part of the right hand side to be replaced." Commented Feb 12, 2017 at 4:40
  • 2
    @StevieD When you use a recursive mapping command, if any part of the {rhs} of your first mapping, is also the {lhs} of another 2nd mapping, then Vim will automatically replace this part with the {rhs} of the 2nd mapping. Sometimes, you may want this, in particular when you want to use a <Plug> mapping provided by a plugin which you installed. But most of the time, you don't want your mapping command to be recursive, because it can lead to unexpected side-effects. See here: learnvimscriptthehardway.stevelosh.com/chapters/05.html Commented Feb 12, 2017 at 4:53
  • 3
    @StevieD If you don't understand yet, just follow the rule given at the end of the page: never use recursive mapping, unless you really need to. :nmap, :vmap, :xmap, :omap, :smap, :cmap, :imap are all recursive mapping commands for various mode. Use :nnoremap, :vnoremap, :xnoremap, :onoremap, :snoremap, :cnoremap, :inoremap instead. Commented Feb 12, 2017 at 4:55

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.