I have tried to attach to following fugitive mapping:

nnoremap <buffer> <silent> D :<C-U>execute <SID>StageDiff('Gdiff')<CR>

a :h window-move-cursor mapping:

diff --git a/plugin/fugitive.vim b/plugin/fugitive.vim
index 805518a..897295a 100644
--- a/plugin/fugitive.vim
+++ b/plugin/fugitive.vim
@@ -2552,8 +2552,8 @@ function! s:BufReadIndex() abort
     nnoremap <buffer> <silent> cc :<C-U>Gcommit<CR>
     nnoremap <buffer> <silent> cva :<C-U>Gcommit --amend --verbose<CR>
     nnoremap <buffer> <silent> cvc :<C-U>Gcommit --verbose<CR>
-    nnoremap <buffer> <silent> D :<C-U>execute <SID>StageDiff('Gdiff')<CR>
-    nnoremap <buffer> <silent> dd :<C-U>execute <SID>StageDiff('Gdiff')<CR>
+    nnoremap <buffer> <silent> D :<C-U>execute <SID>StageDiff('Gdiff')<Bar>exe "normal \<C-w>P"<CR>
+    nnoremap <buffer> <silent> dd :<C-U>execute <SID>StageDiff('Gdiff')<Bar>exe "normal \<C-w>P"<CR>
     nnoremap <buffer> <silent> dh :<C-U>execute <SID>StageDiff('Gsdiff')<CR>
     nnoremap <buffer> <silent> ds :<C-U>execute <SID>StageDiff('Gsdiff')<CR>
     nnoremap <buffer> <silent> dp :<C-U>execute <SID>StageDiffEdit()<CR>

However, it does not work.

Note, the :h fugitive-:Gstatus window is a preview window which is supposed to be unique.

Related issues on github are

  • I don't know if it will help, but I think you should protect <C-w> with the keycode <lt>. So your 2nd mapping could be: nnoremap <buffer> <silent> D :<C-U>exe <SID>StageDiff('Gdiff')<Bar>exe "normal! \<lt>C-w>P"<CR> Otherwise <C-w> will be translated into a literal ^W which on the command-line deletes the previous word. Jul 5 '16 at 9:24
  • Thanks for your suggestion. However, it does not help. I think the backslash does already protect the <C-w> key sequence.
    – Hotschke
    Jul 5 '16 at 9:59

Here is what I came up with to put in your ~/.vimrc:

augroup vimrc_fugitive_status
  autocmd BufEnter index if get(b:, 'fugitive_type') == 'index' | call <SID>fugitive_status_mappings() | endif
augroup END

function! s:fugitive_status_mappings()
  if get(b:, 'status_mappings', 0) == 0
    call s:map_with_preview('dd', 'n')
    call s:map_with_preview('D', 'n')
  let b:status_mappings = 1

function! s:map_with_preview(map, mode)
  call s:update_maping(a:map, a:mode, 'v:val . ":call <SID>focus_preview()\<cr>"') 

function! s:focus_preview()
  call feedkeys("\<c-w>P")

function! s:update_maping(map, mode, expr)
  let map = maparg(a:map, a:mode, 0, 1)
  execute a:mode .
        \ (map.noremap ? 'noremap ' : 'map ') .
        \ (map.buffer ? '<buffer> ' : '') .
        \ (map.silent ? '<silent> ' : '') .
        \ (map.expr ? '<expr> ' : '') .
        \ (map.nowait ? '<nowait> ' : '') .
        \ map.lhs . ' ' .
        \ map([substitute(map.rhs, '<SID>', '<SNR>' . map.sid. '_', 'g')], a:expr)[0]

The basic idea is to capture the old mapping with maparg() and then issue <c-w>P with feedkeys() after executing the old mapping.

This is a non-trivial solution due to the following issues:

  • Fugitive does not supply <Plug> mappings for the status window mappings so we must use maparg()
  • Due to the way the autocmd's fire we must use an event like BufEnter in lieu of the FileType event
  • feedkeys() is tricky inside mappings due to proper escaping so use function call instead

There may very well be a more concise and/or better solution to altering :Gstatus mappings, but I am unsure how to properly do so.

To add more mappings simply add more lines like so to s:fugitve_status_mappings function:

call s:map_with_preview('ds', 'n')
  • Thank you very much. However, I wouldn't mind to modify fugitive itself.
    – Hotschke
    Jul 6 '16 at 8:10
  • For some reason, it does not work for dp. I have added this as you have suggested. Any idea why this is different to dd/D? I just noticed your solution does not work for all mappings reliable. There is something different to you.
    – Hotschke
    Jul 6 '16 at 15:47
  • Are you aware that fugitive already defines an augroup with the same name as you have picked: augroup fugitive_status. Fugitives and your augroup follow the common pattern to delete all autocmds of this group with autocmd!. I could resolve my issue by renaming your augroup to augroup fugitive_status_update_mappings.
    – Hotschke
    Jul 7 '16 at 10:16
  • No, it still does not work reliable. Using dd, dp and dd in a row will make the cursor to jump to the first window not remaining in the preview window of :Gstatus. Can you reproduce this?
    – Hotschke
    Jul 7 '16 at 10:27
  • I was not aware that fugitive uses that autogroup name. Please change it. You can certainly modify fugitive itself. However you will probably have to rebase your changes after you update fugitive. e.g. git pull --rebase. As for the mappings not being reliable I assume there is some race condition with how feedkeys() is being used by fugitive. Normally I avoid using feedkeys() except as a last resort due its tricky nature. Jul 7 '16 at 16:28

Based on the answer by Peter Rincker.

Using feedkeys works in contrast to attaching the mapping \<C-w>P via <Bar> normal.

Problem with the answer by Peter Rincker:
Fugitive defines mappings on the fly based on different events which override occasionally the mappings set up by the event BufEnter. I couldn't figure out which events I would have to add to Peter Rinckers answer to retain the extended mappings.

A simple way to circumvent this problem is to directly modify the mappings in fugitive:

$ git diff
diff --git a/plugin/fugitive.vim b/plugin/fugitive.vim
index 805518a..f0120f8 100644
--- a/plugin/fugitive.vim
+++ b/plugin/fugitive.vim
@@ -14,6 +14,10 @@ endif

 " Section: Utility

+function! s:focus_preview()
+  call feedkeys("\<c-w>P")
 function! s:function(name) abort
   return function(substitute(a:name,'^s:',matchstr(expand('<sfile>'), '<SNR>\d\+_'),''))
@@ -2552,12 +2556,12 @@ function! s:BufReadIndex() abort
     nnoremap <buffer> <silent> cc :<C-U>Gcommit<CR>
     nnoremap <buffer> <silent> cva :<C-U>Gcommit --amend --verbose<CR>
     nnoremap <buffer> <silent> cvc :<C-U>Gcommit --verbose<CR>
-    nnoremap <buffer> <silent> D :<C-U>execute <SID>StageDiff('Gdiff')<CR>
-    nnoremap <buffer> <silent> dd :<C-U>execute <SID>StageDiff('Gdiff')<CR>
-    nnoremap <buffer> <silent> dh :<C-U>execute <SID>StageDiff('Gsdiff')<CR>
-    nnoremap <buffer> <silent> ds :<C-U>execute <SID>StageDiff('Gsdiff')<CR>
-    nnoremap <buffer> <silent> dp :<C-U>execute <SID>StageDiffEdit()<CR>
-    nnoremap <buffer> <silent> dv :<C-U>execute <SID>StageDiff('Gvdiff')<CR>
+    nnoremap <buffer> <silent> D :<C-U>execute <SID>StageDiff('Gdiff')<Bar>exe <SID>focus_preview()<CR>
+    nnoremap <buffer> <silent> dd :<C-U>execute <SID>StageDiff('Gdiff')<Bar>exe <SID>focus_preview()<CR>
+    nnoremap <buffer> <silent> dh :<C-U>execute <SID>StageDiff('Gsdiff')<Bar>exe <SID>focus_preview()<CR>
+    nnoremap <buffer> <silent> ds :<C-U>execute <SID>StageDiff('Gsdiff')<Bar>exe <SID>focus_preview()<CR>
+    nnoremap <buffer> <silent> dp :<C-U>execute <SID>StageDiffEdit()<Bar>exe <SID>focus_preview()<CR>
+    nnoremap <buffer> <silent> dv :<C-U>execute <SID>StageDiff('Gvdiff')<Bar>exe <SID>focus_preview()<CR>
     nnoremap <buffer> <silent> p :<C-U>execute <SID>StagePatch(line('.'),line('.')+v:count1-1)<CR>
     xnoremap <buffer> <silent> p :<C-U>execute <SID>StagePatch(line("'<"),line("'>"))<CR>
     nnoremap <buffer> <silent> P :<C-U>execute <SID>StagePatch(line('.'),line('.')+v:count1-1)<CR>

Of course, they will be overwritten if you pull in a new version of fugitive.

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.