Search code examples
gitvimkey-bindingsvimdiff

Defining a shortcut only in vimdiff


I have been using vimdiff in its vimdiff1 layout, where it opens side by side the two buffer of LOCAL and REMOTE. The reason I preferred this layout over the other standard layout is the two shortcuts do and dp for getting and putting diff chuncks respectively.

------------------------------------------
|                   |                    |
|                   |                    |
|                   |                    |
|     LOCAL         |    REMOTE          |
|                   |                    |
|                   |                    |
|                   |                    |
------------------------------------------

Yet, recently I came across the scenario in which I often had do take a mixture of the two chuncks, for which manual editing to the MERGED file has been easier.

Now, I would like to switch to a LOCAL,MERGED,REMOTE layout, and I was wondering if it's possible to define custom keybinding only for vimdiff. Namely, I'd like to define two gl and gr shorcuts for :diffget LOCAL and :diffget REMOTE.

------------------------------------------
|             |           |              |
|             |           |              |
|   LOCAL     |   MERGED  |   REMOTE     |
|             |           |              |
|             |           |              |
------------------------------------------

Is there a way to define a keybinding only for the vimdiff 'mode'? Or alternatively, are there already standands keybindings which I'm not aware of? For reference: https://git-scm.com/docs/vimdiff/en

Of course, I could set these to be global keybindings with:

noremap gl :diffget LOCAL<CR>
noremap gr :diffget REMOTE<CR>

But this would apply them globally to the normal mode.


Solution

  • But this would apply them globally to the normal mode.

    • gl does nothing in normal mode by default and gr is a very niche command that you have probably never used or heard of, so they are quite safe to map globally.
    • Since those mappings are meant for a specific context, you wouldn't accidentally use them outside of that context anyway.

    So I think you can safely add them to your vimrc, but with a slight modification:

    nnoremap gl :diffget LOCAL<CR>
    nnoremap gr :diffget REMOTE<CR>
    

    :noremap creates a non-recursive mapping for normal mode, visual mode, and operator-pending mode, which is not exactly a good idea if that scenario is not handled properly (it's only useful for custom motions). :nnoremap restricts your mappings to normal mode, which is more in line with what you are trying to do.

    That said, if you really want to have those mappings only for diffs, it could be done with a :help <expr> mapping, like this:

    nnoremap <expr> gl &diff ? ':diffget LOCAL<CR>' : 'gl'
    nnoremap <expr> gr &diff ? ':diffget REMOTE<CR>' : 'gr'
    

    where the mapping is kept global but its right-hand side is evaluated at runtime, yielding different macros in different contexts. Here, the check is done on the :help 'diff' option: if it is enabled, then gl does :diffget LOCAL<CR>, if it is not, then gl does gl.