Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
78 changes: 78 additions & 0 deletions autoload/mergetool.vim
Original file line number Diff line number Diff line change
Expand Up @@ -52,8 +52,34 @@ function! mergetool#start() "{{{

call mergetool#prefer_revision(g:mergetool_prefer_revision)
call mergetool#set_layout(g:mergetool_layout)
call mergetool#bind_commands()
endfunction "}}}

function! mergetool#bind_commands()
command! -nargs=0 MergetoolStop call mergetool#stop()
command! -nargs=1 MergetoolSetLayout call mergetool#set_layout(<f-args>)
command! -nargs=1 MergetoolToggleLayout call mergetool#toggle_layout(<f-args>)
command! -nargs=0 MergetoolPreferLocal call mergetool#prefer_revision('local')
command! -nargs=0 MergetoolPreferRemote call mergetool#prefer_revision('remote')
doautocmd User MergetoolStart
endf

function! mergetool#unbind_commands()
delcommand MergetoolStop
delcommand MergetoolSetLayout
delcommand MergetoolToggleLayout
delcommand MergetoolPreferLocal
delcommand MergetoolPreferRemote
doautocmd User MergetoolStop
endf

" Dummy autocmds to prevent errors.
augroup mergetool_dummy
au!
autocmd User MergetoolStart let s:mergetool_dummy = 1
autocmd User MergetoolStop let s:mergetool_dummy = 0
augroup END

" Stop mergetool effect depends on:
" - when run as 'git mergetool'
" - when run from Vim directly on file with conflict markers
Expand Down Expand Up @@ -104,6 +130,7 @@ function! mergetool#stop() " {{{
endif

let g:mergetool_in_merge_mode = 0
call mergetool#unbind_commands()
tabclose
endif
endfunction " }}}
Expand Down Expand Up @@ -223,6 +250,57 @@ endfunction " }}}

" }}}

" Diff exchange {{{

" Do either diffget or diffput, depending on given direction
" and whether the window has adjacent window in a given direction
" h|<left> + window on right = diffget from right win
" h|<left> + no window on right = diffput to left win
" l|<right> + window on left = diffget from left win
" l|<right> + no window on left = diffput to right win
" Same logic applies for vertical directions: 'j' and 'k'

let s:directions = {
\ 'h': 'l',
\ 'l': 'h',
\ 'j': 'k',
\ 'k': 'j' }

function mergetool#DiffExchange(dir)
let oppdir = s:directions[a:dir]

let winoppdir = s:FindWindowOnDir(oppdir)
if (winoppdir != -1)
execute "diffget " . winbufnr(winoppdir)
else
let windir = s:FindWindowOnDir(a:dir)
if (windir != -1)
execute "diffput " . winbufnr(windir)
else
echohl WarningMsg
echo 'Cannot exchange diff. Found only single window'
echohl None
endif
endif
endfunction

" Finds window in given direction and returns it win number
" If no window found, returns -1
function s:FindWindowOnDir(dir)
let oldwin = winnr()

execute "noautocmd wincmd " . a:dir
let curwin = winnr()
if (oldwin != curwin)
noautocmd wincmd p
return curwin
else
return -1
endif
endfunction

" }}}

" Private functions{{{

let s:markers = {
Expand Down
73 changes: 12 additions & 61 deletions plugin/mergetool.vim
Original file line number Diff line number Diff line change
Expand Up @@ -7,74 +7,25 @@ let g:loaded_mergetool = 1

let g:mergetool_in_merge_mode = 0

" Commands and <plug> mappings for mergetool state. Additional commands
" available during merging.
command! -nargs=0 MergetoolStart call mergetool#start()
command! -nargs=0 MergetoolStop call mergetool#stop()
command! -nargs=0 MergetoolToggle call mergetool#toggle()
command! -nargs=1 MergetoolSetLayout call mergetool#set_layout(<f-args>)
command! -nargs=1 MergetoolToggleLayout call mergetool#toggle_layout(<f-args>)
command! -nargs=0 MergetoolPreferLocal call mergetool#prefer_revision('local')
command! -nargs=0 MergetoolPreferRemote call mergetool#prefer_revision('remote')

nnoremap <silent> <Plug>(MergetoolToggle) :<C-u>call mergetool#toggle()<CR>

" {{{ Diff exchange

" Do either diffget or diffput, depending on given direction
" and whether the window has adjacent window in a given direction
" h|<left> + window on right = diffget from right win
" h|<left> + no window on right = diffput to left win
" l|<right> + window on left = diffget from left win
" l|<right> + no window on left = diffput to right win
" Same logic applies for vertical directions: 'j' and 'k'

let s:directions = {
\ 'h': 'l',
\ 'l': 'h',
\ 'j': 'k',
\ 'k': 'j' }
" Commands and <plug> mappings for diff exchange commands. These can be used
" outside of merging (in any diff windows).
command! -nargs=0 MergetoolDiffExchangeLeft call mergetool#DiffExchange('h')
command! -nargs=0 MergetoolDiffExchangeRight call mergetool#DiffExchange('l')
command! -nargs=0 MergetoolDiffExchangeDown call mergetool#DiffExchange('j')
command! -nargs=0 MergetoolDiffExchangeUp call mergetool#DiffExchange('k')

function s:DiffExchange(dir)
let oppdir = s:directions[a:dir]

let winoppdir = s:FindWindowOnDir(oppdir)
if (winoppdir != -1)
execute "diffget " . winbufnr(winoppdir)
else
let windir = s:FindWindowOnDir(a:dir)
if (windir != -1)
execute "diffput " . winbufnr(windir)
else
echohl WarningMsg
echo 'Cannot exchange diff. Found only single window'
echohl None
endif
endif
endfunction

" Finds window in given direction and returns it win number
" If no window found, returns -1
function s:FindWindowOnDir(dir)
let oldwin = winnr()

execute "noautocmd wincmd " . a:dir
let curwin = winnr()
if (oldwin != curwin)
noautocmd wincmd p
return curwin
else
return -1
endif
endfunction

" Commands and <plug> mappings for diff exchange commands
command! -nargs=0 MergetoolDiffExchangeLeft call s:DiffExchange('h')
command! -nargs=0 MergetoolDiffExchangeRight call s:DiffExchange('l')
command! -nargs=0 MergetoolDiffExchangeDown call s:DiffExchange('j')
command! -nargs=0 MergetoolDiffExchangeUp call s:DiffExchange('k')

nnoremap <silent> <Plug>(MergetoolDiffExchangeLeft) :<C-u>call <SID>DiffExchange('h')<CR>
nnoremap <silent> <Plug>(MergetoolDiffExchangeRight) :<C-u>call <SID>DiffExchange('l')<CR>
nnoremap <silent> <Plug>(MergetoolDiffExchangeDown) :<C-u>call <SID>DiffExchange('j')<CR>
nnoremap <silent> <Plug>(MergetoolDiffExchangeUp) :<C-u>call <SID>DiffExchange('k')<CR>
nnoremap <silent> <Plug>(MergetoolDiffExchangeLeft) :<C-u>call mergetool#DiffExchange('h')<CR>
nnoremap <silent> <Plug>(MergetoolDiffExchangeRight) :<C-u>call mergetool#DiffExchange('l')<CR>
nnoremap <silent> <Plug>(MergetoolDiffExchangeDown) :<C-u>call mergetool#DiffExchange('j')<CR>
nnoremap <silent> <Plug>(MergetoolDiffExchangeUp) :<C-u>call mergetool#DiffExchange('k')<CR>

" }}}
12 changes: 12 additions & 0 deletions readme.md
Original file line number Diff line number Diff line change
Expand Up @@ -383,6 +383,18 @@ let g:airline_section_z = airline#section#create(['_diffmerge', ...other_parts])

![Status line indicator](./screenshots/airline_merge_indicator.png)


You can run vimscript when mergemode begins and ends:

```vim
augroup your_mergetool
au!
autocmd User MergetoolStart set nospell
autocmd User MergetoolStop set spell
augroup END
```


### Quitting merge mode

When exiting merge mode, `vim-mergetool` would prompt you whether merge was successful. If not, it will rollback changes to the buffer, will not save `MERGED` file to disk, and exit with non-zero code, when running as a `git mergetool`.
Expand Down