├── .gitignore ├── EnhancedDiff.vmb ├── Makefile ├── README.md ├── autoload └── EnhancedDiff.vim ├── default_diff.png ├── diff_ignore.png ├── doc └── EnhancedDiff.txt ├── histogram_diff.png ├── plugin └── EnhancedDiff.vim └── test ├── 1 ├── diff.txt ├── file1 ├── file2 └── normal_diff.ok ├── 2 ├── diff.txt ├── file1 ├── file2 └── normal_diff.ok ├── 3 ├── diff.txt ├── file1 ├── file2 └── normal_diff.ok ├── 4 ├── diff.txt ├── file1 ├── file2 └── normal_diff.ok ├── 5 ├── description.txt ├── diff.txt ├── file1 ├── file2 ├── normal_diff.ok └── vimrc ├── 6 ├── description.txt ├── diff.txt ├── file1 ├── file2 ├── normal_diff.ok └── vimrc ├── README.md └── test.sh /.gitignore: -------------------------------------------------------------------------------- 1 | post.pl 2 | vim_passfile 3 | .*.un~ 4 | .*.sw* 5 | # ignore vimballs 6 | *.vba 7 | *.vmb 8 | # ignore test files 9 | # test/1/EnhancedDiff_default.txt 10 | test/*/EnhancedDiff_*.txt 11 | # ignore *.orig files 12 | *.orig 13 | doc/tags 14 | -------------------------------------------------------------------------------- /EnhancedDiff.vmb: -------------------------------------------------------------------------------- 1 | " Vimball Archiver by Charles E. Campbell, Jr., Ph.D. 2 | UseVimball 3 | finish 4 | plugin/EnhancedDiff.vim [[[1 5 | 39 6 | " EnhancedDiff.vim - Enhanced Diff functions for Vim 7 | " ------------------------------------------------------------- 8 | " Version: 0.3 9 | " Maintainer: Christian Brabandt 10 | " Last Change: Thu, 05 Mar 2015 08:11:46 +0100 11 | " Script: http://www.vim.org/scripts/script.php?script_id=5121 12 | " Copyright: (c) 2009-2015 by Christian Brabandt 13 | " The VIM LICENSE applies to EnhancedDifff.vim 14 | " (see |copyright|) except use "EnhancedDiff.vim" 15 | " instead of "Vim". 16 | " No warranty, express or implied. 17 | " *** *** Use At-Your-Own-Risk! *** *** 18 | " GetLatestVimScripts: 5121 3 :AutoInstall: EnhancedDiff.vim 19 | " 20 | " Init: {{{1 21 | let s:cpo= &cpo 22 | if exists("g:loaded_enhanced_diff") || &cp 23 | finish 24 | elseif v:version < 704 25 | echohl WarningMsg 26 | echomsg "The EnhancedDiff Plugin needs at least a Vim version 7.4" 27 | echohl Normal 28 | endif 29 | set cpo&vim 30 | let g:loaded_enhanced_diff = 1 31 | 32 | " Functions {{{1 33 | function! s:CustomDiffAlgComplete(A,L,P) 34 | return "myers\nminimal\ndefault\npatience\nhistogram" 35 | endfu 36 | " public interface {{{1 37 | com! -nargs=1 -complete=custom,s:CustomDiffAlgComplete EnhancedDiff :let &diffexpr='EnhancedDiff#Diff("git diff", "--diff-algorithm=")'|:diffupdate 38 | com! PatienceDiff :EnhancedDiff patience 39 | com! EnhancedDiffDisable :set diffexpr= 40 | 41 | " Restore: "{{{1 42 | let &cpo=s:cpo 43 | unlet s:cpo 44 | " vim: ts=4 sts=4 sw=4 et fdm=marker com+=l\:\" 45 | autoload/EnhancedDiff.vim [[[1 46 | 167 47 | " EnhancedDiff.vim - Enhanced Diff functions for Vim 48 | " ------------------------------------------------------------- 49 | " Version: 0.3 50 | " Maintainer: Christian Brabandt 51 | " Last Change: Thu, 05 Mar 2015 08:11:46 +0100 52 | " Script: http://www.vim.org/scripts/script.php?script_id=5121 53 | " Copyright: (c) 2009-2015 by Christian Brabandt 54 | " The VIM LICENSE applies to EnhancedDifff.vim 55 | " (see |copyright|) except use "EnhancedDiff.vim" 56 | " instead of "Vim". 57 | " No warranty, express or implied. 58 | " *** *** Use At-Your-Own-Risk! *** *** 59 | " GetLatestVimScripts: 5121 3 :AutoInstall: EnhancedDiff.vim 60 | function! s:DiffInit(...) "{{{2 61 | let s:diffcmd=exists("a:1") ? a:1 : 'diff' 62 | let s:diffargs=[] 63 | let diffopt=split(&diffopt, ',') 64 | let special_args = {'icase': '-i', 'iwhite': '-b'} 65 | let git_default = get(g:, 'enhanced_diff_default_git', 66 | \ '--no-index --no-color --no-ext-diff') 67 | let diff_default = get(g:, 'enhanced_diff_default_diff', '--binary') 68 | let default_args = (exists("a:2") ? a:2 : ''). ' '. 69 | \ get(g:, 'enhanced_diff_default_args', '-U0') 70 | 71 | if !executable(split(s:diffcmd)[0]) 72 | throw "no executable" 73 | "else 74 | " Try to use git diff command, allows for more customizations 75 | "if split(s:diffcmd)[0] is# 'git' && !exists("s:git_version") 76 | " let s:git_version = substitute(split(system('git --version'))[-1], '\.', '', 'g') + 0 77 | "endif 78 | endif 79 | let s:diffargs += split(default_args) 80 | if exists("{s:diffcmd}_default") 81 | let s:diffargs += split({s:diffcmd}_default) 82 | endif 83 | 84 | for [i,j] in items(special_args) 85 | if match(diffopt, '\m\C'.i) > -1 86 | call add(s:diffargs, j) 87 | endif 88 | endfor 89 | 90 | " Add file arguments, should be last! 91 | call add(s:diffargs, s:ModifyPathAndCD(v:fname_in)) 92 | call add(s:diffargs, s:ModifyPathAndCD(v:fname_new)) 93 | " v:fname_out will be written later 94 | endfu 95 | function! s:Warn(msg) "{{{2 96 | echohl WarningMsg 97 | unsilent echomsg "EnhancedDiff: ". a:msg 98 | echohl Normal 99 | endfu 100 | function! s:ModifyPathAndCD(file) "{{{2 101 | if has("win32") || has("win64") 102 | " avoid a problem with Windows and cygwins path (issue #3) 103 | if a:file is# '-' 104 | " cd back into the previous directory 105 | cd - 106 | return 107 | endif 108 | let path = fnamemodify(a:file, ':p:h') 109 | if getcwd() isnot# path 110 | exe 'sil :cd' fnameescape(path) 111 | endif 112 | return fnameescape(fnamemodify(a:file, ':p:.')) 113 | endif 114 | return fnameescape(a:file) 115 | endfunction 116 | function! EnhancedDiff#ConvertToNormalDiff(list) "{{{2 117 | " Convert unified diff into normal diff 118 | let result=[] 119 | let start=1 120 | let hunk_start = '^@@ -\(\d\+\)\%(,\(\d\+\)\)\? +\(\d\+\)\%(,\(\d\+\)\)\? @@.*$' 121 | let last = '' 122 | for line in a:list 123 | if start && line !~# '^@@' 124 | continue 125 | else 126 | let start=0 127 | endif 128 | if line =~? '^+' 129 | if last is# 'old' 130 | call add(result, '---') 131 | let last='new' 132 | endif 133 | call add(result, substitute(line, '^+', '> ', '')) 134 | elseif line =~? '^-' 135 | let last='old' 136 | call add(result, substitute(line, '^-', '< ', '')) 137 | elseif line =~? '^ ' " skip context lines 138 | continue 139 | elseif line =~? hunk_start 140 | let list = matchlist(line, hunk_start) 141 | let old_start = list[1] + 0 142 | let old_len = list[2] + 0 143 | let new_start = list[3] + 0 144 | let new_len = list[4] + 0 145 | let action = 'c' 146 | let before_end= '' 147 | let after_end = '' 148 | let last = '' 149 | 150 | if list[2] is# '0' 151 | let action = 'a' 152 | elseif list[4] is# '0' 153 | let action = 'd' 154 | endif 155 | 156 | if (old_len) 157 | let before_end = printf(',%s', old_start + old_len - 1) 158 | endif 159 | if (new_len) 160 | let after_end = printf(',%s', new_start + new_len - 1) 161 | endif 162 | call add(result, old_start.before_end.action.new_start.after_end) 163 | endif 164 | endfor 165 | return result 166 | endfunction 167 | function! EnhancedDiff#Diff(...) "{{{2 168 | let cmd=(exists("a:1") ? a:1 : '') 169 | let arg=(exists("a:2") ? a:2 : '') 170 | try 171 | call s:DiffInit(cmd, arg) 172 | catch 173 | " no-op 174 | " error occured, reset diffexpr 175 | set diffexpr= 176 | call s:Warn(cmd. ' not found in path, aborting!') 177 | return 178 | endtry 179 | " systemlist() was introduced with 7.4.248 180 | if exists("*systemlist") 181 | let difflist=systemlist(s:diffcmd. ' '. join(s:diffargs, ' ')) 182 | else 183 | let difflist=split(system(s:diffcmd. ' '. join(s:diffargs, ' ')), "\n") 184 | endif 185 | call s:ModifyPathAndCD('-') 186 | if v:shell_error < 0 || v:shell_error > 1 187 | " An error occured 188 | set diffexpr= 189 | call s:Warn(cmd. ' Error executing "'. s:diffcmd. ' '.join(s:diffargs, ' ').'"') 190 | call s:Warn(difflist[0]) 191 | return 192 | endif 193 | " if unified diff... 194 | " do some processing here 195 | if !empty(difflist) && difflist[0] !~# '\m\C^\%(\d\+\)\%(,\d\+\)\?[acd]\%(\d\+\)\%(,\d\+\)\?' 196 | " transform into normal diff 197 | let difflist=EnhancedDiff#ConvertToNormalDiff(difflist) 198 | endif 199 | call writefile(difflist, v:fname_out) 200 | if get(g:, 'enhanced_diff_debug', 0) 201 | " This is needed for the tests. 202 | call writefile(difflist, 'EnhancedDiff_normal.txt') 203 | " Also write default diff 204 | let opt = "-a --binary " 205 | if &diffopt =~ "icase" 206 | let opt .= "-i " 207 | endif 208 | if &diffopt =~ "iwhite" 209 | let opt .= "-b " 210 | endif 211 | silent execute "!diff " . opt . v:fname_in . " " . v:fname_new . " > EnhancedDiff_default.txt" 212 | endif 213 | endfunction 214 | doc/EnhancedDiff.txt [[[1 215 | 214 216 | *EnhancedDiff.vim* Enhanced Diff functions for Vim 217 | 218 | Author: Christian Brabandt 219 | Version: 0.3 Thu, 05 Mar 2015 08:11:46 +0100 220 | Copyright: (©) 2015 by Christian Brabandt 221 | The VIM LICENSE (see |copyright|) applies to EnhancedDiffPlugin.vim 222 | except use EnhancedDiffPlugin instead of "Vim". 223 | NO WARRANTY, EXPRESS OR IMPLIED. USE AT-YOUR-OWN-RISK. 224 | 225 | ============================================================================ 226 | 1. Contents *EnhancedDiffPlugin* 227 | ============================================================================ 228 | 229 | 1. Contents.................................: |EnhancedDiffPlugin| 230 | 2. EnhancedDiff Manual......................: |EnhancedDiff-manual| 231 | 3. EnhancedDiff Configuration...............: |EnhancedDiff-config| 232 | 4. EnhancedDiff Feedback....................: |EnhancedDiff-feedback| 233 | 5. EnhancedDiff History.....................: |EnhancedDiff-history| 234 | 235 | ============================================================================ 236 | 2. EnhancedDiffPlugin Manual *EnhancedDiff-manual* 237 | ============================================================================ 238 | 239 | Functionality 240 | 241 | The EnhancedDiff plugin allows to use different diff algorithms. This can 242 | greatly improve the use of |vimdiff| by making a diff more readable. To make 243 | use of different diff algorithms, this plugin makes use of the git command 244 | line tool to generate a unified diff and converts that diff to a normal "ed" 245 | style diff (|diff-diffexpr|) to make vimdiff use that diff. 246 | 247 | You could also use other diff tools if you like, as long as those generate a 248 | diff in the "unified" form. 249 | 250 | By default is disabled, which means, it uses the default diff algorithm (also 251 | known as myers algorithm). 252 | *EnhancedDiff-algorithms* 253 | git supports 4 different diff algorithms. Those are: 254 | 255 | Algorithm Description~ 256 | myers Default diff algorithm 257 | default Alias for myers 258 | minimal Like myers, but tries harder to minimize the resulting 259 | diff 260 | patience Use the patience diff algorithm 261 | histogram Use the histogram diff algorithm (similar to patience but 262 | slightly faster) 263 | 264 | Note you need at least git version 1.8.2 or higher. Older versions do not 265 | support all those algorithms. 266 | 267 | *:EnhancedDiff* 268 | To specify a different diff algorithm use this command: > 269 | 270 | :EnhancedDiff 271 | < 272 | Use any of the above algorithm for creating the diffs. You can use to 273 | complete the different algorithms. 274 | 275 | *:PatienceDiff* 276 | Use the :PatienceDiff to select the "patience" diff algorithm. 277 | 278 | The selected diff algorithm will from then on be used for all the diffs that 279 | will be generated in the future. If you are in diff mode (|vimdiff|) the diff 280 | should be updated immediately. 281 | 282 | *:EnhancedDiffDisable* 283 | Use the :EnhancedDiffDisable command to disable this plugin. 284 | 285 | *EnhancedDiff-vimrc* 286 | If you want e.g. the patience diff algorithm to be the default when using the 287 | |vimdiff| command, you need to set the 'diffexpr' option manually like this 288 | in your |.vimrc| > 289 | 290 | :let &diffexpr='EnhancedDiff#Diff("git diff", "--diff-algorithm=patience")' 291 | < 292 | Since internally, EnhancedDiff does simply set up the 'diffexpr' option. 293 | 294 | An alternative to this method is the following: 295 | 296 | Create a file after/plugin/patiencediff.vim in your default runtimepath (e.g. 297 | ~/.vim/ directory on Linux, ~/vimfiles on Windows, creating missing directories, 298 | if they do not exist yet) and put into it the following: > 299 | 300 | " This can't go in .vimrc, because :PatienceDiff isn't available 301 | if !exists(":PatienceDiff") 302 | " This block is optional, but will protect you from errors if you 303 | " uninstall vim-diff-enhanced or share your config across machines 304 | finish 305 | endif 306 | PatienceDiff 307 | < 308 | 309 | ============================================================================== 310 | 3. EnhancedDiff configuration *EnhancedDiff-config* 311 | ============================================================================== 312 | 313 | You can tweak the arguments for the diff generating tools using the following 314 | variables: 315 | 316 | g:enhanced_diff_default_git 317 | --------------------------- 318 | Default command line arguments for git 319 | (Default: "--no-index --no-color --no-ext-diff") 320 | 321 | g:enhanced_diff_default_diff 322 | ---------------------------- 323 | Default command line arguments for diff 324 | (Default: "--binary") 325 | 326 | g:enhanced_diff_default_args 327 | ---------------------------- 328 | Default arguments for any diff command 329 | (Default: "-U0") 330 | 331 | g:enhanced_diff_default_ 332 | --------------------------------- 333 | Default command line argument for (e.g. use "hg" to specify special 334 | arguments and you want to use hg to generate the diff) 335 | (Default: unset) 336 | 337 | *EnhancedDiff-custom-cmd* 338 | 339 | Suppose you want to use a different command line tool to generate the diff. 340 | 341 | For example, let's say you want to use mercurial to generate your diffs. 342 | First define the g:enhanced_diff_default_hg variable and set it to 343 | include all required arguments: > 344 | 345 | :let g:enhanced_diff_default_hg = '-a' 346 | 347 | Then you define your custom command to make the next time diff mode is started 348 | make use of mercurial: > 349 | 350 | :com! HgDiff :let &diffexpr='EnhancedDiff#Diff("hg diff")' 351 | 352 | The first argument of the EnhancedDiff#Diff specifies the command to use to 353 | generate the diff. The optional second argument specifies an optional 354 | parameter that will be used in addition to the g:enhanced_diff_default_hg 355 | variable. In addition to the arguments from the g:enhanced_diff_default_hg 356 | variable, also the arguments from the g:enhanced_diff_default_args will be 357 | used (e.g. by default the -U0 to prevent generating context lines). 358 | 359 | Note: You need to make sure to generate either a normal style diff or a 360 | unified style diff. A unified diff will be converted to a normal style diff so 361 | that Vim can make use of that diff for its diff mode. 362 | 363 | *EnhancedDiff-convert-diffs* 364 | The EnhancedDiff plugin defines a public function 365 | (EnhancedDiff#ConvertToNormalDiff(arg) that can be used by any plugin to 366 | convert a diff in unified form to a diff that can be read by Vim. 367 | 368 | arg is a |List| containing the diff as returned by git diff. Use it 369 | like this: > 370 | 371 | let mydiff = systemlist('git diff ...') 372 | let difflist = EnhancedDiff#ConvertToNormalDiff(mydiff) 373 | < 374 | If your Vim doesn't have the systemlist() function, you can manully split the 375 | list like this: > 376 | 377 | let mydiff = split(system('git diff ...'), "\n") 378 | let difflist = EnhancedDiff#ConvertToNormalDiff(mydiff) 379 | 380 | Note: If you want to use the converted diff and feed it back to Vim for its 381 | diff mode, you need to write the list back to the file |v:fname_out| 382 | ============================================================================ 383 | 4. Plugin Feedback *EnhancedDiff-feedback* 384 | ============================================================================ 385 | 386 | Feedback is always welcome. If you like the plugin, please rate it at the 387 | vim-page: 388 | http://www.vim.org/scripts/script.php?script_id=5121 389 | 390 | You can also follow the development of the plugin at github: 391 | http://github.com/chrisbra/EnhancedDiff.vim 392 | 393 | Please don't hesitate to report any bugs to the maintainer, mentioned in the 394 | third line of this document. 395 | 396 | ============================================================================ 397 | 5. EnhancedDiff History *EnhancedDiff-history* 398 | ============================================================================ 399 | 400 | 0.4 (unreleased) "{{{1 401 | - documentation update 402 | - if |systemlist()| is not available, use |system()| function (issue 403 | https://github.com/chrisbra/vim-diff-enhanced/issues/2 reported by agude, 404 | thanks!) 405 | - cd into temporary directory before doing the diff (issue 406 | https://github.com/chrisbra/vim-diff-enhanced/issues/3 reported by idbrii, 407 | thanks!) 408 | - rename public commands to :EnhancedDiff prefix (issue 409 | https://github.com/chrisbra/vim-diff-enhanced/isseus/4 reported by justinmk, 410 | thanks!) 411 | 412 | 0.3: Mar 5th, 2014 "{{{1 413 | - update diff, when in diffmode and |:CustomDiff| is used 414 | - run test correctly, when installed via plugin manager (issue 415 | https://github.com/chrisbra/vim-diff-enhanced/issues/1, reported by 416 | advocateddrummer thanks!) 417 | - fix small typo (noticed by Gary Johnson, thanks!) 418 | 419 | 0.2: Feb 25, 2015 "{{{1 420 | 421 | - Updated documentation to link to the vim.org page 422 | 423 | 0.1: Feb 25, 2015 "{{{1 424 | 425 | - Internal version 426 | 427 | ============================================================================== 428 | Modeline: "{{{1 429 | vim:tw=78:ts=8:ft=help:et:fdm=marker:fdl=0:norl 430 | -------------------------------------------------------------------------------- /Makefile: -------------------------------------------------------------------------------- 1 | SCRIPT=$(wildcard plugin/*.vim) 2 | AUTOL =$(wildcard autoload/*.vim) 3 | DOC=$(wildcard doc/*.txt) 4 | PLUGIN=$(shell basename "$$PWD") 5 | VERSION=$(shell sed -n '/Version:/{s/^.*\(\S\.\S\+\)$$/\1/;p}' $(SCRIPT)) 6 | 7 | .PHONY: $(PLUGIN).vmb README test 8 | 9 | all: uninstall vimball install 10 | 11 | vimball: $(PLUGIN).vmb 12 | 13 | test: 14 | cd test && ./test.sh && find . -type f -name "EnhancedDiff_*.txt" -delete 15 | 16 | clean: 17 | find . -type f \( -name "*.vba" -o -name "*.orig" -o -name "*.~*" \ 18 | -o -name ".VimballRecord" -o -name ".*.un~" -o -name "*.sw*" -o \ 19 | -name tags -o -name "*.vmb" -o -name "EnhancedDiff_*.txt" \) -delete 20 | 21 | dist-clean: clean 22 | 23 | install: 24 | vim -N -i NONE -u NONE -c 'ru! plugin/vimballPlugin.vim' -c':so %' -c':q!' $(PLUGIN)-$(VERSION).vmb 25 | 26 | uninstall: 27 | vim -N -i NONE -u NONE -c 'ru! plugin/vimballPlugin.vim' -c':RmVimball' -c':q!' $(PLUGIN)-$(VERSION).vmb 28 | 29 | undo: 30 | for i in */*.orig; do mv -f "$$i" "$${i%.*}"; done 31 | 32 | README: 33 | cp -f $(DOC) README 34 | 35 | $(PLUGIN).vmb: 36 | rm -f $(PLUGIN)-$(VERSION).vmb 37 | vim -N -i NONE -u NONE -c 'ru! plugin/vimballPlugin.vim' -c ':call append("0", [ "$(SCRIPT)", "$(AUTOL)", "$(DOC)"])' -c '$$d' -c ":%MkVimball $(PLUGIN)-$(VERSION) ." -c':q!' 38 | ln -f $(PLUGIN)-$(VERSION).vmb $(PLUGIN).vmb 39 | 40 | release: version all README 41 | 42 | version: 43 | perl -i.orig -pne 'if (/Version:/) {s/\.(\d*)/sprintf(".%d", 1+$$1)/e}' ${SCRIPT} ${AUTOL} 44 | perl -i -pne 'if (/GetLatestVimScripts:/) {s/(\d+)\s+:AutoInstall:/sprintf("%d :AutoInstall:", 1+$$1)/e}' ${SCRIPT} ${AUTOL} 45 | #perl -i -pne 'if (/Last Change:/) {s/\d+\.\d+\.\d\+$$/sprintf("%s", `date -R`)/e}' ${SCRIPT} 46 | perl -i -pne 'if (/Last Change:/) {s/(:\s+).*\n/sprintf(": %s", `date -R`)/e}' ${SCRIPT} ${AUTOL} 47 | perl -i.orig -pne 'if (/Version:/) {s/\.(\d+).*\n/sprintf(".%d %s", 1+$$1, `date -R`)/e}' ${DOC} 48 | VERSION=$(shell sed -n '/Version:/{s/^.*\(\S\.\S\+\)$$/\1/;p}' $(SCRIPT)) 49 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # EnhancedDiff plugin [![Say Thanks!](https://img.shields.io/badge/Say%20Thanks-!-1EAEDB.svg)](https://saythanks.io/to/cb%40256bit.org) 2 | > A Vim plugin for creating better diffs (sometimes) 3 | 4 | This plugin allows you to make use of the Patience diff algorithm for 5 | generating diffs to use with Vim. This needs the git command line tool 6 | available. (But see [Update below][Update]) 7 | 8 | You can also customize your setup to use any other tool to generated diffs 9 | (e.g. mercurial) Read the help on how to configure the plugin accordingly. 10 | 11 | Here are some screenshots that visualize how the patience/histogram algorithm 12 | work. 13 | 14 | This is the default diff generated by Vim: 15 | ![Default diff](default_diff.png) 16 | 17 | Now change that to using the "histogram" algorithm by running `:EnhancedDiff histogram` 18 | If Vim is in diff mode, the diff will be updated to this: 19 | 20 | ![histogram diff](histogram_diff.png) 21 | 22 | Note, that the Patience algorithm might not always provide better diffs. But 23 | using this plugin you can at least easily switch between different diffs. 24 | 25 | ## Update 26 | Starting with Vim [8.1.0360][Vim_81360] Vim now comes bundled with the xdiff 27 | library and is able to handle diff internally without falling back to 28 | calling `diff` as external tool. 29 | 30 | This means, one can now simply set diffopt: 31 | 32 | if has("patch-8.1.0360") 33 | set diffopt+=internal,algorithm:patience 34 | endif 35 | 36 | and Vim will use the patience diff algorithm when creating a diff. 37 | 38 | In addition, Vim can now parse context diffs (currently with only zero 39 | context lines) from a diff tool when using diff as external tool. So a 40 | translation to an ed-like diff is not needed anymore. 41 | 42 | So in essence, starting with that Vim version, you don't need to use this 43 | plugin anymore. 44 | 45 | # Ignoring parts of a file 46 | 47 | Using the command `:EnhancedDiffIgnorePat pat` you can define patterns, that 48 | will be ignored before feeding the buffer contents to the diff program. 49 | Internally this will be handled by substituting those matches with 'XX' 50 | so that the content will look like the same for the diff binary. 51 | 52 | This is how it looks like with a pattern of `^[^;]\+;` and `;[^;]\+$` 53 | ![diff_ignore](diff_ignore.png) 54 | 55 | ### Installation 56 | Use the plugin manager of your choice: 57 | 58 | * [Pathogen][pathogen] 59 | * `git clone https://github.com/chrisbra/vim-diff-enhanced.git ~/.vim/bundle/vim-enhanced-diff` 60 | * `:Helptags` (only needed once after the installation to install the documentation) 61 | * [NeoBundle][neobundle] 62 | * `NeoBundle 'chrisbra/vim-diff-enhanced'` 63 | * [Vundle][vundle] 64 | * `Plugin 'chrisbra/vim-diff-enhanced'` 65 | * [Vim-Plug][vim-plug] 66 | * `Plug 'chrisbra/vim-diff-enhanced'` 67 | 68 | Alternatively download the [stable][] version of the plugin, edit it with Vim (`vim EnhancedDiff-XXX.vmb`) and simply source it (`:so %`). Restart and take a look at the help (`:h EnhancedDiff.txt`) 69 | 70 | [stable]: http://www.vim.org/scripts/script.php?script_id=5121 71 | 72 | ### Usage 73 | Once installed, take a look at the help at `:h EnhancedDiff` 74 | 75 | Here is a short overview of the functionality provided by the plugin: 76 | #### Ex commands: 77 | `:PatienceDiff` - Use the Patience Diff algorithm for the next diff mode 78 | 79 | `:EnhancedDiff ` - Use <algorithm> to generate the diff. 80 | Use any of 81 | * myers Default Diff algorithm used 82 | * default Alias for myers algorithm 83 | * histogram Fast version of patience algorithm 84 | * minimal Default diff algorithm, trying harder to minimize the diff 85 | * patience Patience diff algorithm. 86 | 87 | Note: Those 2 commands use the git command line tool internally to generate the 88 | diffs. Make sure you have at least git version 1.8.2 installed. 89 | 90 | `:EnhancedDiffDisable` - Disable plugin (and use default Vim diff capabilities). 91 | 92 | ### FAQ 93 | 94 | #### How can I enable the patience diff algorithm when starting as vimdiff / git difftool / ... ? 95 | In that case, add this snippet to your .vimrc: 96 | ```viml 97 | " started In Diff-Mode set diffexpr (plugin not loaded yet) 98 | if &diff 99 | let &diffexpr='EnhancedDiff#Diff("git diff", "--diff-algorithm=patience")' 100 | endif 101 | ``` 102 | ### License & Copyright 103 | 104 | © 2015 by Christian Brabandt. The Vim License applies. See `:h license` 105 | 106 | __NO WARRANTY, EXPRESS OR IMPLIED. USE AT-YOUR-OWN-RISK__ 107 | 108 | [pathogen]: https://github.com/tpope/vim-pathogen 109 | [neobundle]: https://github.com/Shougo/neobundle.vim 110 | [vundle]: https://github.com/gmarik/vundle 111 | [vim-plug]: https://github.com/junegunn/vim-plug 112 | [Vim_81360]: https://github.com/vim/vim/releases/tag/v8.1.0360 113 | [Update]: https://github.com/chrisbra/vim-diff-enhanced/blob/master/README.md#update 114 | -------------------------------------------------------------------------------- /autoload/EnhancedDiff.vim: -------------------------------------------------------------------------------- 1 | " EnhancedDiff.vim - Enhanced Diff functions for Vim 2 | " ------------------------------------------------------------- 3 | " Version: 0.3 4 | " Maintainer: Christian Brabandt 5 | " Last Change: Thu, 05 Mar 2015 08:11:46 +0100 6 | " Script: http://www.vim.org/scripts/script.php?script_id=5121 7 | " Copyright: (c) 2009-2015 by Christian Brabandt 8 | " The VIM LICENSE applies to EnhancedDifff.vim 9 | " (see |copyright|) except use "EnhancedDiff.vim" 10 | " instead of "Vim". 11 | " No warranty, express or implied. 12 | " *** *** Use At-Your-Own-Risk! *** *** 13 | " GetLatestVimScripts: 5121 3 :AutoInstall: EnhancedDiff.vim 14 | function! s:DiffInit(...) "{{{2 15 | let s:diffcmd=exists("a:1") ? a:1 : 'diff' 16 | let s:diffargs=[] 17 | let diffopt=split(&diffopt, ',') 18 | let special_args = {'icase': '-i', 'iwhite': '-b'} 19 | let git_default = get(g:, 'enhanced_diff_default_git', 20 | \ '--no-index --no-color --no-ext-diff') 21 | let default_args = (exists("a:2") ? a:2 : ''). ' '. 22 | \ get(g:, 'enhanced_diff_default_args', '-U0') 23 | let diff_cmd = split(s:diffcmd)[0] 24 | if exists("g:enhanced_diff_default_{diff_cmd}") 25 | let {diff_cmd}_default = g:enhanced_diff_default_{diff_cmd} 26 | endif 27 | " need to get first word of the diff command 28 | 29 | if !executable(diff_cmd) 30 | throw "no executable" 31 | endif 32 | let s:diffargs += split(default_args) 33 | if exists("{diff_cmd}_default") 34 | let s:diffargs += split({diff_cmd}_default) 35 | endif 36 | 37 | for [i,j] in items(special_args) 38 | if match(diffopt, '\m\C'.i) > -1 39 | if diff_cmd is# 'git' && i is# 'icase' 40 | " git diff does not support -i option! 41 | call s:Warn("git does not support -i/icase option") 42 | continue 43 | endif 44 | call add(s:diffargs, j) 45 | endif 46 | endfor 47 | 48 | " Add file arguments, should be last! 49 | call add(s:diffargs, s:ModifyPathAndCD(v:fname_in)) 50 | call add(s:diffargs, s:ModifyPathAndCD(v:fname_new)) 51 | " v:fname_out will be written later 52 | endfu 53 | function! s:ModifyDiffFiles() "{{{2 54 | " replace provided pattern by 'XXX' so it will be ignored when diffing 55 | for expr in get(g:, 'enhanced_diff_ignore_pat', []) + get(b:, 'enhanced_diff_ignore_pat', []) 56 | if !exists("cnt1") 57 | let cnt1 = readfile(v:fname_in) 58 | let cnt2 = readfile(v:fname_new) 59 | endif 60 | " do not modify the test diff, that always comes 61 | " before the actual diff is evaluated 62 | if cnt1 ==# ['line1'] && cnt2 ==# ['line2'] 63 | return 64 | endif 65 | call map(cnt1, "substitute(v:val, expr[0], expr[1], 'g')") 66 | call map(cnt2, "substitute(v:val, expr[0], expr[1], 'g')") 67 | endfor 68 | if exists("cnt1") 69 | call writefile(cnt1, v:fname_in) 70 | call writefile(cnt2, v:fname_new) 71 | endif 72 | endfu 73 | function! s:Warn(msg) "{{{2 74 | echohl WarningMsg 75 | unsilent echomsg "EnhancedDiff: ". a:msg 76 | echohl Normal 77 | endfu 78 | function! s:ModifyPathAndCD(file) "{{{2 79 | if has("win32") || has("win64") 80 | " avoid a problem with Windows and cygwins path (issue #3) 81 | if a:file is# '-' 82 | " cd back into the previous directory 83 | cd - 84 | return 85 | endif 86 | let path = fnamemodify(a:file, ':p:h') 87 | if getcwd() isnot# path 88 | exe 'sil :cd' fnameescape(path) 89 | endif 90 | return fnameescape(fnamemodify(a:file, ':p:.')) 91 | endif 92 | return fnameescape(a:file) 93 | endfunction 94 | function! EnhancedDiff#ConvertToNormalDiff(list) "{{{2 95 | " Convert unified diff into normal diff 96 | let result=[] 97 | let start=1 98 | let hunk_start = '^@@ -\(\d\+\)\%(,\(\d\+\)\)\? +\(\d\+\)\%(,\(\d\+\)\)\? @@.*$' 99 | let last = '' 100 | for line in a:list 101 | if start && line !~# '^@@' 102 | continue 103 | else 104 | let start=0 105 | endif 106 | if line =~? '^+' 107 | if last is# 'old' 108 | call add(result, '---') 109 | let last='new' 110 | endif 111 | call add(result, substitute(line, '^+', '> ', '')) 112 | elseif line =~? '^-' 113 | let last='old' 114 | call add(result, substitute(line, '^-', '< ', '')) 115 | elseif line =~? '^ ' " skip context lines 116 | continue 117 | elseif line =~? hunk_start 118 | let list = matchlist(line, hunk_start) 119 | let old_start = list[1] + 0 120 | let old_len = list[2] + 0 121 | let new_start = list[3] + 0 122 | let new_len = list[4] + 0 123 | let action = 'c' 124 | let before_end= '' 125 | let after_end = '' 126 | let last = '' 127 | 128 | if list[2] is# '0' 129 | let action = 'a' 130 | elseif list[4] is# '0' 131 | let action = 'd' 132 | endif 133 | 134 | if (old_len) 135 | let before_end = printf(',%s', old_start + old_len - 1) 136 | endif 137 | if (new_len) 138 | let after_end = printf(',%s', new_start + new_len - 1) 139 | endif 140 | call add(result, old_start.before_end.action.new_start.after_end) 141 | endif 142 | endfor 143 | return result 144 | endfunction 145 | function! s:SysList(cmd) 146 | if exists('*systemlist') 147 | return systemlist(a:cmd) 148 | endif 149 | return split(system(a:cmd), '\n') 150 | endfunction 151 | function! EnhancedDiff#Diff(...) "{{{2 152 | let cmd=(exists("a:1") ? a:1 : '') 153 | let arg=(exists("a:2") ? a:2 : '') 154 | try 155 | call s:DiffInit(cmd, arg) 156 | catch 157 | " no-op 158 | " error occured, reset diffexpr 159 | set diffexpr= 160 | call s:Warn(cmd. ' not found in path, aborting!') 161 | return 162 | endtry 163 | call s:ModifyDiffFiles() 164 | if get(g:, 'enhanced_diff_debug', 0) 165 | sil echomsg "Executing diff command: ". s:diffcmd . ' '. join(s:diffargs, ' ') 166 | endif 167 | let difflist=s:SysList(s:diffcmd . ' ' . join(s:diffargs, ' ')) 168 | call s:ModifyPathAndCD('-') 169 | if v:shell_error < 0 || v:shell_error > 1 170 | " An error occured 171 | set diffexpr= 172 | call s:Warn(cmd. ' Error executing "'. s:diffcmd. ' '.join(s:diffargs, ' ').'"') 173 | call s:Warn(difflist[0]) 174 | return 175 | endif 176 | " if unified diff... 177 | " do some processing here 178 | if !empty(difflist) && difflist[0] !~# '\m\C^\%(\d\+\)\%(,\d\+\)\?[acd]\%(\d\+\)\%(,\d\+\)\?' 179 | " transform into normal diff 180 | let difflist=EnhancedDiff#ConvertToNormalDiff(difflist) 181 | endif 182 | call writefile(difflist, v:fname_out) 183 | if get(g:, 'enhanced_diff_debug', 0) 184 | " This is needed for the tests. 185 | call writefile(difflist, 'EnhancedDiff_normal.txt') 186 | " Also write default diff 187 | let opt = "-a --binary " 188 | if &diffopt =~ "icase" 189 | let opt .= "-i " 190 | endif 191 | if &diffopt =~ "iwhite" 192 | let opt .= "-b " 193 | endif 194 | silent execute "!diff " . opt . v:fname_in . " " . v:fname_new . " > EnhancedDiff_default.txt" 195 | redraw! 196 | endif 197 | endfunction 198 | " vim: ts=2 sts=-1 sw=0 et fdm=marker com+=l\:\" 199 | -------------------------------------------------------------------------------- /default_diff.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/chrisbra/vim-diff-enhanced/8d161f1e97a5f5e64ea4219e6663f98a109df7b1/default_diff.png -------------------------------------------------------------------------------- /diff_ignore.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/chrisbra/vim-diff-enhanced/8d161f1e97a5f5e64ea4219e6663f98a109df7b1/diff_ignore.png -------------------------------------------------------------------------------- /doc/EnhancedDiff.txt: -------------------------------------------------------------------------------- 1 | *EnhancedDiff.vim* Enhanced Diff functions for Vim 2 | 3 | Author: Christian Brabandt 4 | Version: 0.3 Thu, 05 Mar 2015 08:11:46 +0100 5 | Copyright: (©) 2015 by Christian Brabandt 6 | The VIM LICENSE (see |copyright|) applies to EnhancedDiffPlugin.vim 7 | except use EnhancedDiffPlugin instead of "Vim". 8 | NO WARRANTY, EXPRESS OR IMPLIED. USE AT-YOUR-OWN-RISK. 9 | 10 | ============================================================================ 11 | 1. Contents *EnhancedDiffPlugin* 12 | ============================================================================ 13 | 14 | 1. Contents.................................: |EnhancedDiffPlugin| 15 | 2. EnhancedDiff Manual......................: |EnhancedDiff-manual| 16 | 3. EnhancedDiff Configuration...............: |EnhancedDiff-config| 17 | 4. EnhancedDiff Feedback....................: |EnhancedDiff-feedback| 18 | 5. EnhancedDiff History.....................: |EnhancedDiff-history| 19 | 20 | ============================================================================ 21 | 2. EnhancedDiffPlugin Manual *EnhancedDiff-manual* 22 | ============================================================================ 23 | 24 | Functionality 25 | 26 | The EnhancedDiff plugin allows to use different diff algorithms. This can 27 | greatly improve the use of |vimdiff| by making a diff more readable. To make 28 | use of different diff algorithms, this plugin makes use of the git command 29 | line tool to generate a unified diff and converts that diff to a normal "ed" 30 | style diff (|diff-diffexpr|) to make vimdiff use that diff. 31 | 32 | You could also use other diff tools if you like, as long as those generate a 33 | diff in the "unified" form. 34 | 35 | By default is disabled, which means, it uses the default diff algorithm (also 36 | known as myers algorithm). 37 | *EnhancedDiff-algorithms* 38 | git supports 4 different diff algorithms. Those are: 39 | 40 | Algorithm Description~ 41 | myers Default diff algorithm 42 | default Alias for myers 43 | minimal Like myers, but tries harder to minimize the resulting 44 | diff 45 | patience Use the patience diff algorithm 46 | histogram Use the histogram diff algorithm (similar to patience but 47 | slightly faster) 48 | 49 | Note you need at least git version 1.8.2 or higher. Older versions do not 50 | support all those algorithms. 51 | 52 | *:EnhancedDiff* 53 | To specify a different diff algorithm use this command: > 54 | 55 | :EnhancedDiff 56 | < 57 | Use any of the above algorithm for creating the diffs. You can use to 58 | complete the different algorithms. 59 | 60 | *:PatienceDiff* 61 | Use the :PatienceDiff to select the "patience" diff algorithm. 62 | 63 | The selected diff algorithm will from then on be used for all the diffs that 64 | will be generated in the future. If you are in diff mode (|vimdiff|) the diff 65 | should be updated immediately. 66 | 67 | *:EnhancedDiffDisable* 68 | Use the :EnhancedDiffDisable command to disable this plugin. 69 | 70 | *:EnhancedDiffIgnorePat* 71 | 72 | Use the command :EnhancedDiffIgnorePat to add patterns to the ignore list: > 73 | 74 | :EnhancedDiffIgnorePat [-buffer] ^.\{,10} [] 75 | < 76 | This will add the pattern "^.\{,10}" (all text column 10 or before) to the 77 | ignorelist. Internally this works by replacing the pattern by a common string 78 | so that the diff command does not see a difference. Most probably won't work 79 | with multi-line patterns. 80 | 81 | Use the "!" attribute to remove all existing patterns and set it to the given 82 | pattern only. 83 | 84 | If [-buffer] is given, will use buffer-local variable for the ignore pattern. 85 | In that case, the part must be given! 86 | 87 | If is given, will use that as replacement part for the pattern 88 | 89 | Note: This only works, if EnhancedDiff has been enabled, e.g. after: > 90 | 91 | :EnhancedDiff default 92 | < 93 | *EnhancedDiff-vimrc* 94 | If you want e.g. the patience diff algorithm to be the default when using the 95 | |vimdiff| command, you need to set the 'diffexpr' option manually like this 96 | in your |.vimrc| > 97 | 98 | :let &diffexpr='EnhancedDiff#Diff("git diff", "--diff-algorithm=patience")' 99 | < 100 | Since internally, EnhancedDiff does simply set up the 'diffexpr' option. 101 | 102 | An alternative to this method is the following: 103 | 104 | Create a file after/plugin/patiencediff.vim in your default runtimepath (e.g. 105 | ~/.vim/ directory on Linux, ~/vimfiles on Windows, creating missing directories, 106 | if they do not exist yet) and put into it the following: > 107 | 108 | " This can't go in .vimrc, because :PatienceDiff isn't available 109 | if !exists(":PatienceDiff") 110 | " This block is optional, but will protect you from errors if you 111 | " uninstall vim-diff-enhanced or share your config across machines 112 | finish 113 | endif 114 | PatienceDiff 115 | < 116 | 117 | ============================================================================== 118 | 3. EnhancedDiff configuration *EnhancedDiff-config* 119 | ============================================================================== 120 | 121 | You can tweak the arguments for the diff generating tools using the following 122 | variables: 123 | 124 | g:enhanced_diff_default_git 125 | --------------------------- 126 | Default command line arguments for git 127 | (Default: "--no-index --no-color --no-ext-diff") 128 | 129 | g:enhanced_diff_default_args 130 | ---------------------------- 131 | Default arguments for any diff command 132 | (Default: "-U0") 133 | 134 | g:enhanced_diff_default_ 135 | --------------------------------- 136 | Default command line argument for (e.g. use "hg" to specify special 137 | arguments and you want to use hg to generate the diff) 138 | (Default: unset) 139 | 140 | *EnhancedDiff-custom-cmd* 141 | 142 | Suppose you want to use a different command line tool to generate the diff. 143 | 144 | For example, let's say you want to use mercurial to generate your diffs. 145 | First define the g:enhanced_diff_default_hg variable and set it to 146 | include all required arguments: > 147 | 148 | :let g:enhanced_diff_default_hg = '-a' 149 | 150 | Then you define your custom command to make the next time diff mode is started 151 | make use of mercurial: > 152 | 153 | :com! HgDiff :let &diffexpr='EnhancedDiff#Diff("hg diff")' 154 | 155 | The first argument of the EnhancedDiff#Diff specifies the command to use to 156 | generate the diff. The optional second argument specifies an optional 157 | parameter that will be used in addition to the g:enhanced_diff_default_hg 158 | variable. In addition to the arguments from the g:enhanced_diff_default_hg 159 | variable, also the arguments from the g:enhanced_diff_default_args will be 160 | used (e.g. by default the -U0 to prevent generating context lines). 161 | 162 | Note: You need to make sure to generate either a normal style diff or a 163 | unified style diff. A unified diff will be converted to a normal style diff so 164 | that Vim can make use of that diff for its diff mode. 165 | 166 | *EnhancedDiff-convert-diffs* 167 | The EnhancedDiff plugin defines a public function 168 | (EnhancedDiff#ConvertToNormalDiff(arg) that can be used by any plugin to 169 | convert a diff in unified form to a diff that can be read by Vim. 170 | 171 | arg is a |List| containing the diff as returned by git diff. Use it 172 | like this: > 173 | 174 | let mydiff = systemlist('git diff ...') 175 | let difflist = EnhancedDiff#ConvertToNormalDiff(mydiff) 176 | < 177 | If your Vim doesn't have the systemlist() function, you can manully split the 178 | list like this: > 179 | 180 | let mydiff = split(system('git diff ...'), "\n") 181 | let difflist = EnhancedDiff#ConvertToNormalDiff(mydiff) 182 | 183 | Note: If you want to use the converted diff and feed it back to Vim for its 184 | diff mode, you need to write the list back to the file |v:fname_out| 185 | ============================================================================ 186 | 4. Plugin Feedback *EnhancedDiff-feedback* 187 | ============================================================================ 188 | 189 | Feedback is always welcome. If you like the plugin, please rate it at the 190 | vim-page: 191 | http://www.vim.org/scripts/script.php?script_id=5121 192 | 193 | You can also follow the development of the plugin at github: 194 | http://github.com/chrisbra/EnhancedDiff.vim 195 | 196 | Please don't hesitate to report any bugs to the maintainer, mentioned in the 197 | third line of this document. 198 | 199 | ============================================================================ 200 | 5. EnhancedDiff History *EnhancedDiff-history* 201 | ============================================================================ 202 | 203 | 0.4 (unreleased) "{{{1 204 | - documentation update 205 | - if |systemlist()| is not available, use |system()| function (issue 206 | https://github.com/chrisbra/vim-diff-enhanced/issues/2 reported by agude, 207 | thanks!) 208 | - cd into temporary directory before doing the diff (issue 209 | https://github.com/chrisbra/vim-diff-enhanced/issues/3 reported by idbrii, 210 | thanks!) 211 | - rename public commands to :EnhancedDiff prefix (issue 212 | https://github.com/chrisbra/vim-diff-enhanced/isseus/4 reported by justinmk, 213 | thanks!) 214 | - g:enhanced_diff_default_git variable wasn't honored (issue #7, reported by 215 | talha131, thanks!) 216 | - Make |:EnhancedDiffIgnorePat| use buffer-local ignore pattern, if possible 217 | (issue #22, reported by liushapku, thanks!) 218 | 219 | 0.3: Mar 5th, 2014 "{{{1 220 | - update diff, when in diffmode and |:CustomDiff| is used 221 | - run test correctly, when installed via plugin manager (issue 222 | https://github.com/chrisbra/vim-diff-enhanced/issues/1, reported by 223 | advocateddrummer thanks!) 224 | - fix small typo (noticed by Gary Johnson, thanks!) 225 | 226 | 0.2: Feb 25, 2015 "{{{1 227 | 228 | - Updated documentation to link to the vim.org page 229 | 230 | 0.1: Feb 25, 2015 "{{{1 231 | 232 | - Internal version 233 | 234 | ============================================================================== 235 | Modeline: "{{{1 236 | vim:tw=78:ts=8:ft=help:et:fdm=marker:fdl=0:norl 237 | -------------------------------------------------------------------------------- /histogram_diff.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/chrisbra/vim-diff-enhanced/8d161f1e97a5f5e64ea4219e6663f98a109df7b1/histogram_diff.png -------------------------------------------------------------------------------- /plugin/EnhancedDiff.vim: -------------------------------------------------------------------------------- 1 | " EnhancedDiff.vim - Enhanced Diff functions for Vim 2 | " ------------------------------------------------------------- 3 | " Version: 0.3 4 | " Maintainer: Christian Brabandt 5 | " Last Change: Thu, 05 Mar 2015 08:11:46 +0100 6 | " Script: http://www.vim.org/scripts/script.php?script_id=5121 7 | " Copyright: (c) 2009-2015 by Christian Brabandt 8 | " The VIM LICENSE applies to EnhancedDifff.vim 9 | " (see |copyright|) except use "EnhancedDiff.vim" 10 | " instead of "Vim". 11 | " No warranty, express or implied. 12 | " *** *** Use At-Your-Own-Risk! *** *** 13 | " GetLatestVimScripts: 5121 3 :AutoInstall: EnhancedDiff.vim 14 | " 15 | " Init: {{{1 16 | let s:cpo= &cpo 17 | if exists("g:loaded_enhanced_diff") || &cp 18 | finish 19 | endif 20 | set cpo&vim 21 | let g:loaded_enhanced_diff = 1 22 | 23 | " Functions {{{1 24 | function! s:OldGitVersion() "{{{2 25 | if !exists('g:enhanced_diff_old_git') 26 | silent let git_version = matchlist(system("git --version"),'\vgit version (\d+)\.(\d+)\.(\d+)') 27 | let major = git_version[1] 28 | let middle = git_version[2] 29 | let minor = git_version[3] 30 | let g:enhanced_diff_old_git = (major < 1) || (major == 1 && (middle < 8 || (middle == 8 && minor < 2))) 31 | endif 32 | return g:enhanced_diff_old_git 33 | endfu 34 | function! s:CustomDiffAlgComplete(A,L,P) "{{{2 35 | if s:OldGitVersion() 36 | return "myers\ndefault\npatience" 37 | else 38 | return "myers\nminimal\ndefault\npatience\nhistogram" 39 | endif 40 | endfu 41 | function! s:CustomIgnorePat(bang, ...) "{{{2 42 | if a:bang 43 | if a:bang && a:0 && a:1 == '-buffer' 44 | let b:enhanced_diff_ignore_pat=[] 45 | else 46 | let g:enhanced_diff_ignore_pat=[] 47 | endif 48 | endif 49 | if !exists("g:enhanced_diff_ignore_pat") 50 | let g:enhanced_diff_ignore_pat=[] 51 | endif 52 | 53 | if a:0 54 | let local = 0 55 | let replace = 'XXX' 56 | if a:0 == 3 && a:1 == '-buffer' 57 | let local=1 58 | if !exists("b:enhanced_diff_ignore_pat") 59 | let b:enhanced_diff_ignore_pat=[] 60 | endif 61 | endif 62 | let pat = local ? a:2 : a:1 63 | if a:0 == 2 64 | let replace = local ? a:3 : a:2 65 | endif 66 | if local 67 | call add(b:enhanced_diff_ignore_pat, [pat, replace]) 68 | else 69 | call add(g:enhanced_diff_ignore_pat, [pat, replace]) 70 | endif 71 | endif 72 | endfu 73 | function s:EnhancedDiffExpr(algo) 74 | return printf('EnhancedDiff#Diff("git diff","%s")', 75 | \ s:OldGitVersion() 76 | \ ? (a:algo == "patience" ? "--patience":"") 77 | \ : "--diff-algorithm=".a:algo) 78 | endfu 79 | " public interface {{{1 80 | com! -nargs=1 -complete=custom,s:CustomDiffAlgComplete EnhancedDiff :let &diffexpr=s:EnhancedDiffExpr("")|:diffupdate 81 | com! PatienceDiff :EnhancedDiff patience 82 | com! EnhancedDiffDisable :set diffexpr= 83 | "com! -nargs=1 -bang EnhancedDiffIgnorePat if | :let g:enhanced_diff_ignore_pat = [] | else | :let g:enhanced_diff_ignore_pat=get(g:, 'enhanced_diff_ignore_pat', []) + [] |endif 84 | com! -nargs=* -bang EnhancedDiffIgnorePat call s:CustomIgnorePat(0, ) 85 | 86 | " Restore: "{{{1 87 | let &cpo=s:cpo 88 | unlet s:cpo 89 | " vim: ts=4 sts=4 sw=4 et fdm=marker com+=l\:\" 90 | -------------------------------------------------------------------------------- /test/1/diff.txt: -------------------------------------------------------------------------------- 1 | default 2 | -------------------------------------------------------------------------------- /test/1/file1: -------------------------------------------------------------------------------- 1 | line1 2 | -------------------------------------------------------------------------------- /test/1/file2: -------------------------------------------------------------------------------- 1 | line2 2 | -------------------------------------------------------------------------------- /test/1/normal_diff.ok: -------------------------------------------------------------------------------- 1 | 1c1 2 | < line1 3 | --- 4 | > line2 5 | -------------------------------------------------------------------------------- /test/2/diff.txt: -------------------------------------------------------------------------------- 1 | default 2 | -------------------------------------------------------------------------------- /test/2/file1: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | // Frobs foo heartily 4 | int frobnitz(int foo) 5 | { 6 | int i; 7 | for(i = 0; i < 10; i++) 8 | { 9 | printf("Your answer is: "); 10 | printf("%d\n", foo); 11 | } 12 | } 13 | 14 | int fact(int n) 15 | { 16 | if(n > 1) 17 | { 18 | return fact(n-1) * n; 19 | } 20 | return 1; 21 | } 22 | 23 | int main(int argc, char **argv) 24 | { 25 | frobnitz(fact(10)); 26 | } 27 | -------------------------------------------------------------------------------- /test/2/file2: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | int fib(int n) 4 | { 5 | if(n > 2) 6 | { 7 | return fib(n-1) + fib(n-2); 8 | } 9 | return 1; 10 | } 11 | 12 | // Frobs foo heartily 13 | int frobnitz(int foo) 14 | { 15 | int i; 16 | for(i = 0; i < 10; i++) 17 | { 18 | printf("%d\n", foo); 19 | } 20 | } 21 | 22 | int main(int argc, char **argv) 23 | { 24 | frobnitz(fib(10)); 25 | } 26 | -------------------------------------------------------------------------------- /test/2/normal_diff.ok: -------------------------------------------------------------------------------- 1 | 3,4c3 2 | < // Frobs foo heartily 3 | < int frobnitz(int foo) 4 | --- 5 | > int fib(int n) 6 | 6,7c5 7 | < int i; 8 | < for(i = 0; i < 10; i++) 9 | --- 10 | > if(n > 2) 11 | 9,10c7 12 | < printf("Your answer is: "); 13 | < printf("%d\n", foo); 14 | --- 15 | > return fib(n-1) + fib(n-2); 16 | 11a9 17 | > return 1; 18 | 14c12,13 19 | < int fact(int n) 20 | --- 21 | > // Frobs foo heartily 22 | > int frobnitz(int foo) 23 | 16c15,16 24 | < if(n > 1) 25 | --- 26 | > int i; 27 | > for(i = 0; i < 10; i++) 28 | 18c18 29 | < return fact(n-1) * n; 30 | --- 31 | > printf("%d\n", foo); 32 | 20d19 33 | < return 1; 34 | 25c24 35 | < frobnitz(fact(10)); 36 | --- 37 | > frobnitz(fib(10)); 38 | -------------------------------------------------------------------------------- /test/3/diff.txt: -------------------------------------------------------------------------------- 1 | default 2 | -------------------------------------------------------------------------------- /test/3/file1: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | // Frobs foo heartily 4 | int frobnitz(int foo) 5 | { 6 | int i; 7 | for(i = 0; i < 10; i++) 8 | { 9 | printf("Your answer is: "); 10 | printf("%d\n", foo); 11 | } 12 | } 13 | 14 | int fact(int n) 15 | { 16 | if(n > 1) 17 | { 18 | return fact(n-1) * n; 19 | } 20 | return 1; 21 | } 22 | 23 | int main(int argc, char **argv) 24 | { 25 | frobnitz(fact(10)); 26 | } 27 | -------------------------------------------------------------------------------- /test/3/file2: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | // Frobs foo heartily 4 | int frobnitz(int foo) 5 | { 6 | int i; 7 | for(i = 0; i < 10; i++) 8 | { 9 | printf("Your answer is: "); 10 | printf("%d\n", foo); 11 | } 12 | } 13 | 14 | int fact(int n) 15 | { 16 | if(n > 1) 17 | { 18 | return fact(n-1) * n; 19 | } 20 | return 1; 21 | } 22 | 23 | int main(int argc, char **argv) 24 | { 25 | frobnitz(fact(10)); 26 | } 27 | -------------------------------------------------------------------------------- /test/3/normal_diff.ok: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/chrisbra/vim-diff-enhanced/8d161f1e97a5f5e64ea4219e6663f98a109df7b1/test/3/normal_diff.ok -------------------------------------------------------------------------------- /test/4/diff.txt: -------------------------------------------------------------------------------- 1 | patience 2 | -------------------------------------------------------------------------------- /test/4/file1: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | // Frobs foo heartily 4 | int frobnitz(int foo) 5 | { 6 | int i; 7 | for(i = 0; i < 10; i++) 8 | { 9 | printf("Your answer is: "); 10 | printf("%d\n", foo); 11 | } 12 | } 13 | 14 | int fact(int n) 15 | { 16 | if(n > 1) 17 | { 18 | return fact(n-1) * n; 19 | } 20 | return 1; 21 | } 22 | 23 | int main(int argc, char **argv) 24 | { 25 | frobnitz(fact(10)); 26 | } 27 | -------------------------------------------------------------------------------- /test/4/file2: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | int fib(int n) 4 | { 5 | if(n > 2) 6 | { 7 | return fib(n-1) + fib(n-2); 8 | } 9 | return 1; 10 | } 11 | 12 | // Frobs foo heartily 13 | int frobnitz(int foo) 14 | { 15 | int i; 16 | for(i = 0; i < 10; i++) 17 | { 18 | printf("%d\n", foo); 19 | } 20 | } 21 | 22 | int main(int argc, char **argv) 23 | { 24 | frobnitz(fib(10)); 25 | } 26 | -------------------------------------------------------------------------------- /test/4/normal_diff.ok: -------------------------------------------------------------------------------- 1 | 2a3,11 2 | > int fib(int n) 3 | > { 4 | > if(n > 2) 5 | > { 6 | > return fib(n-1) + fib(n-2); 7 | > } 8 | > return 1; 9 | > } 10 | > 11 | 9d17 12 | < printf("Your answer is: "); 13 | 14,22d21 14 | < int fact(int n) 15 | < { 16 | < if(n > 1) 17 | < { 18 | < return fact(n-1) * n; 19 | < } 20 | < return 1; 21 | < } 22 | < 23 | 25c24 24 | < frobnitz(fact(10)); 25 | --- 26 | > frobnitz(fib(10)); 27 | -------------------------------------------------------------------------------- /test/5/description.txt: -------------------------------------------------------------------------------- 1 | ignorepat 2 | -------------------------------------------------------------------------------- /test/5/diff.txt: -------------------------------------------------------------------------------- 1 | patience 2 | -------------------------------------------------------------------------------- /test/5/file1: -------------------------------------------------------------------------------- 1 | 2 | xxxxxxxxx foobar 3 | xxxxxxxxx foobar 4 | xxxxxxxxx foobar 5 | xxxxxxxxx foobar 6 | xxxxxxxxx foobar 7 | xxxxxxxxx foobar 8 | xxxxxxxxx foobar 9 | xxxxxxxxx foobar 10 | -------------------------------------------------------------------------------- /test/5/file2: -------------------------------------------------------------------------------- 1 | 2 | yyyyyyyyy foobar 3 | yyyyyyyyy foo 4 | yyyyyyyyy foo 5 | yyyyyyyyy foobar 6 | yyyyyyyyy foobar 7 | yyyyyyyyy foobar 8 | yyyyyyyyy foobar 9 | yyyyyyyyy foobar 10 | -------------------------------------------------------------------------------- /test/5/normal_diff.ok: -------------------------------------------------------------------------------- 1 | 3,4c3,4 2 | < XXX foobar 3 | < XXX foobar 4 | --- 5 | > XXX foo 6 | > XXX foo 7 | -------------------------------------------------------------------------------- /test/5/vimrc: -------------------------------------------------------------------------------- 1 | :EnhancedDiffIgnorePat ^.*\%<11c 2 | -------------------------------------------------------------------------------- /test/6/description.txt: -------------------------------------------------------------------------------- 1 | no ignorepat 2 | -------------------------------------------------------------------------------- /test/6/diff.txt: -------------------------------------------------------------------------------- 1 | patience 2 | -------------------------------------------------------------------------------- /test/6/file1: -------------------------------------------------------------------------------- 1 | 2 | xxxxxxxxx foobar 3 | xxxxxxxxx foobar 4 | xxxxxxxxx foobar 5 | xxxxxxxxx foobar 6 | xxxxxxxxx foobar 7 | xxxxxxxxx foobar 8 | xxxxxxxxx foobar 9 | xxxxxxxxx foobar 10 | -------------------------------------------------------------------------------- /test/6/file2: -------------------------------------------------------------------------------- 1 | 2 | yyyyyyyyy foobar 3 | yyyyyyyyy foo 4 | yyyyyyyyy foo 5 | yyyyyyyyy foobar 6 | yyyyyyyyy foobar 7 | yyyyyyyyy foobar 8 | yyyyyyyyy foobar 9 | yyyyyyyyy foobar 10 | -------------------------------------------------------------------------------- /test/6/normal_diff.ok: -------------------------------------------------------------------------------- 1 | 2,9c2,9 2 | < xxxxxxxxx foobar 3 | < xxxxxxxxx foobar 4 | < xxxxxxxxx foobar 5 | < xxxxxxxxx foobar 6 | < xxxxxxxxx foobar 7 | < xxxxxxxxx foobar 8 | < xxxxxxxxx foobar 9 | < xxxxxxxxx foobar 10 | --- 11 | > yyyyyyyyy foobar 12 | > yyyyyyyyy foo 13 | > yyyyyyyyy foo 14 | > yyyyyyyyy foobar 15 | > yyyyyyyyy foobar 16 | > yyyyyyyyy foobar 17 | > yyyyyyyyy foobar 18 | > yyyyyyyyy foobar 19 | -------------------------------------------------------------------------------- /test/6/vimrc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/chrisbra/vim-diff-enhanced/8d161f1e97a5f5e64ea4219e6663f98a109df7b1/test/6/vimrc -------------------------------------------------------------------------------- /test/README.md: -------------------------------------------------------------------------------- 1 | ## This directory is used for testing the generated normal diffs ## 2 | 3 | TEST the generation of the correct diff. 4 | 5 | Ok files were generated using `git diff -U0 --no-ext-diff --no-color --no-index file* |~/bin/git-diff-normal-format-stdin` 6 | (diff algorithm is determined by sourcing the diff.txt file) 7 | 8 | Run the `test.sh` script to test. 9 | 10 | with git-diff-normal-format-stdin 11 | --------------------------------- 12 | (slightly changed from [takaaki Kasai](http://takaaki-kasai-tech.blogspot.de/2014/07/use-smarter-algorithm-for-vimdiff-such-as-patience-or-histogram.html)) 13 | 14 | ```ruby 15 | #!/usr/bin/env ruby 16 | iwhite = '' 17 | if (ARGV[0] == '-b') 18 | iwhite = ARGV.shift.dup << ' ' 19 | end 20 | 21 | diffout = `git diff --no-index --no-color -U0 #{iwhite}#{ARGV[0]} #{ARGV[1]}` 22 | diffout.sub!(/\A.*?@@/m, '@@') 23 | diffout.gsub!(/^\+/, '> ') 24 | diffout.gsub!(/^-/, '< ') 25 | diffout.gsub!(/^@@ -(\d+)(?:,(\d+))? \+(\d+)(?:,(\d+))? @@.*/) do 26 | before_start = $1 27 | before_size = $2 28 | after_start = $3 29 | after_size = $4 30 | 31 | action = 'c' 32 | if (before_size == '0') 33 | action = 'a' 34 | elsif (after_size == '0') 35 | action = 'd' 36 | end 37 | 38 | before_end = '' 39 | if (before_size && before_size != '0') 40 | before_end = ",#{before_start.to_i + before_size.to_i - 1}" 41 | end 42 | 43 | after_end = '' 44 | if (after_size && after_size != '0') 45 | after_end = ",#{after_start.to_i + after_size.to_i - 1}" 46 | end 47 | 48 | "#{before_start}#{before_end}#{action}#{after_start}#{after_end}" 49 | end 50 | diffout.gsub!(/^(<.*)(\r|\n|\r\n)(>)/, '\1\2---\2\3') 51 | print diffout 52 | ``` 53 | -------------------------------------------------------------------------------- /test/test.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | # set -ex 3 | 4 | for i in */; do 5 | cd "$i" 6 | algorithm=$(cat ./diff.txt) 7 | description='' 8 | test -f description.txt && description=$(cat ./description.txt) 9 | ( LC_ALL=C vim -N --cmd ":let g:enhanced_diff_debug=1" -c ':set acd' \ 10 | -c "if filereadable('vimrc') | so vimrc |endif'" \ 11 | -c ":EnhancedDiff $algorithm" -c ':botright vsp +next' -c ':windo :diffthis' -c ':qa!' file* \ 12 | > /dev/null ) 2>&1 | sed '/Vim: Warning: Output is not to a terminal/d' 13 | diff=`diff normal_diff.ok EnhancedDiff_normal.txt` 14 | if [ $? -ne 0 ]; then 15 | printf "Failure with test %s\n" "${i%%/}" 16 | printf "$diff\n" 17 | break 18 | else 19 | if [ -z "$description" ]; then 20 | printf "Test %s: OK\n" "${i%%/}" 21 | else 22 | printf "Test %s (%s): OK\n" "${i%%/}" "$description" 23 | fi 24 | fi 25 | cd .. 26 | done 27 | --------------------------------------------------------------------------------