vim map confliction between vimrc and plugin - vim

I'm using jedi-vim. It defines key map <Leader>n as some commands while I also defines it in .vimrc file like following.
nnoremap <Leader>n <C-w><C-w>
But when I typed <Leader>n in python file, jedi#usages() command was executed.
:map <Leader>n returns:
n <Space>n *#:call jedi#usages()<CR>
n <Space>n * <C-W><C-W>
I also tried to unmap <Leader>n before I defined the map. However, it raised an error saying nothing was defined.
How to avoid this conflict?
I know the problem will be fixed when I define g:jedi#usages_command to another command. I'd like to know the way to avoid overlapping mapping.

I know the problem will be fixed when I define g:jedi#usages_command to another command. I'd like to know the way to avoid overlapping mapping.
Defining g:jedi#usages_command is "the way to avoid overlapping mapping".
Plugin mappings always take precedence over yours because they define their mappings after you have defined yours.
There are solutions at the script level, like using <unique>, or checking if the mapping already exists, or simply not defining any user-level mapping… but that's the responsibility of the developer, not yours.
--- edit ---
To expand on Christian's comment… the last mapping always wins, that's how it works and nothing can be done by the user to protect his mappings.
Plugin developers, though, have a few mechanisms at their disposal for preventing their plugins to overwrite user mappings and user settings so it is not unreasonable to expect them to use those mechanisms to respect your mappings.

Related

Conflict between remaps using plugins

I am currently using the NERD commenter plugin to define certain mappings that allow me to comment/uncomment blocks of code. One of the default mappings is:
[count]<leader>c<space> Toggles the comment state of the selected line(s). If the topmost selected line is commented, all selected lines are uncommented and vice versa.(NERDCommenterToggle)
I have remapped this options using nmap <C-_> <plug>NERDCommenterToggle and vmap <C-_> <plug>NERDCommenterToggle
My intention is to toggle between commented and uncommented in normal and visual mode using <C-_>.
The conflict arises because I have set the spacebar as my leader key and I have also set it up as a remap for folding: nnoremap <space> za.
When I put all of this together on my .vimrc pressing <C-_> folds the part of the document if it is "foldable", otherwise it toggles the comments.
The only reason that I can think of for this to happen is that, behind the scenes, <C-_> is still calling the default mapping of the plugin, which, because it contains the leader key, which is mapped to the spacebar is folding the code.
I am not that deep into vimscript, so I don't know if this is the intended behavior but it seems to me very weird that even though I have remapped the NERDCommenterToggle command, it still calls the default map. I was under the impression that the <plug> handles were used to avoid this kind of problems.
If this is indeed the intended behavior, is there a way to create a map to NERDCommenterToggle without it conflicting with the original mapping?
EDIT:
I removed the mapping of my leader key to space and the problem persists, which doesn't make any sense to me. Basically now I have the maps:
nmap <C-_> <plug>NERDCommenterToggle
nnoremap <space> za
and for some reason they interfere with each other and pressing "control + /" (<C-_>) triggers the folding maps.
Background
The whole point of <Plug> mappings is for plugin developers to provide a clean way for end users to make their own mappings without calling internal functions and such. Some of the benefits of that interface are:
ease of use for the end user,
possibility of changing the implementation without impacting the end user,
simplification of the documentation,
collision prevention,
etc.
Ideally, plugin developers should only expose <Plug> mappings, if only to prevent collision with other mappings, from other third-party plugins or by the end user. But that is entirely left to the developper: in no way does the use of a <Plug> mapping by the end user prevents the plugin developer from creating their own default mappings.
The problem
In this specific case, the author chose to create default mappings out of the box (g:NERDCreateDefaultMappings is set to 1) as well as their <Plug> equivalents. This leaves you with two mappings for the same feature (more, actually, because of modes, but let's keep it simple):
nnoremap <Plug>NERDCommenterToggle :call nerdcommenter#Comment("nx", "Toggle")'
nmap <Leader>c<Space> <Plug>NERDCommenterToggle
To which you add a third one:
nmap <C-_> <plug>NERDCommenterToggle
Since the default <Leader>c<Space> mapping is still there and your leader is <Space>, you are bound to find conflicts.
Plan A
Disable the plugin's ability to define default mappings with:
let g:NERDCreateDefaultMappings = 0
as per :help NERDCreateDefaultMappings. This puts you in control so you are free to build whatever mapping you need from the provided <Plug> mappings without the default mappings getting in the way.
Plan B
Note that it is also technically possible to "unmap" that pesky <Leader>c<Space> mapping with:
nunmap <Leader>c<Space>
But the plugin defines its default mappings after your vimrc is sourced so you can't simply add the line above to your vimrc as it will a) throw an error because the targeted mapping doesn't exist at that time, and b) not do anything useful anyway. Using that method efficiently opens quite the can of worms so I recommend plan A.

How to figure out key map redefined in vim plugin?

I installed many plugins by vundle.
I found there maybe multiple plugins use the same hotkey.
Is there smart way to figure out which plugin contains such hotkey?
There are some tutorial about key map. But I still haven't any idea.
A warning
Don't just install many plugins; you'll end up with a complex, slow, and indecipherable mess over time. Especially with plugin managers like Vundle, it's very easy to check out plugins. That benefit can turn bad if you forget to remove plugins that don't turn out to be useful for you.
How to check
In general, the plugin should advertise its features and defaults mappings (and hopefully provides configuration to change those!)
If you indeed have overlapping mappings, you should check:
The plugin's documentation.
The plugin's source code; look for :*[nore]map commands in the plugin/pluginname.vim script.
The actual existing mappings; the :map command lists those. You can restrict the command by modes (e.g. :imap for insert mode mappings) and starting keys (e.g. :map <Leader> lists all mappings that begin with the (configurable) Leader key).
How to change mappings
The canonical way to change plugin mappings is by defining your own mapping to <Plug>... targets that the plugin provides, e.g. :nmap <F1> <Plug>PluginNameMapping, in your ~/.vimrc. Some plugins also use global variables; refrain from modifying the plugin script itself; rather, complain to its author!
Yes, there is.
Use :verbose map <YOURKEY>. It will show you which file was the latest to modify this mapping.
You can always try reading the plugins documentation or source... Till then:
:map <YOURKEY><CR>
will show what was <YOURKEY> mapped to (in normal mode, so you can try it with :cmap, :vmap, etc.). Sometimes it helps if it's mapped to a function which relates to the plugins' name.
And you can issue a single (c|v...) :map to dump the mapping table.
But assuming you might want to know about mapping which used in two (or more plugins), there is no easy way for that. Again, look at the plugins' documentation and/or source code.

How to manage the vim Mappings

How to manage Vim Mappings, since each plugins (Pathogen is a great tool used to manage to manage Vim plugins) come with its own mappings. Collisions occur regularly.
Each plugin should come with a description (ideally accessible via the built-in :help) that includes the commands and mappings it defines. You need to read that anyway, in order to find out about the new functionality. You should also remember if one of the plugin's mappings clashes with an existing mapping of yours. :verbose map ... is a simple and great way to investigate your existing mappings.
In case of clashes, plugins using :map <unique> will fail noticeably, but most plugins will just silently overwrite a taken mapping. To fix that, a plugin should define <Plug>... mappings (see :help using-<Plug>; if it doesn't, complain to the author), which allow you to redefine the mappings (according to your tastes or to avoid a clash) in your ~/.vimrc. For example:
:nmap <C-o> <Plug>EnhancedJumpsOlder
The same can also be used to disable a mapping altogether:
:nmap <Plug>DisableEnhancedJumpsNewer <Plug>EnhancedJumpsNewer
Unless you have a lot of custom mappings (e.g. to emulate a different editor's feel in Vim, which you shouldn't do), or you're using lots of plugins, clashes should not be that frequent.

Can you have different localleaders for different Vim plugins?

I started using a plugin that conflicts with my existing maps, but instead of remapping all of it's maps, I just want to add a prefix. I thought I'd be able to do this with LocalLeader.
Vimdoc says:
<LocalLeader> is just like <Leader>, except that it uses
"maplocalleader" instead of "mapleader". <LocalLeader> is to be used
for mappings which are local to a buffer.
It seems that the only way to set localleader is to set a global variable (the docs don't mention this, but b:maplocalleader didn't work):
let maplocalleader = '\\'
And I don't see how I'd cleanly unset that variable (an autocmd that clears it after plugins are setup!?)
Is there a way to do this? Or is LocalLeader only to give one global prefix and one filetype-specific prefix?
Your last hunch is correct. If the plugin uses <Leader> (and it should unless it's a filetype plugin), there's no use in messing with maplocalleader.
Remapping is canonically done via <Plug> mappings, which the plugin hopefully offers. Some plugins do define a lot of similar mappings, some of those define a g:pluginname_mappingprefix (or so) variable to save you from having to remap all mappings individually. If your plugin doesn't, maybe write a suggestion / patch to the plugin author.
While #IngoKarkat solution is a prefered one, there is a hack which lets you do what you want: the SourcePre event:
autocmd SourcePre * :let maplocalleader='\\'
autocmd SourcePre plugin-name.vim :let maplocalleader='_'
. This works for <Leader> as well. There are lots of cases when this won’t work though. You can as well use SourceCmd for this job, using something like
function s:Source(newmll)
try
let oldmll=g:maplocalleader
let g:maplocalleader=a:newmll
source <amatch>
finally
let g:maplocalleader=oldmll
endtry
endfunction
let maplocalleader='\\'
autocmd SourceCmd plugin-name.vim :call s:Source('_')
in SourceCmd is the only way I see to restore maplocalleader after plugin was sourced, but SourceCmd event here won’t be launched for any file sourced inside plugin-name.vim. For some poorly written plugins (I mean, those that emit errors while sources) putting :source inside a :try block will break execution at the point where error occurs. Should not happen most of time though. You may also want to use */ftplugin/plugin-name.vim as a pattern instead of plugin-name.vim.

Vim custom keybinding conventions?

In Emacs, key sequences beginning with C-c are, by convention, reserved for individual users to set. I think there is at least one more convention, too.
What, if any, are Vim's conventions for custom key bindings?
You can use commands prefixed with your <leader> key as a convention to separate your own individual keymaps from default ones.
Set your <leader> key with a like this in your .vimrc file:
let mapleader = "_"
Then you can create key mappings that are prefixed with whatever you set your leader to like this:
nnoremap <leader><space> :noh<cr>
For more info see here
In Emacs, I would't say it was so much of a a convention, as much of a popular choice.
In Vim there is not even that, and although Ctrl+something or the F keys are popular, it is far from being a wide spread "convention".
A lot of Vim users just use the default "letter operations" in normal mode, with which they accomplish in text editing, what a majority of Emacs users must depend on functions.
There is a backslash which does nothing by default, only being the default value of mapping leader (both mapleader and maplocalleader). This leader is used in plugins and I strongly suggest to leave it for them only, using keys that have default actions attached, but that are not much useful. Common keys are , (repeats t/T/f/F motion in the opposite direction) and _ (moves one line downward, on the first non-blank character), you can also check which ones you don’t use (I, for example, don’t use + and -, latter is good replacement for _). The reasons why I unlike #stonesam92 suggest not to set mapleader to them and instead put your own leader in your mappings directly are the following:
It makes plugins possibly add mappings conflicting with your own ones.
You get used to typing ,a, _a or whatever, not to <Leader>a.
It makes mapping commands work differently depending on their location in the vimrc (<Leader> is computed only once, if you change mapleader afterwards already defined mappings won’t change).
It obfuscates the reading: you have to always remember, what <Leader> is.
If you are writing plugin, always use <Leader> and also leave the user the better way to customize them, two common solutions are using global options and using hasmapto:
" Global option
if !exists('g:plugin_mapping_key')
let g:plugin_mapping_key='<Leader>a'
endif
execute 'nnoremap '.g:plugin_mapping_key.' :DoSomething<CR>'
" hasmapto
nnoremap <Plug>PluginDoSomething :DoSomething<CR>
if !hasmapto('<Plug>PluginDoSomething', 'n', 0)
nmap <Leader>a <Plug>PluginDoSomething
endif

Resources