Fossil SCM
Add some line-number information to the conflict marks on a 3-way merge. More work could be done here, but this is a start.
Commit
14f44e933c0c0c2c6fef25909916d1a297c00fca89f51f1cb043f832eb0771a4
Parent
8c1263754c66005…
1 file changed
+47
-37
+47
-37
| --- src/merge3.c | ||
| +++ src/merge3.c | ||
| @@ -116,21 +116,22 @@ | ||
| 116 | 116 | static int output_one_side( |
| 117 | 117 | Blob *pOut, /* Write to this blob */ |
| 118 | 118 | Blob *pSrc, /* The edited file that is to be copied to pOut */ |
| 119 | 119 | int *aC, /* Array of integer triples describing the edit */ |
| 120 | 120 | int i, /* Index in aC[] of current location in pSrc */ |
| 121 | - int sz /* Number of lines in unedited source to output */ | |
| 121 | + int sz, /* Number of lines in unedited source to output */ | |
| 122 | + int *pLn /* Line number counter */ | |
| 122 | 123 | ){ |
| 123 | 124 | while( sz>0 ){ |
| 124 | 125 | if( aC[i]==0 && aC[i+1]==0 && aC[i+2]==0 ) break; |
| 125 | 126 | if( aC[i]>=sz ){ |
| 126 | - blob_copy_lines(pOut, pSrc, sz); | |
| 127 | + blob_copy_lines(pOut, pSrc, sz); *pLn += sz; | |
| 127 | 128 | aC[i] -= sz; |
| 128 | 129 | break; |
| 129 | 130 | } |
| 130 | - blob_copy_lines(pOut, pSrc, aC[i]); | |
| 131 | - blob_copy_lines(pOut, pSrc, aC[i+2]); | |
| 131 | + blob_copy_lines(pOut, pSrc, aC[i]); *pLn += aC[i]; | |
| 132 | + blob_copy_lines(pOut, pSrc, aC[i+2]); *pLn += aC[i+2]; | |
| 132 | 133 | sz -= aC[i] + aC[i+1]; |
| 133 | 134 | i += 3; |
| 134 | 135 | } |
| 135 | 136 | return i; |
| 136 | 137 | } |
| @@ -138,14 +139,14 @@ | ||
| 138 | 139 | /* |
| 139 | 140 | ** Text of boundary markers for merge conflicts. |
| 140 | 141 | */ |
| 141 | 142 | static const char *const mergeMarker[] = { |
| 142 | 143 | /*123456789 123456789 123456789 123456789 123456789 123456789 123456789*/ |
| 143 | - "<<<<<<< BEGIN MERGE CONFLICT: local copy shown first <<<<<<<<<<<<<<<", | |
| 144 | - "||||||| COMMON ANCESTOR content follows ||||||||||||||||||||||||||||", | |
| 145 | - "======= MERGED IN content follows ==================================", | |
| 146 | - ">>>>>>> END MERGE CONFLICT >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>" | |
| 144 | + "<<<<<<< BEGIN MERGE CONFLICT: local copy shown first <<<<<<<<<<<<", | |
| 145 | + "||||||| COMMON ANCESTOR content follows |||||||||||||||||||||||||", | |
| 146 | + "======= MERGED IN content follows ===============================", | |
| 147 | + ">>>>>>> END MERGE CONFLICT >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>" | |
| 147 | 148 | }; |
| 148 | 149 | |
| 149 | 150 | /* |
| 150 | 151 | ** Return true if the input blob contains any CR/LF pairs on the first |
| 151 | 152 | ** ten lines. This should be enough to detect files that use mainly CR/LF |
| @@ -175,10 +176,20 @@ | ||
| 175 | 176 | if( pBlob->aData[pBlob->nUsed-1]!='\n' ){ |
| 176 | 177 | if( useCrLf ) blob_append_char(pBlob, '\r'); |
| 177 | 178 | blob_append_char(pBlob, '\n'); |
| 178 | 179 | } |
| 179 | 180 | } |
| 181 | + | |
| 182 | +/* | |
| 183 | +** Write out one of the four merge-marks. | |
| 184 | +*/ | |
| 185 | +void append_merge_mark(Blob *pOut, int iMark, int ln, int useCrLf){ | |
| 186 | + ensure_line_end(pOut, useCrLf); | |
| 187 | + blob_append(pOut, mergeMarker[iMark], -1); | |
| 188 | + if( ln>0 ) blob_appendf(pOut, " (line %d)", ln); | |
| 189 | + ensure_line_end(pOut, useCrLf); | |
| 190 | +} | |
| 180 | 191 | |
| 181 | 192 | /* |
| 182 | 193 | ** Do a three-way merge. Initialize pOut to contain the result. |
| 183 | 194 | ** |
| 184 | 195 | ** The merge is an edit against pV2. Both pV1 and pV2 have a |
| @@ -196,10 +207,11 @@ | ||
| 196 | 207 | int i1, i2; /* Index into aC1[] and aC2[] */ |
| 197 | 208 | int nCpy, nDel, nIns; /* Number of lines to copy, delete, or insert */ |
| 198 | 209 | int limit1, limit2; /* Sizes of aC1[] and aC2[] */ |
| 199 | 210 | int nConflict = 0; /* Number of merge conflicts seen so far */ |
| 200 | 211 | int useCrLf = 0; |
| 212 | + int ln1, ln2, lnPivot; /* Line numbers for all files */ | |
| 201 | 213 | DiffConfig DCfg; |
| 202 | 214 | |
| 203 | 215 | blob_zero(pOut); /* Merge results stored in pOut */ |
| 204 | 216 | |
| 205 | 217 | /* If both pV1 and pV2 start with a UTF-8 byte-order-mark (BOM), |
| @@ -259,56 +271,57 @@ | ||
| 259 | 271 | ** which is written into pOut. i1 and i2 are multiples of 3 which are |
| 260 | 272 | ** indices into aC1[] and aC2[] to the edit triple currently being |
| 261 | 273 | ** processed |
| 262 | 274 | */ |
| 263 | 275 | i1 = i2 = 0; |
| 276 | + ln1 = ln2 = lnPivot = 1; | |
| 264 | 277 | while( i1<limit1 && i2<limit2 ){ |
| 265 | 278 | DEBUG( printf("%d: %2d %2d %2d %d: %2d %2d %2d\n", |
| 266 | 279 | i1/3, aC1[i1], aC1[i1+1], aC1[i1+2], |
| 267 | 280 | i2/3, aC2[i2], aC2[i2+1], aC2[i2+2]); ) |
| 268 | 281 | |
| 269 | 282 | if( aC1[i1]>0 && aC2[i2]>0 ){ |
| 270 | 283 | /* Output text that is unchanged in both V1 and V2 */ |
| 271 | 284 | nCpy = min(aC1[i1], aC2[i2]); |
| 272 | 285 | DEBUG( printf("COPY %d\n", nCpy); ) |
| 273 | - blob_copy_lines(pOut, pPivot, nCpy); | |
| 274 | - blob_copy_lines(0, pV1, nCpy); | |
| 275 | - blob_copy_lines(0, pV2, nCpy); | |
| 286 | + blob_copy_lines(pOut, pPivot, nCpy); lnPivot += nCpy; | |
| 287 | + blob_copy_lines(0, pV1, nCpy); ln1 += nCpy; | |
| 288 | + blob_copy_lines(0, pV2, nCpy); ln2 += nCpy; | |
| 276 | 289 | aC1[i1] -= nCpy; |
| 277 | 290 | aC2[i2] -= nCpy; |
| 278 | 291 | }else |
| 279 | 292 | if( aC1[i1] >= aC2[i2+1] && aC1[i1]>0 && aC2[i2+1]+aC2[i2+2]>0 ){ |
| 280 | 293 | /* Output edits to V2 that occurs within unchanged regions of V1 */ |
| 281 | 294 | nDel = aC2[i2+1]; |
| 282 | 295 | nIns = aC2[i2+2]; |
| 283 | 296 | DEBUG( printf("EDIT -%d+%d left\n", nDel, nIns); ) |
| 284 | - blob_copy_lines(0, pPivot, nDel); | |
| 285 | - blob_copy_lines(0, pV1, nDel); | |
| 286 | - blob_copy_lines(pOut, pV2, nIns); | |
| 297 | + blob_copy_lines(0, pPivot, nDel); lnPivot += nDel; | |
| 298 | + blob_copy_lines(0, pV1, nDel); ln1 += nDel; | |
| 299 | + blob_copy_lines(pOut, pV2, nIns); ln2 += nIns; | |
| 287 | 300 | aC1[i1] -= nDel; |
| 288 | 301 | i2 += 3; |
| 289 | 302 | }else |
| 290 | 303 | if( aC2[i2] >= aC1[i1+1] && aC2[i2]>0 && aC1[i1+1]+aC1[i1+2]>0 ){ |
| 291 | 304 | /* Output edits to V1 that occur within unchanged regions of V2 */ |
| 292 | 305 | nDel = aC1[i1+1]; |
| 293 | 306 | nIns = aC1[i1+2]; |
| 294 | 307 | DEBUG( printf("EDIT -%d+%d right\n", nDel, nIns); ) |
| 295 | - blob_copy_lines(0, pPivot, nDel); | |
| 296 | - blob_copy_lines(0, pV2, nDel); | |
| 297 | - blob_copy_lines(pOut, pV1, nIns); | |
| 308 | + blob_copy_lines(0, pPivot, nDel); lnPivot += nDel; | |
| 309 | + blob_copy_lines(0, pV2, nDel); ln2 += nDel; | |
| 310 | + blob_copy_lines(pOut, pV1, nIns); ln1 += nIns; | |
| 298 | 311 | aC2[i2] -= nDel; |
| 299 | 312 | i1 += 3; |
| 300 | 313 | }else |
| 301 | 314 | if( sameEdit(&aC1[i1], &aC2[i2], pV1, pV2) ){ |
| 302 | 315 | /* Output edits that are identical in both V1 and V2. */ |
| 303 | 316 | assert( aC1[i1]==0 ); |
| 304 | 317 | nDel = aC1[i1+1]; |
| 305 | 318 | nIns = aC1[i1+2]; |
| 306 | 319 | DEBUG( printf("EDIT -%d+%d both\n", nDel, nIns); ) |
| 307 | - blob_copy_lines(0, pPivot, nDel); | |
| 308 | - blob_copy_lines(pOut, pV1, nIns); | |
| 309 | - blob_copy_lines(0, pV2, nIns); | |
| 320 | + blob_copy_lines(0, pPivot, nDel); lnPivot += nDel; | |
| 321 | + blob_copy_lines(pOut, pV1, nIns); ln1 += nIns; | |
| 322 | + blob_copy_lines(0, pV2, nIns); ln2 += nIns; | |
| 310 | 323 | i1 += 3; |
| 311 | 324 | i2 += 3; |
| 312 | 325 | }else |
| 313 | 326 | { |
| 314 | 327 | /* We have found a region where different edits to V1 and V2 overlap. |
| @@ -319,25 +332,21 @@ | ||
| 319 | 332 | nConflict++; |
| 320 | 333 | while( !ends_at_CPY(&aC1[i1], sz) || !ends_at_CPY(&aC2[i2], sz) ){ |
| 321 | 334 | sz++; |
| 322 | 335 | } |
| 323 | 336 | DEBUG( printf("CONFLICT %d\n", sz); ) |
| 324 | - ensure_line_end(pOut, useCrLf); | |
| 325 | - blob_append(pOut, mergeMarker[0], -1); | |
| 326 | - ensure_line_end(pOut, useCrLf); | |
| 327 | - i1 = output_one_side(pOut, pV1, aC1, i1, sz); | |
| 328 | - ensure_line_end(pOut, useCrLf); | |
| 329 | - blob_append(pOut, mergeMarker[1], -1); | |
| 330 | - ensure_line_end(pOut, useCrLf); | |
| 331 | - blob_copy_lines(pOut, pPivot, sz); | |
| 332 | - ensure_line_end(pOut, useCrLf); | |
| 333 | - blob_append(pOut, mergeMarker[2], -1); | |
| 334 | - ensure_line_end(pOut, useCrLf); | |
| 335 | - i2 = output_one_side(pOut, pV2, aC2, i2, sz); | |
| 336 | - ensure_line_end(pOut, useCrLf); | |
| 337 | - blob_append(pOut, mergeMarker[3], -1); | |
| 338 | - ensure_line_end(pOut, useCrLf); | |
| 337 | + | |
| 338 | + append_merge_mark(pOut, 0, ln1, useCrLf); | |
| 339 | + i1 = output_one_side(pOut, pV1, aC1, i1, sz, &ln1); | |
| 340 | + | |
| 341 | + append_merge_mark(pOut, 1, lnPivot, useCrLf); | |
| 342 | + blob_copy_lines(pOut, pPivot, sz); lnPivot += sz; | |
| 343 | + | |
| 344 | + append_merge_mark(pOut, 2, ln2, useCrLf); | |
| 345 | + i2 = output_one_side(pOut, pV2, aC2, i2, sz, &ln2); | |
| 346 | + | |
| 347 | + append_merge_mark(pOut, 3, -1, useCrLf); | |
| 339 | 348 | } |
| 340 | 349 | |
| 341 | 350 | /* If we are finished with an edit triple, advance to the next |
| 342 | 351 | ** triple. |
| 343 | 352 | */ |
| @@ -378,12 +387,13 @@ | ||
| 378 | 387 | assert( len==(int)strlen(mergeMarker[2]) ); |
| 379 | 388 | assert( len==(int)strlen(mergeMarker[3]) ); |
| 380 | 389 | assert( count(mergeMarker)==4 ); |
| 381 | 390 | for(i=0; i<n; ){ |
| 382 | 391 | for(j=0; j<4; j++){ |
| 383 | - if( (memcmp(&z[i], mergeMarker[j], len)==0) | |
| 384 | - && (i+1==n || z[i+len]=='\n' || z[i+len]=='\r') ) return 1; | |
| 392 | + if( (memcmp(&z[i], mergeMarker[j], len)==0) ){ | |
| 393 | + return 1; | |
| 394 | + } | |
| 385 | 395 | } |
| 386 | 396 | while( i<n && z[i]!='\n' ){ i++; } |
| 387 | 397 | while( i<n && (z[i]=='\n' || z[i]=='\r') ){ i++; } |
| 388 | 398 | } |
| 389 | 399 | return 0; |
| 390 | 400 |
| --- src/merge3.c | |
| +++ src/merge3.c | |
| @@ -116,21 +116,22 @@ | |
| 116 | static int output_one_side( |
| 117 | Blob *pOut, /* Write to this blob */ |
| 118 | Blob *pSrc, /* The edited file that is to be copied to pOut */ |
| 119 | int *aC, /* Array of integer triples describing the edit */ |
| 120 | int i, /* Index in aC[] of current location in pSrc */ |
| 121 | int sz /* Number of lines in unedited source to output */ |
| 122 | ){ |
| 123 | while( sz>0 ){ |
| 124 | if( aC[i]==0 && aC[i+1]==0 && aC[i+2]==0 ) break; |
| 125 | if( aC[i]>=sz ){ |
| 126 | blob_copy_lines(pOut, pSrc, sz); |
| 127 | aC[i] -= sz; |
| 128 | break; |
| 129 | } |
| 130 | blob_copy_lines(pOut, pSrc, aC[i]); |
| 131 | blob_copy_lines(pOut, pSrc, aC[i+2]); |
| 132 | sz -= aC[i] + aC[i+1]; |
| 133 | i += 3; |
| 134 | } |
| 135 | return i; |
| 136 | } |
| @@ -138,14 +139,14 @@ | |
| 138 | /* |
| 139 | ** Text of boundary markers for merge conflicts. |
| 140 | */ |
| 141 | static const char *const mergeMarker[] = { |
| 142 | /*123456789 123456789 123456789 123456789 123456789 123456789 123456789*/ |
| 143 | "<<<<<<< BEGIN MERGE CONFLICT: local copy shown first <<<<<<<<<<<<<<<", |
| 144 | "||||||| COMMON ANCESTOR content follows ||||||||||||||||||||||||||||", |
| 145 | "======= MERGED IN content follows ==================================", |
| 146 | ">>>>>>> END MERGE CONFLICT >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>" |
| 147 | }; |
| 148 | |
| 149 | /* |
| 150 | ** Return true if the input blob contains any CR/LF pairs on the first |
| 151 | ** ten lines. This should be enough to detect files that use mainly CR/LF |
| @@ -175,10 +176,20 @@ | |
| 175 | if( pBlob->aData[pBlob->nUsed-1]!='\n' ){ |
| 176 | if( useCrLf ) blob_append_char(pBlob, '\r'); |
| 177 | blob_append_char(pBlob, '\n'); |
| 178 | } |
| 179 | } |
| 180 | |
| 181 | /* |
| 182 | ** Do a three-way merge. Initialize pOut to contain the result. |
| 183 | ** |
| 184 | ** The merge is an edit against pV2. Both pV1 and pV2 have a |
| @@ -196,10 +207,11 @@ | |
| 196 | int i1, i2; /* Index into aC1[] and aC2[] */ |
| 197 | int nCpy, nDel, nIns; /* Number of lines to copy, delete, or insert */ |
| 198 | int limit1, limit2; /* Sizes of aC1[] and aC2[] */ |
| 199 | int nConflict = 0; /* Number of merge conflicts seen so far */ |
| 200 | int useCrLf = 0; |
| 201 | DiffConfig DCfg; |
| 202 | |
| 203 | blob_zero(pOut); /* Merge results stored in pOut */ |
| 204 | |
| 205 | /* If both pV1 and pV2 start with a UTF-8 byte-order-mark (BOM), |
| @@ -259,56 +271,57 @@ | |
| 259 | ** which is written into pOut. i1 and i2 are multiples of 3 which are |
| 260 | ** indices into aC1[] and aC2[] to the edit triple currently being |
| 261 | ** processed |
| 262 | */ |
| 263 | i1 = i2 = 0; |
| 264 | while( i1<limit1 && i2<limit2 ){ |
| 265 | DEBUG( printf("%d: %2d %2d %2d %d: %2d %2d %2d\n", |
| 266 | i1/3, aC1[i1], aC1[i1+1], aC1[i1+2], |
| 267 | i2/3, aC2[i2], aC2[i2+1], aC2[i2+2]); ) |
| 268 | |
| 269 | if( aC1[i1]>0 && aC2[i2]>0 ){ |
| 270 | /* Output text that is unchanged in both V1 and V2 */ |
| 271 | nCpy = min(aC1[i1], aC2[i2]); |
| 272 | DEBUG( printf("COPY %d\n", nCpy); ) |
| 273 | blob_copy_lines(pOut, pPivot, nCpy); |
| 274 | blob_copy_lines(0, pV1, nCpy); |
| 275 | blob_copy_lines(0, pV2, nCpy); |
| 276 | aC1[i1] -= nCpy; |
| 277 | aC2[i2] -= nCpy; |
| 278 | }else |
| 279 | if( aC1[i1] >= aC2[i2+1] && aC1[i1]>0 && aC2[i2+1]+aC2[i2+2]>0 ){ |
| 280 | /* Output edits to V2 that occurs within unchanged regions of V1 */ |
| 281 | nDel = aC2[i2+1]; |
| 282 | nIns = aC2[i2+2]; |
| 283 | DEBUG( printf("EDIT -%d+%d left\n", nDel, nIns); ) |
| 284 | blob_copy_lines(0, pPivot, nDel); |
| 285 | blob_copy_lines(0, pV1, nDel); |
| 286 | blob_copy_lines(pOut, pV2, nIns); |
| 287 | aC1[i1] -= nDel; |
| 288 | i2 += 3; |
| 289 | }else |
| 290 | if( aC2[i2] >= aC1[i1+1] && aC2[i2]>0 && aC1[i1+1]+aC1[i1+2]>0 ){ |
| 291 | /* Output edits to V1 that occur within unchanged regions of V2 */ |
| 292 | nDel = aC1[i1+1]; |
| 293 | nIns = aC1[i1+2]; |
| 294 | DEBUG( printf("EDIT -%d+%d right\n", nDel, nIns); ) |
| 295 | blob_copy_lines(0, pPivot, nDel); |
| 296 | blob_copy_lines(0, pV2, nDel); |
| 297 | blob_copy_lines(pOut, pV1, nIns); |
| 298 | aC2[i2] -= nDel; |
| 299 | i1 += 3; |
| 300 | }else |
| 301 | if( sameEdit(&aC1[i1], &aC2[i2], pV1, pV2) ){ |
| 302 | /* Output edits that are identical in both V1 and V2. */ |
| 303 | assert( aC1[i1]==0 ); |
| 304 | nDel = aC1[i1+1]; |
| 305 | nIns = aC1[i1+2]; |
| 306 | DEBUG( printf("EDIT -%d+%d both\n", nDel, nIns); ) |
| 307 | blob_copy_lines(0, pPivot, nDel); |
| 308 | blob_copy_lines(pOut, pV1, nIns); |
| 309 | blob_copy_lines(0, pV2, nIns); |
| 310 | i1 += 3; |
| 311 | i2 += 3; |
| 312 | }else |
| 313 | { |
| 314 | /* We have found a region where different edits to V1 and V2 overlap. |
| @@ -319,25 +332,21 @@ | |
| 319 | nConflict++; |
| 320 | while( !ends_at_CPY(&aC1[i1], sz) || !ends_at_CPY(&aC2[i2], sz) ){ |
| 321 | sz++; |
| 322 | } |
| 323 | DEBUG( printf("CONFLICT %d\n", sz); ) |
| 324 | ensure_line_end(pOut, useCrLf); |
| 325 | blob_append(pOut, mergeMarker[0], -1); |
| 326 | ensure_line_end(pOut, useCrLf); |
| 327 | i1 = output_one_side(pOut, pV1, aC1, i1, sz); |
| 328 | ensure_line_end(pOut, useCrLf); |
| 329 | blob_append(pOut, mergeMarker[1], -1); |
| 330 | ensure_line_end(pOut, useCrLf); |
| 331 | blob_copy_lines(pOut, pPivot, sz); |
| 332 | ensure_line_end(pOut, useCrLf); |
| 333 | blob_append(pOut, mergeMarker[2], -1); |
| 334 | ensure_line_end(pOut, useCrLf); |
| 335 | i2 = output_one_side(pOut, pV2, aC2, i2, sz); |
| 336 | ensure_line_end(pOut, useCrLf); |
| 337 | blob_append(pOut, mergeMarker[3], -1); |
| 338 | ensure_line_end(pOut, useCrLf); |
| 339 | } |
| 340 | |
| 341 | /* If we are finished with an edit triple, advance to the next |
| 342 | ** triple. |
| 343 | */ |
| @@ -378,12 +387,13 @@ | |
| 378 | assert( len==(int)strlen(mergeMarker[2]) ); |
| 379 | assert( len==(int)strlen(mergeMarker[3]) ); |
| 380 | assert( count(mergeMarker)==4 ); |
| 381 | for(i=0; i<n; ){ |
| 382 | for(j=0; j<4; j++){ |
| 383 | if( (memcmp(&z[i], mergeMarker[j], len)==0) |
| 384 | && (i+1==n || z[i+len]=='\n' || z[i+len]=='\r') ) return 1; |
| 385 | } |
| 386 | while( i<n && z[i]!='\n' ){ i++; } |
| 387 | while( i<n && (z[i]=='\n' || z[i]=='\r') ){ i++; } |
| 388 | } |
| 389 | return 0; |
| 390 |
| --- src/merge3.c | |
| +++ src/merge3.c | |
| @@ -116,21 +116,22 @@ | |
| 116 | static int output_one_side( |
| 117 | Blob *pOut, /* Write to this blob */ |
| 118 | Blob *pSrc, /* The edited file that is to be copied to pOut */ |
| 119 | int *aC, /* Array of integer triples describing the edit */ |
| 120 | int i, /* Index in aC[] of current location in pSrc */ |
| 121 | int sz, /* Number of lines in unedited source to output */ |
| 122 | int *pLn /* Line number counter */ |
| 123 | ){ |
| 124 | while( sz>0 ){ |
| 125 | if( aC[i]==0 && aC[i+1]==0 && aC[i+2]==0 ) break; |
| 126 | if( aC[i]>=sz ){ |
| 127 | blob_copy_lines(pOut, pSrc, sz); *pLn += sz; |
| 128 | aC[i] -= sz; |
| 129 | break; |
| 130 | } |
| 131 | blob_copy_lines(pOut, pSrc, aC[i]); *pLn += aC[i]; |
| 132 | blob_copy_lines(pOut, pSrc, aC[i+2]); *pLn += aC[i+2]; |
| 133 | sz -= aC[i] + aC[i+1]; |
| 134 | i += 3; |
| 135 | } |
| 136 | return i; |
| 137 | } |
| @@ -138,14 +139,14 @@ | |
| 139 | /* |
| 140 | ** Text of boundary markers for merge conflicts. |
| 141 | */ |
| 142 | static const char *const mergeMarker[] = { |
| 143 | /*123456789 123456789 123456789 123456789 123456789 123456789 123456789*/ |
| 144 | "<<<<<<< BEGIN MERGE CONFLICT: local copy shown first <<<<<<<<<<<<", |
| 145 | "||||||| COMMON ANCESTOR content follows |||||||||||||||||||||||||", |
| 146 | "======= MERGED IN content follows ===============================", |
| 147 | ">>>>>>> END MERGE CONFLICT >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>" |
| 148 | }; |
| 149 | |
| 150 | /* |
| 151 | ** Return true if the input blob contains any CR/LF pairs on the first |
| 152 | ** ten lines. This should be enough to detect files that use mainly CR/LF |
| @@ -175,10 +176,20 @@ | |
| 176 | if( pBlob->aData[pBlob->nUsed-1]!='\n' ){ |
| 177 | if( useCrLf ) blob_append_char(pBlob, '\r'); |
| 178 | blob_append_char(pBlob, '\n'); |
| 179 | } |
| 180 | } |
| 181 | |
| 182 | /* |
| 183 | ** Write out one of the four merge-marks. |
| 184 | */ |
| 185 | void append_merge_mark(Blob *pOut, int iMark, int ln, int useCrLf){ |
| 186 | ensure_line_end(pOut, useCrLf); |
| 187 | blob_append(pOut, mergeMarker[iMark], -1); |
| 188 | if( ln>0 ) blob_appendf(pOut, " (line %d)", ln); |
| 189 | ensure_line_end(pOut, useCrLf); |
| 190 | } |
| 191 | |
| 192 | /* |
| 193 | ** Do a three-way merge. Initialize pOut to contain the result. |
| 194 | ** |
| 195 | ** The merge is an edit against pV2. Both pV1 and pV2 have a |
| @@ -196,10 +207,11 @@ | |
| 207 | int i1, i2; /* Index into aC1[] and aC2[] */ |
| 208 | int nCpy, nDel, nIns; /* Number of lines to copy, delete, or insert */ |
| 209 | int limit1, limit2; /* Sizes of aC1[] and aC2[] */ |
| 210 | int nConflict = 0; /* Number of merge conflicts seen so far */ |
| 211 | int useCrLf = 0; |
| 212 | int ln1, ln2, lnPivot; /* Line numbers for all files */ |
| 213 | DiffConfig DCfg; |
| 214 | |
| 215 | blob_zero(pOut); /* Merge results stored in pOut */ |
| 216 | |
| 217 | /* If both pV1 and pV2 start with a UTF-8 byte-order-mark (BOM), |
| @@ -259,56 +271,57 @@ | |
| 271 | ** which is written into pOut. i1 and i2 are multiples of 3 which are |
| 272 | ** indices into aC1[] and aC2[] to the edit triple currently being |
| 273 | ** processed |
| 274 | */ |
| 275 | i1 = i2 = 0; |
| 276 | ln1 = ln2 = lnPivot = 1; |
| 277 | while( i1<limit1 && i2<limit2 ){ |
| 278 | DEBUG( printf("%d: %2d %2d %2d %d: %2d %2d %2d\n", |
| 279 | i1/3, aC1[i1], aC1[i1+1], aC1[i1+2], |
| 280 | i2/3, aC2[i2], aC2[i2+1], aC2[i2+2]); ) |
| 281 | |
| 282 | if( aC1[i1]>0 && aC2[i2]>0 ){ |
| 283 | /* Output text that is unchanged in both V1 and V2 */ |
| 284 | nCpy = min(aC1[i1], aC2[i2]); |
| 285 | DEBUG( printf("COPY %d\n", nCpy); ) |
| 286 | blob_copy_lines(pOut, pPivot, nCpy); lnPivot += nCpy; |
| 287 | blob_copy_lines(0, pV1, nCpy); ln1 += nCpy; |
| 288 | blob_copy_lines(0, pV2, nCpy); ln2 += nCpy; |
| 289 | aC1[i1] -= nCpy; |
| 290 | aC2[i2] -= nCpy; |
| 291 | }else |
| 292 | if( aC1[i1] >= aC2[i2+1] && aC1[i1]>0 && aC2[i2+1]+aC2[i2+2]>0 ){ |
| 293 | /* Output edits to V2 that occurs within unchanged regions of V1 */ |
| 294 | nDel = aC2[i2+1]; |
| 295 | nIns = aC2[i2+2]; |
| 296 | DEBUG( printf("EDIT -%d+%d left\n", nDel, nIns); ) |
| 297 | blob_copy_lines(0, pPivot, nDel); lnPivot += nDel; |
| 298 | blob_copy_lines(0, pV1, nDel); ln1 += nDel; |
| 299 | blob_copy_lines(pOut, pV2, nIns); ln2 += nIns; |
| 300 | aC1[i1] -= nDel; |
| 301 | i2 += 3; |
| 302 | }else |
| 303 | if( aC2[i2] >= aC1[i1+1] && aC2[i2]>0 && aC1[i1+1]+aC1[i1+2]>0 ){ |
| 304 | /* Output edits to V1 that occur within unchanged regions of V2 */ |
| 305 | nDel = aC1[i1+1]; |
| 306 | nIns = aC1[i1+2]; |
| 307 | DEBUG( printf("EDIT -%d+%d right\n", nDel, nIns); ) |
| 308 | blob_copy_lines(0, pPivot, nDel); lnPivot += nDel; |
| 309 | blob_copy_lines(0, pV2, nDel); ln2 += nDel; |
| 310 | blob_copy_lines(pOut, pV1, nIns); ln1 += nIns; |
| 311 | aC2[i2] -= nDel; |
| 312 | i1 += 3; |
| 313 | }else |
| 314 | if( sameEdit(&aC1[i1], &aC2[i2], pV1, pV2) ){ |
| 315 | /* Output edits that are identical in both V1 and V2. */ |
| 316 | assert( aC1[i1]==0 ); |
| 317 | nDel = aC1[i1+1]; |
| 318 | nIns = aC1[i1+2]; |
| 319 | DEBUG( printf("EDIT -%d+%d both\n", nDel, nIns); ) |
| 320 | blob_copy_lines(0, pPivot, nDel); lnPivot += nDel; |
| 321 | blob_copy_lines(pOut, pV1, nIns); ln1 += nIns; |
| 322 | blob_copy_lines(0, pV2, nIns); ln2 += nIns; |
| 323 | i1 += 3; |
| 324 | i2 += 3; |
| 325 | }else |
| 326 | { |
| 327 | /* We have found a region where different edits to V1 and V2 overlap. |
| @@ -319,25 +332,21 @@ | |
| 332 | nConflict++; |
| 333 | while( !ends_at_CPY(&aC1[i1], sz) || !ends_at_CPY(&aC2[i2], sz) ){ |
| 334 | sz++; |
| 335 | } |
| 336 | DEBUG( printf("CONFLICT %d\n", sz); ) |
| 337 | |
| 338 | append_merge_mark(pOut, 0, ln1, useCrLf); |
| 339 | i1 = output_one_side(pOut, pV1, aC1, i1, sz, &ln1); |
| 340 | |
| 341 | append_merge_mark(pOut, 1, lnPivot, useCrLf); |
| 342 | blob_copy_lines(pOut, pPivot, sz); lnPivot += sz; |
| 343 | |
| 344 | append_merge_mark(pOut, 2, ln2, useCrLf); |
| 345 | i2 = output_one_side(pOut, pV2, aC2, i2, sz, &ln2); |
| 346 | |
| 347 | append_merge_mark(pOut, 3, -1, useCrLf); |
| 348 | } |
| 349 | |
| 350 | /* If we are finished with an edit triple, advance to the next |
| 351 | ** triple. |
| 352 | */ |
| @@ -378,12 +387,13 @@ | |
| 387 | assert( len==(int)strlen(mergeMarker[2]) ); |
| 388 | assert( len==(int)strlen(mergeMarker[3]) ); |
| 389 | assert( count(mergeMarker)==4 ); |
| 390 | for(i=0; i<n; ){ |
| 391 | for(j=0; j<4; j++){ |
| 392 | if( (memcmp(&z[i], mergeMarker[j], len)==0) ){ |
| 393 | return 1; |
| 394 | } |
| 395 | } |
| 396 | while( i<n && z[i]!='\n' ){ i++; } |
| 397 | while( i<n && (z[i]=='\n' || z[i]=='\r') ){ i++; } |
| 398 | } |
| 399 | return 0; |
| 400 |