Fossil SCM

Improvements to the new merge display.

drh 2024-12-03 01:06 merge-enhancements
Commit 7002d98d7373dab303dd8be5d7fe80e29c7d5b3209a87ffaa388e428a6cef579
2 files changed +15 -10 +69 -47
+15 -10
--- src/merge.tcl
+++ src/merge.tcl
@@ -126,38 +126,39 @@
126126
continue
127127
}
128128
set key2 [string index $B 0]
129129
set key3 [string index $C 0]
130130
set key4 [string index $D 0]
131
+ if {$key4=="X"} {set dtag rm} {set dtag -}
131132
if {$key1=="."} {
132133
.lnA insert end \n -
133
- .txtA insert end \n -
134
+ .txtA insert end \n $dtag
134135
} else {
135136
.lnA insert end $lnA\n -
136137
incr lnA
137
- .txtA insert end [string range $A 1 end]\n -
138
+ .txtA insert end [string range $A 1 end]\n $dtag
138139
}
139140
if {$key2=="."} {
140141
.lnB insert end \n -
141
- .txtB insert end \n -
142
+ .txtB insert end \n $dtag
142143
} else {
143144
.lnB insert end $lnB\n -
144145
incr lnB
145
- if {$key4=="2"} {set tag chng} {set tag -}
146
+ if {$key4=="2"} {set tag chng} {set tag $dtag}
146147
if {$key2=="1"} {
147148
.txtB insert end [string range $A 1 end]\n $tag
148149
} else {
149150
.txtB insert end [string range $B 1 end]\n $tag
150151
}
151152
}
152153
if {$key3=="."} {
153154
.lnC insert end \n -
154
- .txtC insert end \n -
155
+ .txtC insert end \n $dtag
155156
} else {
156157
.lnC insert end $lnC\n -
157158
incr lnC
158
- if {$key4=="3"} {set tag add} {set tag -}
159
+ if {$key4=="3"} {set tag add} {set tag $dtag}
159160
if {$key3=="1"} {
160161
.txtC insert end [string range $A 1 end]\n $tag
161162
} elseif {$key3=="2"} {
162163
.txtC insert end [string range $B 1 end]\n $tag
163164
} else {
@@ -164,11 +165,11 @@
164165
.txtC insert end [string range $C 1 end]\n $tag
165166
}
166167
}
167168
if {$key4=="."} {
168169
.lnD insert end \n -
169
- .txtD insert end \n -
170
+ .txtD insert end \n $dtag
170171
} else {
171172
.lnD insert end $lnD\n -
172173
incr lnD
173174
if {$key4=="1"} {
174175
.txtD insert end [string range $A 1 end]\n -
@@ -481,13 +482,17 @@
481482
::ttk::button .bb.search -text {Search} -command searchOnOff
482483
pack .bb.quit -side left
483484
if {$fossilcmd!=""} {pack .bb.save -side left}
484485
pack .bb.files .bb.search -side left
485486
grid rowconfigure . 1 -weight 1
486
-grid columnconfigure . 1 -weight 1
487
-grid columnconfigure . 4 -weight 1
488
-grid .bb -row 0 -columnspan 6
487
+set rn 0
488
+foreach {lnwid txtwid} [cols] {
489
+ grid columnconfigure . $rn -weight 1 -uniform a
490
+ grid columnconfigure . [expr {$rn+1}] -weight 1 -uniform b
491
+ incr rn 2
492
+}
493
+grid .bb -row 0 -columnspan 8
489494
eval grid [cols] -row 1 -sticky nsew
490495
grid .sby -row 1 -column 8 -sticky ns
491496
grid .sbxA -row 2 -columnspan 2 -sticky ew
492497
grid .spacer -row 2 -column 2
493498
grid .sbxB -row 2 -column 3 -columnspan 2 -sticky ew
494499
--- src/merge.tcl
+++ src/merge.tcl
@@ -126,38 +126,39 @@
126 continue
127 }
128 set key2 [string index $B 0]
129 set key3 [string index $C 0]
130 set key4 [string index $D 0]
 
131 if {$key1=="."} {
132 .lnA insert end \n -
133 .txtA insert end \n -
134 } else {
135 .lnA insert end $lnA\n -
136 incr lnA
137 .txtA insert end [string range $A 1 end]\n -
138 }
139 if {$key2=="."} {
140 .lnB insert end \n -
141 .txtB insert end \n -
142 } else {
143 .lnB insert end $lnB\n -
144 incr lnB
145 if {$key4=="2"} {set tag chng} {set tag -}
146 if {$key2=="1"} {
147 .txtB insert end [string range $A 1 end]\n $tag
148 } else {
149 .txtB insert end [string range $B 1 end]\n $tag
150 }
151 }
152 if {$key3=="."} {
153 .lnC insert end \n -
154 .txtC insert end \n -
155 } else {
156 .lnC insert end $lnC\n -
157 incr lnC
158 if {$key4=="3"} {set tag add} {set tag -}
159 if {$key3=="1"} {
160 .txtC insert end [string range $A 1 end]\n $tag
161 } elseif {$key3=="2"} {
162 .txtC insert end [string range $B 1 end]\n $tag
163 } else {
@@ -164,11 +165,11 @@
164 .txtC insert end [string range $C 1 end]\n $tag
165 }
166 }
167 if {$key4=="."} {
168 .lnD insert end \n -
169 .txtD insert end \n -
170 } else {
171 .lnD insert end $lnD\n -
172 incr lnD
173 if {$key4=="1"} {
174 .txtD insert end [string range $A 1 end]\n -
@@ -481,13 +482,17 @@
481 ::ttk::button .bb.search -text {Search} -command searchOnOff
482 pack .bb.quit -side left
483 if {$fossilcmd!=""} {pack .bb.save -side left}
484 pack .bb.files .bb.search -side left
485 grid rowconfigure . 1 -weight 1
486 grid columnconfigure . 1 -weight 1
487 grid columnconfigure . 4 -weight 1
488 grid .bb -row 0 -columnspan 6
 
 
 
 
489 eval grid [cols] -row 1 -sticky nsew
490 grid .sby -row 1 -column 8 -sticky ns
491 grid .sbxA -row 2 -columnspan 2 -sticky ew
492 grid .spacer -row 2 -column 2
493 grid .sbxB -row 2 -column 3 -columnspan 2 -sticky ew
494
--- src/merge.tcl
+++ src/merge.tcl
@@ -126,38 +126,39 @@
126 continue
127 }
128 set key2 [string index $B 0]
129 set key3 [string index $C 0]
130 set key4 [string index $D 0]
131 if {$key4=="X"} {set dtag rm} {set dtag -}
132 if {$key1=="."} {
133 .lnA insert end \n -
134 .txtA insert end \n $dtag
135 } else {
136 .lnA insert end $lnA\n -
137 incr lnA
138 .txtA insert end [string range $A 1 end]\n $dtag
139 }
140 if {$key2=="."} {
141 .lnB insert end \n -
142 .txtB insert end \n $dtag
143 } else {
144 .lnB insert end $lnB\n -
145 incr lnB
146 if {$key4=="2"} {set tag chng} {set tag $dtag}
147 if {$key2=="1"} {
148 .txtB insert end [string range $A 1 end]\n $tag
149 } else {
150 .txtB insert end [string range $B 1 end]\n $tag
151 }
152 }
153 if {$key3=="."} {
154 .lnC insert end \n -
155 .txtC insert end \n $dtag
156 } else {
157 .lnC insert end $lnC\n -
158 incr lnC
159 if {$key4=="3"} {set tag add} {set tag $dtag}
160 if {$key3=="1"} {
161 .txtC insert end [string range $A 1 end]\n $tag
162 } elseif {$key3=="2"} {
163 .txtC insert end [string range $B 1 end]\n $tag
164 } else {
@@ -164,11 +165,11 @@
165 .txtC insert end [string range $C 1 end]\n $tag
166 }
167 }
168 if {$key4=="."} {
169 .lnD insert end \n -
170 .txtD insert end \n $dtag
171 } else {
172 .lnD insert end $lnD\n -
173 incr lnD
174 if {$key4=="1"} {
175 .txtD insert end [string range $A 1 end]\n -
@@ -481,13 +482,17 @@
482 ::ttk::button .bb.search -text {Search} -command searchOnOff
483 pack .bb.quit -side left
484 if {$fossilcmd!=""} {pack .bb.save -side left}
485 pack .bb.files .bb.search -side left
486 grid rowconfigure . 1 -weight 1
487 set rn 0
488 foreach {lnwid txtwid} [cols] {
489 grid columnconfigure . $rn -weight 1 -uniform a
490 grid columnconfigure . [expr {$rn+1}] -weight 1 -uniform b
491 incr rn 2
492 }
493 grid .bb -row 0 -columnspan 8
494 eval grid [cols] -row 1 -sticky nsew
495 grid .sby -row 1 -column 8 -sticky ns
496 grid .sbxA -row 2 -columnspan 2 -sticky ew
497 grid .spacer -row 2 -column 2
498 grid .sbxB -row 2 -column 3 -columnspan 2 -sticky ew
499
+69 -47
--- src/merge3.c
+++ src/merge3.c
@@ -75,33 +75,10 @@
7575
if( aC1[2]!=aC2[2] ) return 0;
7676
if( sameLines(pV1, pV2, aC1[2]) ) return 1;
7777
return 0;
7878
}
7979
80
-/*
81
-** The aC[] array contains triples of integers. Within each triple, the
82
-** elements are:
83
-**
84
-** (0) The number of lines to copy
85
-** (1) The number of lines to delete
86
-** (2) The number of liens to insert
87
-**
88
-** Suppose we want to advance over sz lines of the original file. This routine
89
-** returns true if that advance would land us on a copy operation. It
90
-** returns false if the advance would end on a delete.
91
-*/
92
-static int ends_at_CPY(int *aC, int sz){
93
- while( sz>0 && (aC[0]>0 || aC[1]>0 || aC[2]>0) ){
94
- if( aC[0]>=sz ) return 1;
95
- sz -= aC[0];
96
- if( aC[1]>sz ) return 0;
97
- sz -= aC[1];
98
- aC += 3;
99
- }
100
- return 1;
101
-}
102
-
10380
/*
10481
** Text of boundary markers for merge conflicts.
10582
*/
10683
static const char *const mergeMarker[] = {
10784
/*123456789 123456789 123456789 123456789 123456789 123456789 123456789*/
@@ -178,10 +155,13 @@
178155
Blob *pV1; /* First variant */
179156
Blob *pV2; /* Second variant */
180157
Blob *pOut; /* Write merge results here */
181158
int useCrLf; /* Use CRLF line endings */
182159
int nContext; /* Size of unchanged line boundaries */
160
+ unsigned int mxPivot; /* Number of lines in the pivot */
161
+ unsigned int mxV1; /* Number of lines in V1 */
162
+ unsigned int mxV2; /* Number of lines in V2 */
183163
unsigned int lnPivot; /* Lines read from pivot */
184164
unsigned int lnV1; /* Lines read from v1 */
185165
unsigned int lnV2; /* Lines read from v2 */
186166
unsigned int lnOut; /* Lines written to out */
187167
unsigned int nConflict; /* Number of conflicts seen */
@@ -200,32 +180,34 @@
200180
static void dbgStartEnd(MergeBuilder *p){ (void)p; }
201181
202182
/* The next N lines of PIVOT are unchanged in both V1 and V2
203183
*/
204184
static void dbgSame(MergeBuilder *p, unsigned int N){
205
- blob_appendf(p->pOut, "COPY %u lines (%u..%u) FROM BASELINE\n",
206
- N, p->lnPivot, p->lnPivot+N-1);
185
+ blob_appendf(p->pOut,
186
+ "COPY %u from BASELINE(%u..%u) or V1(%u..%u) or V2(%u..%u)\n",
187
+ N, p->lnPivot+1, p->lnPivot+N, p->lnV1+1, p->lnV1+N,
188
+ p->lnV2+1, p->lnV2+N);
207189
p->lnPivot += N;
208190
p->lnV1 += N;
209191
p->lnV2 += N;
210192
}
211193
212194
/* The next nPivot lines of the PIVOT are changed into nV1 lines by V1
213195
*/
214196
static void dbgChngV1(MergeBuilder *p, unsigned int nPivot, unsigned int nV1){
215
- blob_appendf(p->pOut, "COPY %u lines (%u..%u) FROM V1\n",
216
- nV1, p->lnV1, p->lnV1+nV1-1);
197
+ blob_appendf(p->pOut, "COPY %u from V1(%u..%u)\n",
198
+ nV1, p->lnV1+1, p->lnV1+nV1);
217199
p->lnPivot += nPivot;
218200
p->lnV2 += nPivot;
219201
p->lnV1 += nV1;
220202
}
221203
222204
/* The next nPivot lines of the PIVOT are changed into nV2 lines by V2
223205
*/
224206
static void dbgChngV2(MergeBuilder *p, unsigned int nPivot, unsigned int nV2){
225
- blob_appendf(p->pOut, "COPY %u lines (%u..%u) FROM V2\n",
226
- nV2, p->lnV2, p->lnV2+nV2-1);
207
+ blob_appendf(p->pOut, "COPY %u lines FROM V2(%u..%u)\n",
208
+ nV2, p->lnV2+1, p->lnV2+nV2);
227209
p->lnPivot += nPivot;
228210
p->lnV1 += nPivot;
229211
p->lnV2 += nV2;
230212
}
231213
@@ -232,12 +214,12 @@
232214
/* The next nPivot lines of the PIVOT are changed into nV lines from V1 and
233215
** V2, which should be the same. In other words, the same change is found
234216
** in both V1 and V2.
235217
*/
236218
static void dbgChngBoth(MergeBuilder *p, unsigned int nPivot, unsigned int nV){
237
- blob_appendf(p->pOut, "COPY %u lines (%u..%u) FROM V1\n",
238
- nV, p->lnV1, p->lnV1+nV-1);
219
+ blob_appendf(p->pOut, "COPY %u lines from V1(%u..%u) or V2(%u..%u)\n",
220
+ nV, p->lnV1+1, p->lnV1+nV, p->lnV2+1, p->lnV2+nV);
239221
p->lnPivot += nPivot;
240222
p->lnV1 += nV;
241223
p->lnV2 += nV;
242224
}
243225
@@ -249,14 +231,15 @@
249231
unsigned int nPivot,
250232
unsigned int nV1,
251233
unsigned int nV2
252234
){
253235
blob_appendf(p->pOut,
254
- "CONFLICT BASELINE(%u..%u) versus V1(%u..%u) versus V2(%u..%u)\n",
255
- p->lnPivot, p->lnPivot+nPivot-1,
256
- p->lnV1, p->lnPivot+nV1-1,
257
- p->lnV2, p->lnPivot+nV2-1);
236
+ "CONFLICT %u,%u,%u BASELINE(%u..%u) versus V1(%u..%u) versus V2(%u..%u)\n",
237
+ nPivot, nV1, nV2,
238
+ p->lnPivot+1, p->lnPivot+nPivot,
239
+ p->lnV1+1, p->lnV1+nV1,
240
+ p->lnV2+1, p->lnV2+nV2);
258241
p->lnV1 += nV1;
259242
p->lnPivot += nPivot;
260243
p->lnV2 += nV2;
261244
}
262245
@@ -416,19 +399,23 @@
416399
if( nSkip>0 ){
417400
blob_appendf(p->pOut, "S%d . . .\n", nSkip);
418401
blob_copy_lines(0, p->pPivot, nSkip);
419402
i += nSkip;
420403
}
421
- while( i<N ){
422
- tclLineOfText(p->pOut, p->pPivot);
423
- blob_append(p->pOut, " 1 1 1\n", 7);
424
- i++;
425
- }
426404
427405
p->lnPivot += N;
428406
p->lnV1 += N;
429407
p->lnV2 += N;
408
+
409
+ if( p->lnPivot<p->mxPivot || p->lnV1<p->mxV1 || p->lnV2<p->mxV2 ){
410
+ while( i<N ){
411
+ tclLineOfText(p->pOut, p->pPivot);
412
+ blob_append(p->pOut, " 1 1 1\n", 7);
413
+ i++;
414
+ }
415
+ }
416
+
430417
blob_copy_lines(0, p->pV1, N);
431418
blob_copy_lines(0, p->pV2, N);
432419
}
433420
static void tclChngV1(MergeBuilder *p, unsigned int nPivot, unsigned int nV1){
434421
int i;
@@ -530,10 +517,13 @@
530517
}else{
531518
blob_append_char(p->pOut, '.');
532519
}
533520
blob_append(p->pOut, " X\n", 3);
534521
}
522
+ p->lnPivot += nPivot;
523
+ p->lnV1 += nV1;
524
+ p->lnV2 += nV2;
535525
}
536526
static void mergebuilder_init_tcl(MergeBuilder *p){
537527
mergebuilder_init(p);
538528
p->xSame = tclSame;
539529
p->xChngV1 = tclChngV1;
@@ -541,10 +531,33 @@
541531
p->xChngBoth = tclChngBoth;
542532
p->xConflict = tclConflict;
543533
p->nContext = 6;
544534
}
545535
/*****************************************************************************/
536
+
537
+/*
538
+** The aC[] array contains triples of integers. Within each triple, the
539
+** elements are:
540
+**
541
+** (0) The number of lines to copy
542
+** (1) The number of lines to delete
543
+** (2) The number of liens to insert
544
+**
545
+** Suppose we want to advance over sz lines of the original file. This routine
546
+** returns true if that advance would land us on a copy operation. It
547
+** returns false if the advance would end on a delete.
548
+*/
549
+static int ends_with_copy(int *aC, int sz){
550
+ while( sz>0 && (aC[0]>0 || aC[1]>0 || aC[2]>0) ){
551
+ if( aC[0]>=sz ) return 1;
552
+ sz -= aC[0];
553
+ if( aC[1]>sz ) return 0;
554
+ sz -= aC[1];
555
+ aC += 3;
556
+ }
557
+ return 1;
558
+}
546559
547560
/*
548561
** aC[] is an "edit triple" for changes from A to B. Advance through
549562
** this triple to determine the number of lines to bypass on B in order
550563
** to match an advance of sz lines on A.
@@ -558,10 +571,11 @@
558571
*pLn = 0;
559572
while( sz>0 ){
560573
if( aC[i]==0 && aC[i+1]==0 && aC[i+2]==0 ) break;
561574
if( aC[i]>=sz ){
562575
aC[i] -= sz;
576
+ *pLn += sz;
563577
break;
564578
}
565579
*pLn += aC[i];
566580
*pLn += aC[i+2];
567581
sz -= aC[i] + aC[i+1];
@@ -611,13 +625,21 @@
611625
blob_rewind(p->pV1); /* Rewind inputs: Needed to reconstruct output */
612626
blob_rewind(p->pV2);
613627
blob_rewind(p->pPivot);
614628
615629
/* Determine the length of the aC1[] and aC2[] change vectors */
616
- for(i1=0; aC1[i1] || aC1[i1+1] || aC1[i1+2]; i1+=3){}
630
+ p->mxPivot = 0;
631
+ p->mxV1 = 0;
632
+ for(i1=0; aC1[i1] || aC1[i1+1] || aC1[i1+2]; i1+=3){
633
+ p->mxPivot += aC1[i1] + aC1[i1+1];
634
+ p->mxV1 += aC1[i1] + aC1[i1+2];
635
+ }
617636
limit1 = i1;
618
- for(i2=0; aC2[i2] || aC2[i2+1] || aC2[i2+2]; i2+=3){}
637
+ p->mxV2 = 0;
638
+ for(i2=0; aC2[i2] || aC2[i2+1] || aC2[i2+2]; i2+=3){
639
+ p->mxV2 += aC2[i2] + aC2[i2+2];
640
+ }
619641
limit2 = i2;
620642
621643
/* Output header text and do any other required initialization */
622644
p->xStart(p);
623645
@@ -645,11 +667,11 @@
645667
}else
646668
if( aC2[i2] >= aC1[i1+1] && aC2[i2]>0 && aC1[i1+1]+aC1[i1+2]>0 ){
647669
/* Output edits to V1 that occur within unchanged regions of V2 */
648670
nDel = aC1[i1+1];
649671
nIns = aC1[i1+2];
650
- p->xChngV2(p, nDel, nIns);
672
+ p->xChngV1(p, nDel, nIns);
651673
aC2[i2] -= nDel;
652674
i1 += 3;
653675
}else
654676
if( sameEdit(&aC1[i1], &aC2[i2], p->pV1, p->pV2) ){
655677
/* Output edits that are identical in both V1 and V2. */
@@ -663,14 +685,14 @@
663685
{
664686
/* We have found a region where different edits to V1 and V2 overlap.
665687
** This is a merge conflict. Find the size of the conflict, then
666688
** output both possible edits separated by distinctive marks.
667689
*/
668
- unsigned int sz = 1; /* Size of the conflict in lines */
669
- unsigned int nV1, nV2;
690
+ unsigned int sz = 1; /* Size of the conflict in the pivot, in lines */
691
+ unsigned int nV1, nV2; /* Size of conflict in V1 and V2, in lines */
670692
nConflict++;
671
- while( !ends_at_CPY(&aC1[i1], sz) || !ends_at_CPY(&aC2[i2], sz) ){
693
+ while( !ends_with_copy(&aC1[i1], sz) || !ends_with_copy(&aC2[i2], sz) ){
672694
sz++;
673695
}
674696
i1 = skip_conflict(aC1, i1, sz, &nV1);
675697
i2 = skip_conflict(aC2, i2, sz, &nV2);
676698
p->xConflict(p, sz, nV1, nV2);
@@ -688,11 +710,11 @@
688710
** insert.
689711
*/
690712
if( i1<limit1 && aC1[i1+2]>0 ){
691713
p->xChngV1(p, 0, aC1[i1+2]);
692714
}else if( i2<limit2 && aC2[i2+2]>0 ){
693
- p->xChngV1(p, 0, aC2[i2+2]);
715
+ p->xChngV2(p, 0, aC2[i2+2]);
694716
}
695717
696718
/* Output footer text */
697719
p->xEnd(p);
698720
699721
--- src/merge3.c
+++ src/merge3.c
@@ -75,33 +75,10 @@
75 if( aC1[2]!=aC2[2] ) return 0;
76 if( sameLines(pV1, pV2, aC1[2]) ) return 1;
77 return 0;
78 }
79
80 /*
81 ** The aC[] array contains triples of integers. Within each triple, the
82 ** elements are:
83 **
84 ** (0) The number of lines to copy
85 ** (1) The number of lines to delete
86 ** (2) The number of liens to insert
87 **
88 ** Suppose we want to advance over sz lines of the original file. This routine
89 ** returns true if that advance would land us on a copy operation. It
90 ** returns false if the advance would end on a delete.
91 */
92 static int ends_at_CPY(int *aC, int sz){
93 while( sz>0 && (aC[0]>0 || aC[1]>0 || aC[2]>0) ){
94 if( aC[0]>=sz ) return 1;
95 sz -= aC[0];
96 if( aC[1]>sz ) return 0;
97 sz -= aC[1];
98 aC += 3;
99 }
100 return 1;
101 }
102
103 /*
104 ** Text of boundary markers for merge conflicts.
105 */
106 static const char *const mergeMarker[] = {
107 /*123456789 123456789 123456789 123456789 123456789 123456789 123456789*/
@@ -178,10 +155,13 @@
178 Blob *pV1; /* First variant */
179 Blob *pV2; /* Second variant */
180 Blob *pOut; /* Write merge results here */
181 int useCrLf; /* Use CRLF line endings */
182 int nContext; /* Size of unchanged line boundaries */
 
 
 
183 unsigned int lnPivot; /* Lines read from pivot */
184 unsigned int lnV1; /* Lines read from v1 */
185 unsigned int lnV2; /* Lines read from v2 */
186 unsigned int lnOut; /* Lines written to out */
187 unsigned int nConflict; /* Number of conflicts seen */
@@ -200,32 +180,34 @@
200 static void dbgStartEnd(MergeBuilder *p){ (void)p; }
201
202 /* The next N lines of PIVOT are unchanged in both V1 and V2
203 */
204 static void dbgSame(MergeBuilder *p, unsigned int N){
205 blob_appendf(p->pOut, "COPY %u lines (%u..%u) FROM BASELINE\n",
206 N, p->lnPivot, p->lnPivot+N-1);
 
 
207 p->lnPivot += N;
208 p->lnV1 += N;
209 p->lnV2 += N;
210 }
211
212 /* The next nPivot lines of the PIVOT are changed into nV1 lines by V1
213 */
214 static void dbgChngV1(MergeBuilder *p, unsigned int nPivot, unsigned int nV1){
215 blob_appendf(p->pOut, "COPY %u lines (%u..%u) FROM V1\n",
216 nV1, p->lnV1, p->lnV1+nV1-1);
217 p->lnPivot += nPivot;
218 p->lnV2 += nPivot;
219 p->lnV1 += nV1;
220 }
221
222 /* The next nPivot lines of the PIVOT are changed into nV2 lines by V2
223 */
224 static void dbgChngV2(MergeBuilder *p, unsigned int nPivot, unsigned int nV2){
225 blob_appendf(p->pOut, "COPY %u lines (%u..%u) FROM V2\n",
226 nV2, p->lnV2, p->lnV2+nV2-1);
227 p->lnPivot += nPivot;
228 p->lnV1 += nPivot;
229 p->lnV2 += nV2;
230 }
231
@@ -232,12 +214,12 @@
232 /* The next nPivot lines of the PIVOT are changed into nV lines from V1 and
233 ** V2, which should be the same. In other words, the same change is found
234 ** in both V1 and V2.
235 */
236 static void dbgChngBoth(MergeBuilder *p, unsigned int nPivot, unsigned int nV){
237 blob_appendf(p->pOut, "COPY %u lines (%u..%u) FROM V1\n",
238 nV, p->lnV1, p->lnV1+nV-1);
239 p->lnPivot += nPivot;
240 p->lnV1 += nV;
241 p->lnV2 += nV;
242 }
243
@@ -249,14 +231,15 @@
249 unsigned int nPivot,
250 unsigned int nV1,
251 unsigned int nV2
252 ){
253 blob_appendf(p->pOut,
254 "CONFLICT BASELINE(%u..%u) versus V1(%u..%u) versus V2(%u..%u)\n",
255 p->lnPivot, p->lnPivot+nPivot-1,
256 p->lnV1, p->lnPivot+nV1-1,
257 p->lnV2, p->lnPivot+nV2-1);
 
258 p->lnV1 += nV1;
259 p->lnPivot += nPivot;
260 p->lnV2 += nV2;
261 }
262
@@ -416,19 +399,23 @@
416 if( nSkip>0 ){
417 blob_appendf(p->pOut, "S%d . . .\n", nSkip);
418 blob_copy_lines(0, p->pPivot, nSkip);
419 i += nSkip;
420 }
421 while( i<N ){
422 tclLineOfText(p->pOut, p->pPivot);
423 blob_append(p->pOut, " 1 1 1\n", 7);
424 i++;
425 }
426
427 p->lnPivot += N;
428 p->lnV1 += N;
429 p->lnV2 += N;
 
 
 
 
 
 
 
 
 
430 blob_copy_lines(0, p->pV1, N);
431 blob_copy_lines(0, p->pV2, N);
432 }
433 static void tclChngV1(MergeBuilder *p, unsigned int nPivot, unsigned int nV1){
434 int i;
@@ -530,10 +517,13 @@
530 }else{
531 blob_append_char(p->pOut, '.');
532 }
533 blob_append(p->pOut, " X\n", 3);
534 }
 
 
 
535 }
536 static void mergebuilder_init_tcl(MergeBuilder *p){
537 mergebuilder_init(p);
538 p->xSame = tclSame;
539 p->xChngV1 = tclChngV1;
@@ -541,10 +531,33 @@
541 p->xChngBoth = tclChngBoth;
542 p->xConflict = tclConflict;
543 p->nContext = 6;
544 }
545 /*****************************************************************************/
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
546
547 /*
548 ** aC[] is an "edit triple" for changes from A to B. Advance through
549 ** this triple to determine the number of lines to bypass on B in order
550 ** to match an advance of sz lines on A.
@@ -558,10 +571,11 @@
558 *pLn = 0;
559 while( sz>0 ){
560 if( aC[i]==0 && aC[i+1]==0 && aC[i+2]==0 ) break;
561 if( aC[i]>=sz ){
562 aC[i] -= sz;
 
563 break;
564 }
565 *pLn += aC[i];
566 *pLn += aC[i+2];
567 sz -= aC[i] + aC[i+1];
@@ -611,13 +625,21 @@
611 blob_rewind(p->pV1); /* Rewind inputs: Needed to reconstruct output */
612 blob_rewind(p->pV2);
613 blob_rewind(p->pPivot);
614
615 /* Determine the length of the aC1[] and aC2[] change vectors */
616 for(i1=0; aC1[i1] || aC1[i1+1] || aC1[i1+2]; i1+=3){}
 
 
 
 
 
617 limit1 = i1;
618 for(i2=0; aC2[i2] || aC2[i2+1] || aC2[i2+2]; i2+=3){}
 
 
 
619 limit2 = i2;
620
621 /* Output header text and do any other required initialization */
622 p->xStart(p);
623
@@ -645,11 +667,11 @@
645 }else
646 if( aC2[i2] >= aC1[i1+1] && aC2[i2]>0 && aC1[i1+1]+aC1[i1+2]>0 ){
647 /* Output edits to V1 that occur within unchanged regions of V2 */
648 nDel = aC1[i1+1];
649 nIns = aC1[i1+2];
650 p->xChngV2(p, nDel, nIns);
651 aC2[i2] -= nDel;
652 i1 += 3;
653 }else
654 if( sameEdit(&aC1[i1], &aC2[i2], p->pV1, p->pV2) ){
655 /* Output edits that are identical in both V1 and V2. */
@@ -663,14 +685,14 @@
663 {
664 /* We have found a region where different edits to V1 and V2 overlap.
665 ** This is a merge conflict. Find the size of the conflict, then
666 ** output both possible edits separated by distinctive marks.
667 */
668 unsigned int sz = 1; /* Size of the conflict in lines */
669 unsigned int nV1, nV2;
670 nConflict++;
671 while( !ends_at_CPY(&aC1[i1], sz) || !ends_at_CPY(&aC2[i2], sz) ){
672 sz++;
673 }
674 i1 = skip_conflict(aC1, i1, sz, &nV1);
675 i2 = skip_conflict(aC2, i2, sz, &nV2);
676 p->xConflict(p, sz, nV1, nV2);
@@ -688,11 +710,11 @@
688 ** insert.
689 */
690 if( i1<limit1 && aC1[i1+2]>0 ){
691 p->xChngV1(p, 0, aC1[i1+2]);
692 }else if( i2<limit2 && aC2[i2+2]>0 ){
693 p->xChngV1(p, 0, aC2[i2+2]);
694 }
695
696 /* Output footer text */
697 p->xEnd(p);
698
699
--- src/merge3.c
+++ src/merge3.c
@@ -75,33 +75,10 @@
75 if( aC1[2]!=aC2[2] ) return 0;
76 if( sameLines(pV1, pV2, aC1[2]) ) return 1;
77 return 0;
78 }
79
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
80 /*
81 ** Text of boundary markers for merge conflicts.
82 */
83 static const char *const mergeMarker[] = {
84 /*123456789 123456789 123456789 123456789 123456789 123456789 123456789*/
@@ -178,10 +155,13 @@
155 Blob *pV1; /* First variant */
156 Blob *pV2; /* Second variant */
157 Blob *pOut; /* Write merge results here */
158 int useCrLf; /* Use CRLF line endings */
159 int nContext; /* Size of unchanged line boundaries */
160 unsigned int mxPivot; /* Number of lines in the pivot */
161 unsigned int mxV1; /* Number of lines in V1 */
162 unsigned int mxV2; /* Number of lines in V2 */
163 unsigned int lnPivot; /* Lines read from pivot */
164 unsigned int lnV1; /* Lines read from v1 */
165 unsigned int lnV2; /* Lines read from v2 */
166 unsigned int lnOut; /* Lines written to out */
167 unsigned int nConflict; /* Number of conflicts seen */
@@ -200,32 +180,34 @@
180 static void dbgStartEnd(MergeBuilder *p){ (void)p; }
181
182 /* The next N lines of PIVOT are unchanged in both V1 and V2
183 */
184 static void dbgSame(MergeBuilder *p, unsigned int N){
185 blob_appendf(p->pOut,
186 "COPY %u from BASELINE(%u..%u) or V1(%u..%u) or V2(%u..%u)\n",
187 N, p->lnPivot+1, p->lnPivot+N, p->lnV1+1, p->lnV1+N,
188 p->lnV2+1, p->lnV2+N);
189 p->lnPivot += N;
190 p->lnV1 += N;
191 p->lnV2 += N;
192 }
193
194 /* The next nPivot lines of the PIVOT are changed into nV1 lines by V1
195 */
196 static void dbgChngV1(MergeBuilder *p, unsigned int nPivot, unsigned int nV1){
197 blob_appendf(p->pOut, "COPY %u from V1(%u..%u)\n",
198 nV1, p->lnV1+1, p->lnV1+nV1);
199 p->lnPivot += nPivot;
200 p->lnV2 += nPivot;
201 p->lnV1 += nV1;
202 }
203
204 /* The next nPivot lines of the PIVOT are changed into nV2 lines by V2
205 */
206 static void dbgChngV2(MergeBuilder *p, unsigned int nPivot, unsigned int nV2){
207 blob_appendf(p->pOut, "COPY %u lines FROM V2(%u..%u)\n",
208 nV2, p->lnV2+1, p->lnV2+nV2);
209 p->lnPivot += nPivot;
210 p->lnV1 += nPivot;
211 p->lnV2 += nV2;
212 }
213
@@ -232,12 +214,12 @@
214 /* The next nPivot lines of the PIVOT are changed into nV lines from V1 and
215 ** V2, which should be the same. In other words, the same change is found
216 ** in both V1 and V2.
217 */
218 static void dbgChngBoth(MergeBuilder *p, unsigned int nPivot, unsigned int nV){
219 blob_appendf(p->pOut, "COPY %u lines from V1(%u..%u) or V2(%u..%u)\n",
220 nV, p->lnV1+1, p->lnV1+nV, p->lnV2+1, p->lnV2+nV);
221 p->lnPivot += nPivot;
222 p->lnV1 += nV;
223 p->lnV2 += nV;
224 }
225
@@ -249,14 +231,15 @@
231 unsigned int nPivot,
232 unsigned int nV1,
233 unsigned int nV2
234 ){
235 blob_appendf(p->pOut,
236 "CONFLICT %u,%u,%u BASELINE(%u..%u) versus V1(%u..%u) versus V2(%u..%u)\n",
237 nPivot, nV1, nV2,
238 p->lnPivot+1, p->lnPivot+nPivot,
239 p->lnV1+1, p->lnV1+nV1,
240 p->lnV2+1, p->lnV2+nV2);
241 p->lnV1 += nV1;
242 p->lnPivot += nPivot;
243 p->lnV2 += nV2;
244 }
245
@@ -416,19 +399,23 @@
399 if( nSkip>0 ){
400 blob_appendf(p->pOut, "S%d . . .\n", nSkip);
401 blob_copy_lines(0, p->pPivot, nSkip);
402 i += nSkip;
403 }
 
 
 
 
 
404
405 p->lnPivot += N;
406 p->lnV1 += N;
407 p->lnV2 += N;
408
409 if( p->lnPivot<p->mxPivot || p->lnV1<p->mxV1 || p->lnV2<p->mxV2 ){
410 while( i<N ){
411 tclLineOfText(p->pOut, p->pPivot);
412 blob_append(p->pOut, " 1 1 1\n", 7);
413 i++;
414 }
415 }
416
417 blob_copy_lines(0, p->pV1, N);
418 blob_copy_lines(0, p->pV2, N);
419 }
420 static void tclChngV1(MergeBuilder *p, unsigned int nPivot, unsigned int nV1){
421 int i;
@@ -530,10 +517,13 @@
517 }else{
518 blob_append_char(p->pOut, '.');
519 }
520 blob_append(p->pOut, " X\n", 3);
521 }
522 p->lnPivot += nPivot;
523 p->lnV1 += nV1;
524 p->lnV2 += nV2;
525 }
526 static void mergebuilder_init_tcl(MergeBuilder *p){
527 mergebuilder_init(p);
528 p->xSame = tclSame;
529 p->xChngV1 = tclChngV1;
@@ -541,10 +531,33 @@
531 p->xChngBoth = tclChngBoth;
532 p->xConflict = tclConflict;
533 p->nContext = 6;
534 }
535 /*****************************************************************************/
536
537 /*
538 ** The aC[] array contains triples of integers. Within each triple, the
539 ** elements are:
540 **
541 ** (0) The number of lines to copy
542 ** (1) The number of lines to delete
543 ** (2) The number of liens to insert
544 **
545 ** Suppose we want to advance over sz lines of the original file. This routine
546 ** returns true if that advance would land us on a copy operation. It
547 ** returns false if the advance would end on a delete.
548 */
549 static int ends_with_copy(int *aC, int sz){
550 while( sz>0 && (aC[0]>0 || aC[1]>0 || aC[2]>0) ){
551 if( aC[0]>=sz ) return 1;
552 sz -= aC[0];
553 if( aC[1]>sz ) return 0;
554 sz -= aC[1];
555 aC += 3;
556 }
557 return 1;
558 }
559
560 /*
561 ** aC[] is an "edit triple" for changes from A to B. Advance through
562 ** this triple to determine the number of lines to bypass on B in order
563 ** to match an advance of sz lines on A.
@@ -558,10 +571,11 @@
571 *pLn = 0;
572 while( sz>0 ){
573 if( aC[i]==0 && aC[i+1]==0 && aC[i+2]==0 ) break;
574 if( aC[i]>=sz ){
575 aC[i] -= sz;
576 *pLn += sz;
577 break;
578 }
579 *pLn += aC[i];
580 *pLn += aC[i+2];
581 sz -= aC[i] + aC[i+1];
@@ -611,13 +625,21 @@
625 blob_rewind(p->pV1); /* Rewind inputs: Needed to reconstruct output */
626 blob_rewind(p->pV2);
627 blob_rewind(p->pPivot);
628
629 /* Determine the length of the aC1[] and aC2[] change vectors */
630 p->mxPivot = 0;
631 p->mxV1 = 0;
632 for(i1=0; aC1[i1] || aC1[i1+1] || aC1[i1+2]; i1+=3){
633 p->mxPivot += aC1[i1] + aC1[i1+1];
634 p->mxV1 += aC1[i1] + aC1[i1+2];
635 }
636 limit1 = i1;
637 p->mxV2 = 0;
638 for(i2=0; aC2[i2] || aC2[i2+1] || aC2[i2+2]; i2+=3){
639 p->mxV2 += aC2[i2] + aC2[i2+2];
640 }
641 limit2 = i2;
642
643 /* Output header text and do any other required initialization */
644 p->xStart(p);
645
@@ -645,11 +667,11 @@
667 }else
668 if( aC2[i2] >= aC1[i1+1] && aC2[i2]>0 && aC1[i1+1]+aC1[i1+2]>0 ){
669 /* Output edits to V1 that occur within unchanged regions of V2 */
670 nDel = aC1[i1+1];
671 nIns = aC1[i1+2];
672 p->xChngV1(p, nDel, nIns);
673 aC2[i2] -= nDel;
674 i1 += 3;
675 }else
676 if( sameEdit(&aC1[i1], &aC2[i2], p->pV1, p->pV2) ){
677 /* Output edits that are identical in both V1 and V2. */
@@ -663,14 +685,14 @@
685 {
686 /* We have found a region where different edits to V1 and V2 overlap.
687 ** This is a merge conflict. Find the size of the conflict, then
688 ** output both possible edits separated by distinctive marks.
689 */
690 unsigned int sz = 1; /* Size of the conflict in the pivot, in lines */
691 unsigned int nV1, nV2; /* Size of conflict in V1 and V2, in lines */
692 nConflict++;
693 while( !ends_with_copy(&aC1[i1], sz) || !ends_with_copy(&aC2[i2], sz) ){
694 sz++;
695 }
696 i1 = skip_conflict(aC1, i1, sz, &nV1);
697 i2 = skip_conflict(aC2, i2, sz, &nV2);
698 p->xConflict(p, sz, nV1, nV2);
@@ -688,11 +710,11 @@
710 ** insert.
711 */
712 if( i1<limit1 && aC1[i1+2]>0 ){
713 p->xChngV1(p, 0, aC1[i1+2]);
714 }else if( i2<limit2 && aC2[i2+2]>0 ){
715 p->xChngV2(p, 0, aC2[i2+2]);
716 }
717
718 /* Output footer text */
719 p->xEnd(p);
720
721

Keyboard Shortcuts

Open search /
Next entry (timeline) j
Previous entry (timeline) k
Open focused entry Enter
Show this help ?
Toggle theme Top nav button