directory diff plugin with split treeview, similar to BeyondCompare, fully async and low dependency
vim plugin to diff two directories like BeyondCompare by using diff
inspired by will133/vim-dirdiff
why another directory diff plugin?
sh
or diff
envvimdiff
if you like my work, check here for a list of my vim plugins, or buy me a coffee
requirement
job
install by vim-plug or any other plugin manager:
Plug 'ZSaberLv0/ZFVimDirDiff'
Plug 'ZSaberLv0/ZFVimJob' " required
Plug 'ZSaberLv0/ZFVimIgnore' " optional, but recommended for auto ignore setup
Plug 'ZSaberLv0/ZFVimBackup' " optional, but recommended for auto backup
use :ZFDirDiff
command to start diff
:ZFDirDiff pathA pathB
if path contains spaces:
:ZFDirDiff path\ A path\ B
:call ZFDirDiff("path A", "path B")
use :ZFDirDiffMark
to mark two directories to start diff
Open a file and :ZFDirDiffMark
and the containing directory will be stored as
a diff candidate. Then repeat with another file and you'll be asked to
diff the two.
:edit pathA/file.vim
:ZFDirDiffMark
:edit pathB/file.vim
:ZFDirDiffMark
Or integrate with your file manager. For vim-dirvish, add ~/.vim/ftplugin/dirvish.vim:
nnoremap <buffer> X :<C-u>ZFDirDiffMark <C-r><C-l><CR>
Or for netrw, add ~/.vim/ftplugin/netrw.vim:
nnoremap <buffer> X :<C-u>ZFDirDiffMark <C-r>=b:netrw_curdir<CR>/<C-r><C-l><CR>
Then X on two directories.
you can also start diff from scrooloose/nerdtree:
inside nerdtree window, press m
to popup menu,
press z
to choose mark to diff
,
and mark another node again to start diff
you may also use it as command line diff tool
vim -c 'call ZFDirDiff("path A", "path B")'
sh ZFDirDiff.sh "path A" "path B"
within the diff window:
DD
to update the diff result under cursoro
or <cr>
to diff current file, or fold/unfold current dirO
to unfold all contents under current dir,
x
to fold to parent, X
to fold to rootcd
to make current dir as diff root dir,
u
to go up for current side,
and U
to go up for both sideDM
to mark current file,
and DM
again on another file to diff these two files]c
or DJ
to move to next diff, [c
or DK
to prev diff,
use Dj
/ Dk
to move to next / prev diff filedo
or DH
to sync from another side to current side,
dp
or DL
to sync from current side to another sidea
to add new file or dirdd
to delete node under cursorDN
to mark mutiple files,
when done, use do/DH/dp/DL/dd
to sync or delete marked filesp
to copy the node's path, and P
for the node's full pathq
to exit diffwithin the file diff window:
:h diff
for more infoq
to quick file diff and back to owner diff windowthis plugin should work well without any extra config
for experienced user, here's some configs you may interest
let g:ZFDirDiff_autoBackup = 1
: whether perform auto backup, see https://github.com/ZSaberLv0/ZFVimBackup
let g:ZFDirDiff_ignoreEmptyDir = 1
: whether ignore empty dir
let g:ZFDirDiff_ignoreSpace = 0
: whether ignore empty lines and spaces (not supported for python backend)
let g:ZFIgnoreOption_ZFDirDiff = {...}
: ignore options, see https://github.com/ZSaberLv0/ZFVimIgnore
let g:ZFIgnoreOption_ZFDirDiff = {
\ 'bin' : 0,
\ 'media' : 0,
\ 'ZFDirDiff' : 1,
\ }
let g:ZFDirDiffKeymap_update = ['DU']
: update entire diff windowlet g:ZFDirDiffKeymap_updateParent = ['DD']
: update diff under cursorlet g:ZFDirDiffKeymap_open = ['<cr>', 'o']
: toggle dir open or open file difflet g:ZFDirDiffKeymap_foldOpenAll = []
: open all node under cursor, including same fileslet g:ZFDirDiffKeymap_foldOpenAllDiff = ['O']
: open all diff node under cursorlet g:ZFDirDiffKeymap_foldClose = ['x']
: close nodelet g:ZFDirDiffKeymap_foldCloseAll = ['X']
: close all nodelet g:ZFDirDiffKeymap_goParent = ['U']
: make both left and right diff window go to parent dirlet g:ZFDirDiffKeymap_diffThisDir = ['cd']
: change current side's root to node under cursorlet g:ZFDirDiffKeymap_diffParentDir = ['u']
: change current side's root to parentlet g:ZFDirDiffKeymap_markToDiff = ['DM']
: mark node under cursor, mark again to diff with two marked nodelet g:ZFDirDiffKeymap_markToSync = ['DN']
: mark one or more nodes, to sync mutiple nodes at oncelet g:ZFDirDiffKeymap_quit = ['q']
: quit difflet g:ZFDirDiffKeymap_diffNext = [']c', 'DJ']
: jump to next visible difflet g:ZFDirDiffKeymap_diffPrev = ['[c', 'DK']
: jump to prev visible difflet g:ZFDirDiffKeymap_diffNextFile = ['Dj']
: jump to next diff file, auto open closed dirlet g:ZFDirDiffKeymap_diffPrevFile = ['Dk']
: jump to prev diff file, auto open closed dirlet g:ZFDirDiffKeymap_syncToHere = ['do', 'DH']
: sync nodes from there to herelet g:ZFDirDiffKeymap_syncToThere = ['dp', 'DL']
: sync nodes from here to therelet g:ZFDirDiffKeymap_add = ['a']
: add new node, end with /
to add dirlet g:ZFDirDiffKeymap_delete = ['dd']
: delete selected nodeslet g:ZFDirDiffKeymap_getPath = ['p']
: get relative path of node under cursorlet g:ZFDirDiffKeymap_getFullPath = ['P']
: get absolute path of node under cursorlet g:ZFDirDiffKeymap_quitFileDiff = ['q']
: quit file diff, and go back to its owner diff windowlet g:ZFDirDiffUIChar_dir_prefix_closed = '+ '
let g:ZFDirDiffUIChar_dir_prefix_opened = '~ '
let g:ZFDirDiffUIChar_dir_postfix = '/'
let g:ZFDirDiffUIChar_file_prefix = ' '
let g:ZFDirDiffUIChar_file_postfix = ''
let g:ZFDirDiffUI_tabstop = 2
let g:ZFDirDiffUI_autoOpenSingleChildDir = 1
let g:ZFDirDiffUI_showSameDir = 1
let g:ZFDirDiffUI_showSameFile = 1
highlight default link ZFDirDiffHL_Header Title
highlight default link ZFDirDiffHL_Tail Title
highlight default link ZFDirDiffHL_DirChecking SpecialKey
highlight default link ZFDirDiffHL_DirSame Folded
highlight default link ZFDirDiffHL_DirDiff DiffAdd
highlight default link ZFDirDiffHL_FileChecking SpecialKey
highlight default link ZFDirDiffHL_FileSame Folded
highlight default link ZFDirDiffHL_FileDiff DiffText
highlight default link ZFDirDiffHL_DirOnlyHere DiffAdd
highlight default link ZFDirDiffHL_FileOnlyHere DiffAdd
highlight default link ZFDirDiffHL_ConflictDirHere ErrorMsg
highlight default link ZFDirDiffHL_ConflictDirThere WarningMsg
highlight default link ZFDirDiffHL_MarkToDiff Cursor
highlight default link ZFDirDiffHL_MarkToSync Cursor
Q: screen keeps blink when diff updating in background
A: unfortunately, I have no idea for how to solve this issue,
mainly because of matchadd()
must inside proper window,
causing frequent window switching