3

A plugin I've recently started maintaining currently checks to see if any bindings exist to its functions before creating the default ones. This makes it easy to setup custom bindings and not have to do anything about the default ones.

if !hasmapto('<Plug>MyFunction', 'n')
    nmap <buffer> <Leader>f <Plug>MyFunction
endif

What this doesn't do is keep these default bindings from clobbering existing mappings. How can I detect if, say, there is an existing normal mode mapping for <leader>f before clobbering it with the plugin's default mapping.

1

2 Answers 2

3

You can use the mapcheck() function to check if the user mapped a key to something:

:echo json_encode(mapcheck('<F1>', 'n'))
""

:echo mapcheck('<F11>', 'n')
:set cursorcolumn!<CR>:set cursorcolumn?<CR>

So in your mapping, you can do:

if !hasmapto('<Plug>MyFunction', 'n') && mapcheck('<Leader>f', 'n') is# ''
    nmap <buffer> <Leader>f <Plug>MyFunction
endif

Personally, I'm not completely convinced this is actually a good approach though. While it does prevent overriding user mappings, it's also very "magic" and may be surprising.

An approach that I often use is to make a single setting to disable all mappings:

if get(g:, 'myplugin_map_keys', 1)
    nmap <buffer> <Leader>f <Plug>MyFunction
endif

This way users have a reasonable set of mappings by default, but can disable mappings and do their own thing if they want something custom.

Another option is to map from a variable:

exe printf('nmap <buffer> %s <Plug>MyFunction',
         \ get(g:, 'myplugin_map_foo', '<Leader>f')

This way users can set their own keys for a specific mapping, without having to remap everything.


I don't think there is "one right way". Aside from personal preference, it also depends on the kind of plugin you're working on. For some plugins a key mapping is just an "extra bonus", whereas it's critical for others. Some plugins map just one or two keys, others dozens or even hundreds.

For smaller plugins with just one or two mappings, the first method will usually be better; for larger plugins with a lot of mappings, the second is often better. Of course, you can also do both.

2
  • Thanks. Using this I searched around for other implementations and am now wondering why you used ... is# '' instead of ... == ''. Can you clarify that bit?
    – Caleb
    Apr 16, 2019 at 7:17
  • 2
    @Caleb is is the "strict comparison", similar to === in JavaScript and PHP. 0 == '' is 1, which is often not what you want, but 0 is '' is 0. The # is to explicitly match case (otherwise ignorecase setting is used). Neither are strictly needed here, but it's just a habit I've picked up after I ran in to a few bugs with ==, and I think everyone should probably be using it (just like everyone is using ===). Also see :help expr4. Apr 16, 2019 at 7:23
1
silent! {map} <unique> {lhs} {rhs}

Works too. The <unique> modifier issues an error if there is already a mapping for the left-hand side, which silent swallows.

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.