systemSetup

system setup, configuration and dotfiles
git clone https://noulin.net/git/systemSetup.git
Log | Files | Refs | README | LICENSE

dirdiff.vim (30620B)


      1 " -*- vim -*-
      2 " FILE: "/home/wlee/.vim/plugin/DirDiff.vim" {{{
      3 " LAST MODIFICATION: "Wed, 11 Apr 2012 15:49:03 -0500 (wlee)"
      4 " HEADER MAINTAINED BY: N/A
      5 " VERSION: 1.1.5
      6 " (C) 2001-2015 by William Lee, <wl1012@yahoo.com>
      7 " }}}
      8 
      9 " Public Interface:
     10 command! -nargs=* -complete=dir DirDiff call <SID>DirDiff (<f-args>)
     11 command! -nargs=0 DirDiffOpen call <SID>DirDiffOpen ()
     12 command! -nargs=0 DirDiffNext call <SID>DirDiffNext ()
     13 command! -nargs=0 DirDiffPrev call <SID>DirDiffPrev ()
     14 command! -nargs=0 DirDiffUpdate call <SID>DirDiffUpdate ()
     15 command! -nargs=0 DirDiffQuit call <SID>DirDiffQuit ()
     16 
     17 " The following comamnds can be used in the Vim diff mode:
     18 " 
     19 " \dg - Diff get: maps to :diffget<CR>
     20 " \dp - Diff put: maps to :diffput<CR>
     21 " \dj - Diff next: (think j for down) 
     22 " \dk - Diff previous: (think k for up)
     23 
     24 if !exists("g:DirDiffEnableMappings")
     25     let g:DirDiffEnableMappings = 0
     26 endif
     27 
     28 if g:DirDiffEnableMappings
     29     nnoremap <unique> <Leader>dg :diffget<CR>
     30     nnoremap <unique> <Leader>dp :diffput<CR>
     31     nnoremap <unique> <Leader>dj :DirDiffNext<CR>
     32     nnoremap <unique> <Leader>dk :DirDiffPrev<CR>
     33 endif
     34 
     35 " Global Maps:
     36 
     37 " Default Variables.  You can override these in your global variables
     38 " settings.
     39 "
     40 " For DirDiffExcludes and DirDiffIgnore, separate different patterns with a
     41 " ',' (comma and no space!).
     42 "
     43 " eg. in your .vimrc file: let g:DirDiffExcludes = "CVS,*.class,*.o"
     44 "                          let g:DirDiffIgnore = "Id:"
     45 "                          " ignore white space in diff
     46 "                          let g:DirDiffAddArgs = "-w" 
     47 "
     48 " You can set the pattern that diff excludes.  Defaults to the CVS directory
     49 if !exists("g:DirDiffExcludes")
     50     let g:DirDiffExcludes = ""
     51 endif
     52 " This is the -I argument of the diff, ignore the lines of differences that
     53 " matches the pattern
     54 if !exists("g:DirDiffIgnore")
     55     let g:DirDiffIgnore = ""
     56 endif
     57 if !exists("g:DirDiffSort")
     58     let g:DirDiffSort = 1
     59 endif
     60 if !exists("g:DirDiffWindowSize")
     61     let g:DirDiffWindowSize = 14
     62 endif
     63 if !exists("g:DirDiffInteractive")
     64     let g:DirDiffInteractive = 0
     65 endif
     66 if !exists("g:DirDiffIgnoreCase")
     67     let g:DirDiffIgnoreCase = 0
     68 endif
     69 " Additional arguments
     70 if !exists("g:DirDiffAddArgs")
     71     let g:DirDiffAddArgs = ""
     72 endif
     73 " Support for i18n (dynamically figure out the diff text)
     74 " Defaults to off
     75 if !exists("g:DirDiffDynamicDiffText")
     76     let g:DirDiffDynamicDiffText = 0
     77 endif
     78 
     79 " String used for the English equivalent "Files "
     80 if !exists("g:DirDiffTextFiles")
     81     let g:DirDiffTextFiles = "Files "
     82 endif
     83 
     84 " String used for the English equivalent " and "
     85 if !exists("g:DirDiffTextAnd")
     86     let g:DirDiffTextAnd = " and "
     87 endif
     88 
     89 " String used for the English equivalent " differ")
     90 if !exists("g:DirDiffTextDiffer")
     91     let g:DirDiffTextDiffer = " differ"
     92 endif
     93 
     94 " String used for the English equivalent "Only in ")
     95 if !exists("g:DirDiffTextOnlyIn")
     96     let g:DirDiffTextOnlyIn = "Only in "
     97 endif
     98 
     99 " String used for the English equivalent ": ")
    100 if !exists("g:DirDiffTextOnlyInCenter")
    101     let g:DirDiffTextOnlyInCenter = ": "
    102 endif
    103 
    104 " Set some script specific variables:
    105 "
    106 let s:DirDiffFirstDiffLine = 6
    107 let s:DirDiffALine = 1
    108 let s:DirDiffBLine = 2
    109 
    110 " -- Variables used in various utilities
    111 if has("unix")
    112     let s:DirDiffCopyCmd = "cp"
    113     let s:DirDiffCopyFlags = ""
    114     let s:DirDiffCopyDirCmd = "cp"
    115     let s:DirDiffCopyDirFlags = "-rf"
    116     let s:DirDiffCopyInteractiveFlag = "-i"
    117 
    118     let s:DirDiffDeleteCmd = "rm"
    119     let s:DirDiffDeleteFlags = ""
    120     let s:DirDiffDeleteInteractiveFlag = "-i"
    121 
    122     let s:DirDiffDeleteDirCmd = "rm"
    123     let s:DirDiffDeleteDirFlags = "-rf"
    124 
    125     let s:sep = "/"
    126 
    127     let s:DirDiffMakeDirCmd  = "!mkdir "
    128 
    129 elseif has("win32")
    130     let s:DirDiffCopyCmd = "copy"
    131     let s:DirDiffCopyFlags = ""
    132     let s:DirDiffCopyDirCmd = "xcopy"
    133     let s:DirDiffCopyDirFlags = "/e /i /q"
    134     let s:DirDiffCopyInteractiveFlag = "/-y"
    135 
    136     let s:DirDiffDeleteCmd = "del"
    137     let s:DirDiffDeleteFlags = "/s /q"
    138     let s:DirDiffDeleteInteractiveFlag = "/p"
    139     " Windows is somewhat stupid since "del" can only remove the files, not
    140     " the directory.  The command "rd" would remove files recursively, but it
    141     " doesn't really work on a file (!).  where is the deltree command???
    142      
    143     let s:DirDiffDeleteDirCmd = "rd"
    144     " rd is by default prompting, we need to handle this in a different way
    145     let s:DirDiffDeleteDirFlags = "/s"
    146     let s:DirDiffDeleteDirQuietFlag = "/q"
    147 
    148     let s:sep = "\\"
    149 
    150     let s:DirDiffMakeDirCmd  = "!mkdir "
    151 else
    152     " Platforms not supported
    153     let s:DirDiffCopyCmd = ""
    154     let s:DirDiffCopyFlags = ""
    155     let s:DirDiffDeleteCmd = ""
    156     let s:DirDiffDeleteFlags = ""
    157     let s:sep = ""
    158 endif
    159 
    160 
    161 function! <SID>DirDiff(srcA, srcB)
    162     " Setup
    163     let DirDiffAbsSrcA = fnamemodify(expand(a:srcA, ":p"), ":p")
    164     let DirDiffAbsSrcB = fnamemodify(expand(a:srcB, ":p"), ":p")
    165 
    166     " Check for an internationalized version of diff ?
    167     call <SID>GetDiffStrings()
    168 
    169     " Remove the trailing \ or /
    170     let DirDiffAbsSrcA = substitute(DirDiffAbsSrcA, '\\$\|/$', '', '')
    171     let DirDiffAbsSrcB = substitute(DirDiffAbsSrcB, '\\$\|/$', '', '')
    172 
    173     let DiffBuffer = tempname()
    174     " We first write to that file
    175     " Constructs the command line
    176     let cmd = "!diff"
    177     let cmdarg = " -r --brief"
    178 
    179     " If variable is set, we ignore the case
    180     if (g:DirDiffIgnoreCase)
    181         let cmdarg = cmdarg." -i"
    182     endif
    183     if (g:DirDiffAddArgs != "")
    184         let cmdarg = cmdarg." ".g:DirDiffAddArgs." "
    185     endif
    186     if (g:DirDiffExcludes != "")
    187         let cmdarg = cmdarg.' -x"'.substitute(g:DirDiffExcludes, ',', '" -x"', 'g').'"'
    188     endif
    189     if (g:DirDiffIgnore != "")
    190         let cmdarg = cmdarg.' -I"'.substitute(g:DirDiffIgnore, ',', '" -I"', 'g').'"'
    191     endif
    192     " Prompt the user for additional arguments
    193 "    let addarg = input("Additional diff args (current =". cmdarg. "): ")
    194     let addarg = ""
    195     let cmd = cmd.cmdarg." ".addarg." \"".DirDiffAbsSrcA."\" \"".DirDiffAbsSrcB."\""
    196     let cmd = cmd." > \"".DiffBuffer."\""
    197 
    198     echo "Diffing directories, it may take a while..."
    199     let error = <SID>DirDiffExec(cmd, 0)
    200     if (error == 0)
    201         redraw | echom "diff found no differences - directories match."
    202         return
    203     endif
    204     silent exe "edit ".DiffBuffer
    205     echo "Defining [A] and [B] ... "
    206     " We then do a substitution on the directory path
    207     " We need to do substitution of the the LONGER string first, otherwise
    208     " it'll mix up the A and B directory
    209     if (strlen(DirDiffAbsSrcA) > strlen(DirDiffAbsSrcB))
    210 	    silent! exe "%s/".<SID>EscapeDirForRegex(DirDiffAbsSrcA)."/[A]/"
    211 	    silent! exe "%s/".<SID>EscapeDirForRegex(DirDiffAbsSrcB)."/[B]/"
    212     else
    213 	    silent! exe "%s/".<SID>EscapeDirForRegex(DirDiffAbsSrcB)."/[B]/"
    214 	    silent! exe "%s/".<SID>EscapeDirForRegex(DirDiffAbsSrcA)."/[A]/"
    215     endif
    216     " In windows, diff behaves somewhat weirdly, for the appened path it'll
    217     " use "/" instead of "\".  Convert this to \
    218     if (has("win32"))
    219         silent! %s/\//\\/g
    220     endif
    221 
    222     echo "Sorting entries ..."
    223     " We then sort the lines if the option is set
    224     if (g:DirDiffSort == 1)
    225         1,$call <SID>Sort("s:Strcmp")
    226     endif
    227 
    228     " Put in spacer in front of each line
    229     silent! %s/^/    /
    230 
    231     " We then put the file [A] and [B] on top of the diff lines
    232     call append(0, "[A]=". DirDiffAbsSrcA)
    233     call append(1, "[B]=". DirDiffAbsSrcB)
    234     if g:DirDiffEnableMappings
    235         call append(2, "Usage:   <Enter>/'o'=open,'s'=sync,'<Leader>dg'=diffget,'<Leader>dp'=diffput,'<Leader>dj'=next,'<Leader>dk'=prev, 'q'=quit")
    236     else
    237         call append(2, "Usage:   <Enter>/'o'=open,'s'=sync,'q'=quit")
    238     endif
    239     call append(3, "Options: 'u'=update,'x'=set excludes,'i'=set ignore,'a'=set args" )
    240     call append(4, "Diff Args:" . cmdarg)
    241     call append(5, "")
    242     " go to the beginning of the file
    243     0
    244     setlocal nomodified
    245     setlocal nomodifiable
    246     setlocal buftype=nowrite
    247     "setlocal buftype=nofile
    248     "setlocal bufhidden=delete
    249     setlocal bufhidden=hide
    250     setlocal nowrap
    251 
    252     " Set up local key bindings
    253     " 'n' actually messes with the search next pattern, I think using \dj and
    254     " \dk is enough.  Otherwise, use j,k, and enter.
    255 "    nnoremap <buffer> n :call <SID>DirDiffNext()<CR>
    256 "    nnoremap <buffer> p :call <SID>DirDiffPrev()<CR>
    257     nnoremap <buffer> s :. call <SID>DirDiffSync()<CR>
    258     vnoremap <buffer> s :call <SID>DirDiffSync()<CR>
    259     nnoremap <buffer> u :call <SID>DirDiffUpdate()<CR>
    260     nnoremap <buffer> x :call <SID>ChangeExcludes()<CR>
    261     nnoremap <buffer> a :call <SID>ChangeArguments()<CR>
    262     nnoremap <buffer> i :call <SID>ChangeIgnore()<CR>
    263     nnoremap <buffer> q :call <SID>DirDiffQuit()<CR>
    264 
    265     nnoremap <buffer> o    :call <SID>DirDiffOpen()<CR>
    266     nnoremap <buffer> <CR>  :call <SID>DirDiffOpen()<CR>  
    267     nnoremap <buffer> <2-Leftmouse> :call <SID>DirDiffOpen()<CR>
    268     call <SID>SetupSyntax()
    269 
    270     " Open the first diff
    271     call <SID>DirDiffNext()
    272 endfunction
    273 
    274 " Set up syntax highlighing for the diff window
    275 "function! <SID>SetupSyntax()
    276 function! <SID>SetupSyntax()
    277   if has("syntax") && exists("g:syntax_on") 
    278       "&& !has("syntax_items")
    279     syn match DirDiffSrcA               "\[A\]"
    280     syn match DirDiffSrcB               "\[B\]"
    281     syn match DirDiffUsage              "^Usage.*"
    282     syn match DirDiffOptions            "^Options.*"
    283     " exec 'syn match DirDiffFiles              "' . s:DirDiffDifferLine .'"'
    284     " exec 'syn match DirDiffOnly               "' . s:DirDiffDiffOnlyLine . '"'
    285     syn match DirDiffSelected           "^==>.*" contains=DirDiffSrcA,DirDiffSrcB
    286 
    287     hi def link DirDiffSrcA               Directory
    288     hi def link DirDiffSrcB               Type
    289     hi def link DirDiffUsage              Special
    290     hi def link DirDiffOptions            Special
    291     hi def link DirDiffFiles              String
    292     hi def link DirDiffOnly               PreProc
    293     hi def link DirDiffSelected           DiffChange
    294   endif
    295 endfunction
    296 
    297 " You should call this within the diff window
    298 function! <SID>DirDiffUpdate()
    299     let dirA = <SID>GetBaseDir("A")
    300     let dirB = <SID>GetBaseDir("B")
    301     call <SID>DirDiff(dirA, dirB)
    302 endfun
    303 
    304 " Quit the DirDiff mode
    305 function! <SID>DirDiffQuit()
    306     let in = confirm ("Are you sure you want to quit DirDiff?", "&Yes\n&No", 2)
    307     if (in == 1)
    308         call <SID>CloseDiffWindows()
    309         bd!
    310     endif
    311 endfun
    312 
    313 " Returns an escaped version of the path for regex uses
    314 function! <SID>EscapeDirForRegex(path)
    315     " This list is probably not complete, modify later
    316     return escape(a:path, "/\\[]$^~")
    317 endfunction
    318 
    319 " Close the opened diff comparison windows if they exist
    320 function! <SID>CloseDiffWindows()
    321     if (<SID>AreDiffWinsOpened())
    322         wincmd k
    323         " Ask the user to save if buffer is modified
    324         call <SID>AskIfModified()
    325         bd!
    326         " User may just have one window opened, we may not need to close
    327         " the second diff window
    328         if (&diff)
    329             call <SID>AskIfModified()
    330             bd!
    331         endif
    332     endif
    333 endfunction
    334 
    335 function! <SID>EscapeFileName(path)
    336 	if (v:version >= 702)
    337 		return fnameescape(a:path)
    338 	else
    339 		" This is not a complete list of escaped character, so it's
    340 		" not as sophisicated as the fnameescape, but this should
    341 		" cover most of the cases and should work for Vim version <
    342 		" 7.2
    343 		return escape(a:path, " \t\n*?[{`$\\%#'\"|!<")
    344 	endif
    345 endfunction
    346 
    347 function! <SID>EchoErr(varName, varValue)
    348 	echoe '' . a:varName . ' : ' . a:varValue
    349 endfunction
    350 
    351 function! <SID>DirDiffOpen()
    352     " First dehighlight the last marked
    353     call <SID>DeHighlightLine()
    354 
    355 	let buffNumber = bufnr('%')
    356     let line = getline(".")
    357 
    358     " We first parse back the [A] and [B] directories from the top of the line
    359     let dirA = <SID>GetBaseDir("A")
    360     let dirB = <SID>GetBaseDir("B")
    361 
    362 
    363     " Save the number of this window, to which we wish to return
    364     " This is required in case there are other windows open
    365 	" let thisWindow = winnr()
    366 	"let thisWindow = winnr(buffNumber)
    367 
    368 	exec 'buffer ' . buffNumber
    369 
    370     call <SID>CloseDiffWindows()
    371     " Mark the current location of the line
    372     "mark n
    373     let b:currentDiff = line(".")
    374 
    375     " Ensure we're in the right window
    376     " silent! exec thisWindow.'wincmd w'
    377 
    378     " Parse the line and see whether it's a "Only in" or "Files Differ"
    379     call <SID>HighlightLine()
    380     let fileA = <SID>GetFileNameFromLine("A", line)
    381     let fileB = <SID>GetFileNameFromLine("B", line)
    382     if <SID>IsOnly(line)
    383         " We open the file
    384         let fileSrc = <SID>ParseOnlySrc(line)
    385         if (fileSrc == "A")
    386             let fileToOpen = fileA
    387         elseif (fileSrc == "B")
    388             let fileToOpen = fileB
    389         endif
    390         split
    391         wincmd k
    392         silent exec "edit ". <SID>EscapeFileName(fileToOpen)
    393         " Fool the window saying that this is diff
    394         diffthis
    395         wincmd j
    396         " Resize the window
    397         exe("resize " . g:DirDiffWindowSize)
    398         exe (b:currentDiff)
    399     elseif <SID>IsDiffer(line)
    400         "Open the diff windows
    401         split
    402         wincmd k
    403         silent exec "edit ".<SID>EscapeFileName(fileB)
    404 
    405         " To ensure that A is on the left and B on the right, splitright must be off
    406         " let saved_splitright = &splitright
    407         " set nosplitright
    408         " silent exec "vert diffsplit ".<SID>EscapeFileName(fileA)
    409         " let &splitright = saved_splitright
    410         silent exec "leftabove vert diffsplit ".<SID>EscapeFileName(fileA)
    411 
    412         " Go back to the diff window
    413         wincmd j
    414         " Resize the window
    415         exe("resize " . g:DirDiffWindowSize)
    416         exe (b:currentDiff)
    417         " Center the line
    418         exe ("normal z.")
    419     else
    420         echo "There is no diff at the current line!"
    421     endif
    422 endfunction
    423 
    424 " Ask the user to save if the buffer is modified
    425 "
    426 function! <SID>AskIfModified()
    427     if (&modified)
    428         let input = confirm("File " . expand("%:p") . " has been modified.", "&Save\nCa&ncel", 1)
    429         if (input == 1)
    430             w!
    431         endif
    432     endif
    433 endfunction
    434 
    435 
    436 function! <SID>HighlightLine()
    437     let savedLine = line(".")
    438     exe (b:currentDiff)
    439     setlocal modifiable
    440     let line = getline(".")
    441     if (match(line, "^    ") == 0)
    442         s/^    /==> /
    443     endif
    444     setlocal nomodifiable
    445     setlocal nomodified
    446     exe (savedLine)
    447     " This is necessary since the modified file would make the syntax
    448     " disappear.
    449     call <SID>SetupSyntax()
    450     redraw
    451 endfunction
    452 
    453 function! <SID>DeHighlightLine()
    454     let savedLine = line(".")
    455     exe (b:currentDiff)
    456     let line = getline(".")
    457     setlocal modifiable
    458     if (match(line, "^==> ") == 0)
    459         s/^==> /    /
    460     endif
    461     setlocal nomodifiable
    462     setlocal nomodified
    463     exe (savedLine)
    464     redraw
    465 endfunction
    466 
    467 " Returns the directory for buffer "A" or "B".  You need to be in the diff
    468 " buffer though.
    469 function! <SID>GetBaseDir(diffName)
    470     let currLine = line(".")
    471     if (a:diffName == "A")
    472         let baseLine = s:DirDiffALine
    473     else
    474         let baseLine = s:DirDiffBLine
    475     endif
    476     let regex = '\['.a:diffName.'\]=\(.*\)'
    477     let line = getline(baseLine)
    478     let rtn = substitute(line, regex , '\1', '')
    479     return rtn
    480 endfunction
    481 
    482 function! <SID>DirDiffNext()
    483     " If the current window is a diff, go down one
    484     if (&diff == 1)
    485         wincmd j
    486     endif
    487     " if the current line is <= 6, (within the header range), we go to the
    488     " first diff line open it
    489     if (line(".") < s:DirDiffFirstDiffLine)
    490         exe (s:DirDiffFirstDiffLine)
    491         let b:currentDiff = line(".")
    492     endif
    493     silent! exe (b:currentDiff + 1)
    494     call <SID>DirDiffOpen()
    495 endfunction
    496 
    497 function! <SID>DirDiffPrev()
    498     " If the current window is a diff, go down one
    499     if (&diff == 1)
    500         wincmd j
    501     endif
    502     silent! exe (b:currentDiff - 1)
    503     call <SID>DirDiffOpen()
    504 endfunction
    505 
    506 " For each line, we can perform a recursive copy or delete to sync up the
    507 " difference. Returns non-zero if the operation is NOT successful, returns 0
    508 " if everything is fine.
    509 "
    510 function! <SID>DirDiffSyncHelper(AB, line)
    511     let fileA = <SID>GetFileNameFromLine("A", a:line)
    512     let fileB = <SID>GetFileNameFromLine("B", a:line)
    513 "    echo "Helper line is ". a:line. " fileA " . fileA . " fileB " . fileB
    514     if <SID>IsOnly(a:line)
    515         " If a:AB is "A" and the ParseOnlySrc returns "A", that means we need to
    516         " copy
    517         let fileSrc = <SID>ParseOnlySrc(a:line)
    518         let operation = ""
    519         if (a:AB == "A" && fileSrc == "A")
    520             let operation = "Copy"
    521             " Use A, and A has source, thus copy the file from A to B
    522             let fileFrom = fileA
    523             let fileTo = fileB
    524         elseif (a:AB == "A" && fileSrc == "B")
    525             let operation = "Delete"
    526             " Use A, but B has source, thus delete the file from B
    527             let fileFrom = fileB
    528             let fileTo = fileA
    529         elseif (a:AB == "B" && fileSrc == "A")
    530             let operation = "Delete"
    531             " Use B, but the source file is A, thus removing A
    532             let fileFrom = fileA
    533             let fileTo = fileB
    534         elseif (a:AB == "B" && fileSrc == "B")
    535             " Use B, and B has the source file, thus copy B to A
    536             let operation = "Copy"
    537             let fileFrom = fileB
    538             let fileTo = fileA
    539         endif
    540     elseif <SID>IsDiffer(a:line)
    541         " Copy no matter what
    542         let operation = "Copy"
    543         if (a:AB == "A")
    544             let fileFrom = fileA
    545             let fileTo = fileB
    546         elseif (a:AB == "B")
    547             let fileFrom = fileB
    548             let fileTo = fileA
    549         endif
    550     else 
    551         echo "There is no diff here!"
    552         " Error
    553         return 1
    554     endif
    555     if (operation == "Copy")
    556         let rtnCode = <SID>Copy(fileFrom, fileTo)
    557     elseif (operation == "Delete")
    558         let rtnCode = <SID>Delete(fileFrom)
    559     endif
    560     return rtnCode
    561 endfunction
    562 
    563 " Synchronize the range
    564 function! <SID>DirDiffSync() range
    565     let answer = 1
    566     let silence = 0
    567     let syncMaster = "A"
    568     let currLine = a:firstline
    569     let lastLine = a:lastline
    570     let syncCount = 0
    571 
    572     while ((currLine <= lastLine))
    573         " Update the highlight
    574         call <SID>DeHighlightLine()
    575         let b:currentDiff = currLine
    576         call <SID>HighlightLine()
    577         let line = getline(currLine)
    578         if (!silence)
    579             let answer = confirm(substitute(line, "^....", '', ''). "\nSynchronization option:" , "&A -> B\n&B -> A\nA&lways A\nAl&ways B\n&Skip\nCa&ncel", 6)
    580             if (answer == 1 || answer == 3)
    581                 let syncMaster = "A"
    582             endif
    583             if (answer == 2 || answer == 4)
    584                 let syncMaster = "B"
    585             endif
    586             if (answer == 3 || answer == 4)
    587                 let silence = 1
    588             endif
    589             if (answer == 5)
    590                 let currLine = currLine + 1
    591                 continue
    592             endif
    593             if (answer == 6)
    594                 break
    595             endif
    596         endif
    597 
    598 "        call <SID>DeHighlightLine()
    599         let rtnCode = <SID>DirDiffSyncHelper(syncMaster, line)
    600         if (rtnCode == 0)
    601             " Successful
    602             let syncCount = syncCount + 1
    603             " Assume that the line is synchronized, we delete the entry
    604             setlocal modifiable
    605             exe (currLine.",".currLine." delete")
    606             setlocal nomodifiable
    607             setlocal nomodified
    608             let lastLine = lastLine - 1
    609         else
    610             " Failed!
    611             let currLine = currLine + 1
    612         endif
    613     endwhile
    614     echo syncCount . " diff item(s) synchronized."
    615 endfunction
    616 
    617 " Return file "A" or "B" depending on the line given.  If it's a Only line,
    618 " either A or B does not exist, but the according value would be returned.
    619 function! <SID>GetFileNameFromLine(AB, line)
    620     " Determine where the source of the copy is.
    621     let dirA = <SID>GetBaseDir("A")
    622     let dirB = <SID>GetBaseDir("B")
    623 
    624     let fileToProcess = ""
    625 
    626     if <SID>IsOnly(a:line)
    627         let fileToProcess = <SID>ParseOnlyFile(a:line)
    628     elseif <SID>IsDiffer(a:line)
    629         let regex = '^.*' . s:DirDiffDifferLine . '\[A\]\(.*\)' . s:DirDiffDifferAndLine . '\[B\]\(.*\)' . s:DirDiffDifferEndLine . '.*$'
    630         let fileToProcess = substitute(a:line, regex, '\1', '')
    631     else
    632     endif
    633 
    634     "echo "line : " . a:line. "AB = " . a:AB . " File to Process " . fileToProcess
    635     if (a:AB == "A")
    636         return dirA . fileToProcess
    637     elseif (a:AB == "B")
    638         return dirB . fileToProcess
    639     else
    640         return ""
    641     endif
    642 endfunction
    643 
    644 "Returns the source (A or B) of the "Only" line
    645 function! <SID>ParseOnlySrc(line)
    646     return substitute(a:line, '^.*' . s:DirDiffDiffOnlyLine . '\[\(.\)\].*' . s:DirDiffDiffOnlyLineCenter . '.*', '\1', '')
    647 endfunction
    648 
    649 function! <SID>ParseOnlyFile(line)
    650     let regex = '^.*' . s:DirDiffDiffOnlyLine . '\[.\]\(.*\)' . s:DirDiffDiffOnlyLineCenter . '\(.*\)'
    651     let root = substitute(a:line, regex , '\1', '')
    652     let file = root . s:sep . substitute(a:line, regex , '\2', '')
    653     return file
    654 endfunction
    655 
    656 function! <SID>Copy(fileFromOrig, fileToOrig)
    657     let fileFrom = substitute(a:fileFromOrig, '/', s:sep, 'g')
    658     let fileTo = substitute(a:fileToOrig, '/', s:sep, 'g')
    659     echo "Copy from " . fileFrom . " to " . fileTo
    660     if (s:DirDiffCopyCmd == "")
    661         echo "Copy not supported on this platform"
    662         return 1
    663     endif
    664 
    665     " Constructs the copy command
    666     let copycmd = "!".s:DirDiffCopyCmd." ".s:DirDiffCopyFlags
    667     " Append the interactive flag
    668     if (g:DirDiffInteractive)
    669         let copycmd = copycmd . " " . s:DirDiffCopyInteractiveFlag
    670     endif
    671     let copycmd = copycmd . " \"".fileFrom."\" \"".fileTo."\""
    672 
    673     " Constructs the copy directory command
    674     let copydircmd = "!".s:DirDiffCopyDirCmd." ".s:DirDiffCopyDirFlags
    675     " Append the interactive flag
    676     if (g:DirDiffInteractive)
    677         let copydircmd = copydircmd . " " . s:DirDiffCopyInteractiveFlag
    678     endif
    679     let copydircmd = copydircmd . " \"".fileFrom."\" \"".fileTo."\""
    680 
    681     let error = 0
    682     if (isdirectory(fileFrom))
    683         let error = <SID>DirDiffExec(copydircmd, g:DirDiffInteractive)
    684     else
    685         let error = <SID>DirDiffExec(copycmd, g:DirDiffInteractive)
    686     endif
    687     if (error != 0)
    688         echo "Can't copy from " . fileFrom . " to " . fileTo
    689         return 1
    690     endif
    691     return 0
    692 endfunction
    693 
    694 " Would execute the command, either silent or not silent, by the
    695 " interactive flag ([0|1]).  Returns the v:shell_error after
    696 " executing the command.
    697 function! <SID>DirDiffExec(cmd, interactive)
    698     let error = 0
    699     if (a:interactive)
    700         exe (a:cmd)
    701         let error = v:shell_error
    702     else
    703         silent exe (a:cmd)
    704         let error = v:shell_error
    705     endif
    706 "    let d = input("DirDiffExec: " . a:cmd . " " . a:interactive . " returns " . v:shell_error)
    707     return error
    708 endfunction
    709 
    710 " Delete the file or directory.  Returns 0 if nothing goes wrong, error code
    711 " otherwise.
    712 function! <SID>Delete(fileFromOrig)
    713     let fileFrom = substitute(a:fileFromOrig, '/', s:sep, 'g')
    714     echo "Deleting from " . fileFrom
    715     if (s:DirDiffDeleteCmd == "")
    716         echo "Delete not supported on this platform"
    717         return 1
    718     endif
    719 
    720     let delcmd = ""
    721 
    722     if (isdirectory(fileFrom))
    723         let delcmd = "!".s:DirDiffDeleteDirCmd." ".s:DirDiffDeleteDirFlags
    724         if (g:DirDiffInteractive)
    725             " If running on Unix, and we're running in interactive mode, we
    726             " append the -i tag
    727             if (has("unix"))
    728                 let delcmd = delcmd . " " . s:DirDiffDeleteInteractiveFlag
    729             endif
    730         else
    731             " If running on windows, and we're not running in interactive
    732             " mode, we append the quite flag to the "rd" command
    733             if (has("win32"))
    734                 let delcmd = delcmd . " " . s:DirDiffDeleteDirQuietFlag
    735             endif
    736         endif
    737     else
    738         let delcmd = "!".s:DirDiffDeleteCmd." ".s:DirDiffDeleteFlags
    739         if (g:DirDiffInteractive)
    740             let delcmd = delcmd . " " . s:DirDiffDeleteInteractiveFlag
    741         endif
    742     endif
    743 
    744     let delcmd = delcmd ." \"".fileFrom."\""
    745     let error = <SID>DirDiffExec(delcmd, g:DirDiffInteractive)
    746     if (error != 0)
    747         echo "Can't delete " . fileFrom
    748     endif
    749     return error
    750 endfunction
    751 
    752 function! <SID>AreDiffWinsOpened()
    753     let currBuff = expand("%:p")
    754     let currLine = line(".")
    755     wincmd k
    756     let abovedBuff = expand("%:p")
    757     if (&diff)
    758         let abovedIsDiff = 1
    759     else
    760         let abovedIsDiff = 0
    761     endif
    762     " Go Back if the aboved buffer is not the same
    763     if (currBuff != abovedBuff)
    764         wincmd j
    765         " Go back to the same line
    766         exe (currLine)
    767         if (abovedIsDiff == 1)
    768             return 1
    769         else
    770             " Aboved is just a bogus buffer, not a diff buffer
    771             return 0
    772         endif
    773     else
    774         exe (currLine)
    775         return 0
    776     endif
    777 endfunction
    778 
    779 " The given line begins with the "Only in"
    780 function! <SID>IsOnly(line)	
    781     return (match(a:line, "^ *" . s:DirDiffDiffOnlyLine . "\\|^==> " . s:DirDiffDiffOnlyLine ) == 0)
    782 endfunction
    783 
    784 " The given line begins with the "Files"
    785 function! <SID>IsDiffer(line)
    786     return (match(a:line, "^ *" . s:DirDiffDifferLine . "\\|^==> " . s:DirDiffDifferLine  ) == 0)
    787 endfunction
    788 
    789 " Let you modify the Exclude patthern
    790 function! <SID>ChangeExcludes()
    791     let g:DirDiffExcludes = input ("Exclude pattern (separate multiple patterns with ','): ", g:DirDiffExcludes)
    792     echo "\nPress update ('u') to refresh the diff."
    793 endfunction
    794 
    795 " Let you modify additional arguments for diff
    796 function! <SID>ChangeArguments()
    797     let g:DirDiffAddArgs = input ("Additional diff args: ", g:DirDiffAddArgs)
    798     echo "\nPress update ('u') to refresh the diff."
    799 endfunction
    800 
    801 " Let you modify the Ignore patthern
    802 function! <SID>ChangeIgnore()
    803     let g:DirDiffIgnore = input ("Ignore pattern (separate multiple patterns with ','): ", g:DirDiffIgnore)
    804     echo "\nPress update ('u') to refresh the diff."
    805 endfunction
    806 
    807 " Sorting functions from the Vim docs.  Use this instead of the sort binary.
    808 "
    809 " Function for use with Sort(), to compare two strings.
    810 func! <SID>Strcmp(str1, str2)
    811   if (a:str1 < a:str2)
    812 	return -1
    813   elseif (a:str1 > a:str2)
    814 	return 1
    815   else
    816 	return 0
    817   endif
    818 endfunction
    819 
    820 " Sort lines.  SortR() is called recursively.
    821 func! <SID>SortR(start, end, cmp)
    822   if (a:start >= a:end)
    823 	return
    824   endif
    825   let partition = a:start - 1
    826   let middle = partition
    827   let partStr = getline((a:start + a:end) / 2)
    828   let i = a:start
    829   while (i <= a:end)
    830 	let str = getline(i)
    831 	exec "let result = " . a:cmp . "(str, partStr)"
    832 	if (result <= 0)
    833 	    " Need to put it before the partition.  Swap lines i and partition.
    834 	    let partition = partition + 1
    835 	    if (result == 0)
    836 		let middle = partition
    837 	    endif
    838 	    if (i != partition)
    839 		let str2 = getline(partition)
    840 		call setline(i, str2)
    841 		call setline(partition, str)
    842 	    endif
    843 	endif
    844 	let i = i + 1
    845   endwhile
    846 
    847   " Now we have a pointer to the "middle" element, as far as partitioning
    848   " goes, which could be anywhere before the partition.  Make sure it is at
    849   " the end of the partition.
    850   if (middle != partition)
    851 	let str = getline(middle)
    852 	let str2 = getline(partition)
    853 	call setline(middle, str2)
    854 	call setline(partition, str)
    855   endif
    856   call <SID>SortR(a:start, partition - 1, a:cmp)
    857   call <SID>SortR(partition + 1, a:end, a:cmp)
    858 endfunc
    859 
    860 " To Sort a range of lines, pass the range to Sort() along with the name of a
    861 " function that will compare two lines.
    862 func! <SID>Sort(cmp) range
    863   call <SID>SortR(a:firstline, a:lastline, a:cmp)
    864 endfunc
    865 
    866 " Added to deal with internationalized version of diff, which returns a
    867 " different string than "Files ... differ" or "Only in ... "
    868 
    869 function! <SID>GetDiffStrings()
    870     " Check if we have the dynamic text string turned on.  If not, just return
    871     " what's set in the global variables
    872 
    873     if (g:DirDiffDynamicDiffText == 0)
    874         let s:DirDiffDiffOnlyLineCenter = g:DirDiffTextOnlyInCenter
    875         let s:DirDiffDiffOnlyLine = g:DirDiffTextOnlyIn
    876         let s:DirDiffDifferLine = g:DirDiffTextFiles
    877         let s:DirDiffDifferAndLine = g:DirDiffTextAnd
    878         let s:DirDiffDifferEndLine = g:DirDiffTextDiffer
    879         return
    880     endif
    881 
    882 	let tmp1 = tempname()
    883 	let tmp2 = tempname()
    884 	let tmpdiff = tempname()
    885 
    886     " We need to pad the backslashes in order to make it match
    887     let tmp1rx = <SID>EscapeDirForRegex(tmp1)
    888     let tmp2rx = <SID>EscapeDirForRegex(tmp2)
    889     let tmpdiffrx = <SID>EscapeDirForRegex(tmpdiff)
    890 
    891 	silent exe s:DirDiffMakeDirCmd . "\"" . tmp1 . "\""
    892 	silent exe s:DirDiffMakeDirCmd . "\"" . tmp2 . "\""
    893 	silent exe "!echo test > \"" . tmp1 . s:sep . "test" . "\""
    894 	silent exe "!diff -r --brief \"" . tmp1 . "\" \"" . tmp2 . "\" > \"" . tmpdiff . "\""
    895 
    896 	" Now get the result of that diff cmd
    897 	silent exe "split ". tmpdiff
    898     "echo "First line: " . getline(1)
    899     "echo "tmp1: " . tmp1
    900     "echo "tmp1rx: " . tmp1rx
    901     let regex = '\(^.*\)' . tmp1rx . '\(.*\)' . "test"
    902 	let s:DirDiffDiffOnlyLine = substitute( getline(1), regex, '\1', '') 
    903 	let s:DirDiffDiffOnlyLineCenter = substitute( getline(1), regex, '\2', '') 
    904     "echo "DirDiff Only: " . s:DirDiffDiffOnlyLine
    905 	
    906 	q
    907 
    908 	" Now let's get the Differ string
    909     "echo "Getting the diff in GetDiffStrings"
    910 	
    911 	silent exe "!echo testdifferent > \"" . tmp2 . s:sep . "test" . "\""
    912 	silent exe "!diff -r --brief \"" . tmp1 . "\" \"" . tmp2 . "\" > \"" . tmpdiff . "\""
    913 	
    914 	silent exe "split ". tmpdiff
    915 	let s:DirDiffDifferLine = substitute( getline(1), tmp1rx . ".*$", "", '') 
    916     " Note that the diff on cygwin may output '/' instead of '\' for the
    917     " separator, so we need to accomodate for both cases
    918     let andrx = "^.*" . tmp1rx . "[\\\/]test\\(.*\\)" . tmp2rx . "[\\\/]test.*$"
    919     let endrx = "^.*" . tmp1rx . "[\\\/]test.*" . tmp2rx . "[\\\/]test\\(.*$\\)"
    920     "echo "andrx : " . andrx
    921     "echo "endrx : " . endrx
    922 	let s:DirDiffDifferAndLine = substitute( getline(1), andrx , "\\1", '') 
    923     let s:DirDiffDifferEndLine = substitute( getline(1), endrx, "\\1", '') 
    924 
    925 	"echo "s:DirDiffDifferLine = " . s:DirDiffDifferLine
    926 	"echo "s:DirDiffDifferAndLine = " . s:DirDiffDifferAndLine
    927 	"echo "s:DirDiffDifferEndLine = " . s:DirDiffDifferEndLine
    928 
    929 	q
    930 
    931 	" Delete tmp files
    932     "echo "Deleting tmp files."
    933 
    934 	call <SID>Delete(tmp1)
    935 	call <SID>Delete(tmp2)
    936 	call <SID>Delete(tmpdiff)
    937 
    938 	"avoid get diff text again
    939 	let g:DirDiffTextOnlyInCenter = s:DirDiffDiffOnlyLineCenter
    940 	let g:DirDiffTextOnlyIn = s:DirDiffDiffOnlyLine
    941 	let g:DirDiffTextFiles = s:DirDiffDifferLine
    942 	let g:DirDiffTextAnd = s:DirDiffDifferAndLine
    943 	let g:DirDiffTextDiffer = s:DirDiffDifferEndLine
    944 	let g:DirDiffDynamicDiffText = 0
    945 
    946 endfunction