My idea is that whenever &diff is true for a buffer, I would like some mappings to be active when that buffer is the current buffer.

The following attempt works for when I open a session in diff mode via vimdiff, and almost works when I do diffthis from a non-diff session; I say almost because running :diffthis does not set the mappings because the BufEnter event is not triggered, so I have to jump away from that buffer and back to it to see the mappings activated.

How can I have the autocmd be executed even when :diffthis is executed and, in general, everytime &diff is/becomes true in the window where the cursor is?

function! Toggle_diffopts(which)
  exe 'set diffopt'
        \ . ['+','-'][!!(index(split(&diffopt,','), a:which) + 1)]
        \ . '='
        \ . a:which
function! SetDiffMappings()
  if &diff
    nnoremap <buffer> <silent> <Leader>diw :call Toggle_diffopts('iwhite')<CR>
    nnoremap <buffer> <silent> <Leader>dic :call Toggle_diffopts('icase')<CR>
    let b:diff_mappings = v:true
    if exists('b:diff_mappings') && b:diff_mappings
      nunmap <buffer> <Leader>diw
      nunmap <buffer> <Leader>dic
      let b:diff_mappings = v:false
augroup DiffMappings
  autocmd BufEnter * :call SetDiffMappings()
augroup end

This does not answer my question.

  • 3
    I haven't tested this myself... But will autocmd OptionSet diff call SetDiffMappings() work? It's supposed to trigger every time &diff is modified, so I guess it fits the bill? It might do by itself, or you might need to combine it with BufEnter or similar for when you already start a buffer in diff mode (or call vimdiff in the command line) in case it doesn't trigger in that specific case... I hope that helps! – filbranden Jan 29 at 22:17
  • 1
    @filbranden, I have the feeling that yours is the answer. I didn't know of the OptionSet event. However I'll check tomorrow, as now is time to sleep for me :P – Enlico Jan 29 at 22:25
  • 1
    @filbranden, OptionSet is not triggered when moving between windows, so I can't rely just on that, but adding the command you suggest beside the one I have already seems to work. Feel free to add an answer and I'll accept it. – Enlico Jan 30 at 8:11

You're doing it all wrong(tm). As mapping is buffer-local, while option is window-local (diff), you should create mapping once per buffer, and test the option value within the mapping (e.g. map-expression), not the other way round (but also try NOT to map dic/diw and other too common key combinations).

Next, your buffer-local mapping toggles global option (diffopt) - this is a very very bad design. Make sure you NEVER toggle global state due to buffer/window/tab switch. Always use global commands and mappings to change global settings.

On the contrary, creating plain global command has advantages. It's trivial to implement and easy to remember and to type due to auto-completion.

And finally, if you only need it from time to time then don't even bother writing a command. In real life typing :set dif<tab><right><right>...=<tab> is still much faster than musing about "if it's diw or what".

  • About paragraph 1 (mapping once per buffer test option within mapping vs the other way around): could you go a bit more in detail? Paragraph 2: since diffopt is indeed global, are you "simply" implying that I shouldn't use <buffer> in the mappings? Paragraph 3: wouldn't the usage of a global command mean that the mapping would be available even in windows where the diff is off? Paragraph 4: probably you're right. – Enlico Jan 31 at 20:55
  • @Enrico 1. Kind of nn <expr>x cond ? "x" : "y" See help for map-expression 2. Buffer-local mappings should change only buffer state, not global state. This is logical. 3. diffopt is global. Even if it's doing nothing in all other windows. – Matt Feb 1 at 5:45

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.