Fossil SCM

Rework the side-by-side diff so that it handles tab characters. Fix an off-by-one error in the line numbers of side-by-side diffs.

drh 2011-10-22 03:37 trunk
Commit 8670373321604573901fad634ef7fb2cef2ca46d
1 file changed +70 -51
+70 -51
--- src/diff.c
+++ src/diff.c
@@ -299,35 +299,40 @@
299299
}
300300
}
301301
}
302302
303303
/*
304
-** Append spaces to a blob
304
+** Write a 6-digit line number into the buffer z[]. z[] is guaranteed to
305
+** have space for at least 7 characters.
305306
*/
306
-static void appendSpace(Blob *pOut, int n){
307
- const char z100[101] =
308
- " "
309
- " ";
310
- while( n>100 ){
311
- blob_append(pOut, z100, 100); n -= 100;
312
- }
313
- if( n>0 ){
314
- blob_append(pOut, z100, n);
315
- }
307
+static void sbsWriteLineno(char *z, int ln){
308
+ sqlite3_snprintf(7, z, "%6d", ln+1);
309
+ z[6] = ' ';
316310
}
317311
318312
/*
319
-** Append text to a sbs diff output
313
+** Write up to width characters of pLine into z[]. Translate tabs into
314
+** spaces. If trunc is true, then append \n\000 after the last character
315
+** written.
320316
*/
321
-static void appendSbsLine(Blob *pOut, DLine *pLine, int width, int pad){
322
- int sz = pLine->h & LENGTH_MASK;
323
- if( sz<width ){
324
- blob_append(pOut, pLine->z, sz);
325
- if( pad ) appendSpace(pOut, width-sz);
326
- }else{
327
- blob_append(pOut, pLine->z, width);
328
- }
317
+static int sbsWriteText(char *z, DLine *pLine, int width, int trunc){
318
+ int n = pLine->h & LENGTH_MASK;
319
+ int i, j;
320
+ const char *zIn = pLine->z;
321
+ for(i=j=0; i<n && j<width; i++){
322
+ if( zIn[i]=='\t' ){
323
+ z[j++] = ' ';
324
+ while( (j&7)!=0 && j<width ) z[j++] = ' ';
325
+ }else{
326
+ z[j++] = zIn[i];
327
+ }
328
+ }
329
+ if( trunc ){
330
+ z[j++] = '\n';
331
+ z[j] = 0;
332
+ }
333
+ return j;
329334
}
330335
331336
332337
/*
333338
** Given a diff context in which the aEdit[] array has been filled
@@ -344,15 +349,18 @@
344349
int mxr; /* Maximum value for r */
345350
int na, nb; /* Number of lines shown from A and B */
346351
int i, j; /* Loop counters */
347352
int m, ma, mb;/* Number of lines to output */
348353
int skip; /* Number of lines to skip */
349
- char zFormat[50]; /* Output format */
354
+ int mxLine; /* Length of a line of text */
355
+ char *zLine; /* A line of text being formatted */
356
+ int len; /* Length of an output line */
350357
351
- sqlite3_snprintf(sizeof(zFormat), zFormat,
352
- "%%4d %%%d.%ds %%c %%4d %%.%ds\n",
353
- width, width, width);
358
+ mxLine = width*2 + 2*7 + 3 + 1;
359
+ zLine = fossil_malloc( mxLine + 1 );
360
+ if( zLine==0 ) return;
361
+ zLine[mxLine] = 0;
354362
A = p->aFrom;
355363
B = p->aTo;
356364
R = p->aEdit;
357365
mxr = p->nEdit;
358366
while( mxr>2 && R[mxr-1]==0 && R[mxr-2]==0 ){ mxr -= 3; }
@@ -396,15 +404,16 @@
396404
/* Show the initial common area */
397405
a += skip;
398406
b += skip;
399407
m = R[r] - skip;
400408
for(j=0; j<m; j++){
401
- blob_appendf(pOut, "%6d ", a+j);
402
- appendSbsLine(pOut, &A[a+j], width, 1);
403
- blob_appendf(pOut, " %6d ", b+j);
404
- appendSbsLine(pOut, &B[b+j], width, 0);
405
- blob_append(pOut, "\n", 1);
409
+ memset(zLine, ' ', mxLine);
410
+ sbsWriteLineno(zLine, a+j);
411
+ sbsWriteText(&zLine[7], &A[a+j], width, 0);
412
+ sbsWriteLineno(&zLine[width+10], b+j);
413
+ len = sbsWriteText(&zLine[width+17], &B[b+j], width, 1);
414
+ blob_append(pOut, zLine, len+width+17);
406415
}
407416
a += m;
408417
b += m;
409418
410419
/* Show the differences */
@@ -411,41 +420,49 @@
411420
for(i=0; i<nr; i++){
412421
ma = R[r+i*3+1];
413422
mb = R[r+i*3+2];
414423
m = ma<mb ? ma : mb;
415424
for(j=0; j<m; j++){
416
- blob_appendf(pOut, "%6d ", a+j);
417
- appendSbsLine(pOut, &A[a+j], width, 1);
418
- blob_appendf(pOut, " | %6d ", b+j);
419
- appendSbsLine(pOut, &B[b+j], width, 0);
420
- blob_append(pOut, "\n", 1);
425
+ memset(zLine, ' ', mxLine);
426
+ sbsWriteLineno(zLine, a+j);
427
+ sbsWriteText(&zLine[7], &A[a+j], width, 0);
428
+ zLine[width+8] = '|';
429
+ sbsWriteLineno(&zLine[width+10], b+j);
430
+ len = sbsWriteText(&zLine[width+17], &B[b+j], width, 1);
431
+ blob_append(pOut, zLine, len+width+17);
421432
}
422433
a += m;
423434
b += m;
424435
ma -= m;
425436
mb -= m;
426437
for(j=0; j<ma; j++){
427
- blob_appendf(pOut, "%6d ", a+j);
428
- appendSbsLine(pOut, &A[a+j], width, 1);
429
- blob_append(pOut, " <\n", 3);
438
+ memset(zLine, ' ', width+7);
439
+ sbsWriteLineno(zLine, a+j);
440
+ sbsWriteText(&zLine[7], &A[a+j], width, 0);
441
+ zLine[width+8] = '<';
442
+ zLine[width+9] = '\n';
443
+ zLine[width+10] = 0;
444
+ blob_append(pOut, zLine, width+10);
430445
}
431446
a += ma;
432447
for(j=0; j<mb; j++){
433
- appendSpace(pOut, width+7);
434
- blob_appendf(pOut, " > %6d ", b+j);
435
- appendSbsLine(pOut, &B[b+j], width, 0);
436
- blob_append(pOut, "\n", 1);
448
+ memset(zLine, ' ', mxLine);
449
+ zLine[width+8] = '>';
450
+ sbsWriteLineno(&zLine[width+10], b+j);
451
+ len = sbsWriteText(&zLine[width+17], &B[b+j], width, 1);
452
+ blob_append(pOut, zLine, len+width+17);
437453
}
438454
b += mb;
439455
if( i<nr-1 ){
440456
m = R[r+i*3+3];
441457
for(j=0; j<m; j++){
442
- blob_appendf(pOut, "%6d ", a+j);
443
- appendSbsLine(pOut, &A[a+j], width, 1);
444
- blob_appendf(pOut, " %6d ", b+j);
445
- appendSbsLine(pOut, &B[b+j], width, 0);
446
- blob_append(pOut, "\n", 1);
458
+ memset(zLine, ' ', mxLine);
459
+ sbsWriteLineno(zLine, a+j);
460
+ sbsWriteText(&zLine[7], &A[a+j], width, 0);
461
+ sbsWriteLineno(&zLine[width+10], b+j);
462
+ len = sbsWriteText(&zLine[width+17], &B[b+j], width, 1);
463
+ blob_append(pOut, zLine, len+width+17);
447464
}
448465
b += m;
449466
a += m;
450467
}
451468
}
@@ -453,17 +470,19 @@
453470
/* Show the final common area */
454471
assert( nr==i );
455472
m = R[r+nr*3];
456473
if( m>nContext ) m = nContext;
457474
for(j=0; j<m; j++){
458
- blob_appendf(pOut, "%6d ", a+j);
459
- appendSbsLine(pOut, &A[a+j], width, 1);
460
- blob_appendf(pOut, " %6d ", b+j);
461
- appendSbsLine(pOut, &B[b+j], width, 0);
462
- blob_append(pOut, "\n", 1);
475
+ memset(zLine, ' ', mxLine);
476
+ sbsWriteLineno(zLine, a+j);
477
+ sbsWriteText(&zLine[7], &A[a+j], width, 0);
478
+ sbsWriteLineno(&zLine[width+10], b+j);
479
+ len = sbsWriteText(&zLine[width+17], &B[b+j], width, 1);
480
+ blob_append(pOut, zLine, len+width+17);
463481
}
464482
}
483
+ free(zLine);
465484
}
466485
467486
/*
468487
** Compute the optimal longest common subsequence (LCS) using an
469488
** exhaustive search. This version of the LCS is only used for
470489
--- src/diff.c
+++ src/diff.c
@@ -299,35 +299,40 @@
299 }
300 }
301 }
302
303 /*
304 ** Append spaces to a blob
 
305 */
306 static void appendSpace(Blob *pOut, int n){
307 const char z100[101] =
308 " "
309 " ";
310 while( n>100 ){
311 blob_append(pOut, z100, 100); n -= 100;
312 }
313 if( n>0 ){
314 blob_append(pOut, z100, n);
315 }
316 }
317
318 /*
319 ** Append text to a sbs diff output
 
 
320 */
321 static void appendSbsLine(Blob *pOut, DLine *pLine, int width, int pad){
322 int sz = pLine->h & LENGTH_MASK;
323 if( sz<width ){
324 blob_append(pOut, pLine->z, sz);
325 if( pad ) appendSpace(pOut, width-sz);
326 }else{
327 blob_append(pOut, pLine->z, width);
328 }
 
 
 
 
 
 
 
 
 
329 }
330
331
332 /*
333 ** Given a diff context in which the aEdit[] array has been filled
@@ -344,15 +349,18 @@
344 int mxr; /* Maximum value for r */
345 int na, nb; /* Number of lines shown from A and B */
346 int i, j; /* Loop counters */
347 int m, ma, mb;/* Number of lines to output */
348 int skip; /* Number of lines to skip */
349 char zFormat[50]; /* Output format */
 
 
350
351 sqlite3_snprintf(sizeof(zFormat), zFormat,
352 "%%4d %%%d.%ds %%c %%4d %%.%ds\n",
353 width, width, width);
 
354 A = p->aFrom;
355 B = p->aTo;
356 R = p->aEdit;
357 mxr = p->nEdit;
358 while( mxr>2 && R[mxr-1]==0 && R[mxr-2]==0 ){ mxr -= 3; }
@@ -396,15 +404,16 @@
396 /* Show the initial common area */
397 a += skip;
398 b += skip;
399 m = R[r] - skip;
400 for(j=0; j<m; j++){
401 blob_appendf(pOut, "%6d ", a+j);
402 appendSbsLine(pOut, &A[a+j], width, 1);
403 blob_appendf(pOut, " %6d ", b+j);
404 appendSbsLine(pOut, &B[b+j], width, 0);
405 blob_append(pOut, "\n", 1);
 
406 }
407 a += m;
408 b += m;
409
410 /* Show the differences */
@@ -411,41 +420,49 @@
411 for(i=0; i<nr; i++){
412 ma = R[r+i*3+1];
413 mb = R[r+i*3+2];
414 m = ma<mb ? ma : mb;
415 for(j=0; j<m; j++){
416 blob_appendf(pOut, "%6d ", a+j);
417 appendSbsLine(pOut, &A[a+j], width, 1);
418 blob_appendf(pOut, " | %6d ", b+j);
419 appendSbsLine(pOut, &B[b+j], width, 0);
420 blob_append(pOut, "\n", 1);
 
 
421 }
422 a += m;
423 b += m;
424 ma -= m;
425 mb -= m;
426 for(j=0; j<ma; j++){
427 blob_appendf(pOut, "%6d ", a+j);
428 appendSbsLine(pOut, &A[a+j], width, 1);
429 blob_append(pOut, " <\n", 3);
 
 
 
 
430 }
431 a += ma;
432 for(j=0; j<mb; j++){
433 appendSpace(pOut, width+7);
434 blob_appendf(pOut, " > %6d ", b+j);
435 appendSbsLine(pOut, &B[b+j], width, 0);
436 blob_append(pOut, "\n", 1);
 
437 }
438 b += mb;
439 if( i<nr-1 ){
440 m = R[r+i*3+3];
441 for(j=0; j<m; j++){
442 blob_appendf(pOut, "%6d ", a+j);
443 appendSbsLine(pOut, &A[a+j], width, 1);
444 blob_appendf(pOut, " %6d ", b+j);
445 appendSbsLine(pOut, &B[b+j], width, 0);
446 blob_append(pOut, "\n", 1);
 
447 }
448 b += m;
449 a += m;
450 }
451 }
@@ -453,17 +470,19 @@
453 /* Show the final common area */
454 assert( nr==i );
455 m = R[r+nr*3];
456 if( m>nContext ) m = nContext;
457 for(j=0; j<m; j++){
458 blob_appendf(pOut, "%6d ", a+j);
459 appendSbsLine(pOut, &A[a+j], width, 1);
460 blob_appendf(pOut, " %6d ", b+j);
461 appendSbsLine(pOut, &B[b+j], width, 0);
462 blob_append(pOut, "\n", 1);
 
463 }
464 }
 
465 }
466
467 /*
468 ** Compute the optimal longest common subsequence (LCS) using an
469 ** exhaustive search. This version of the LCS is only used for
470
--- src/diff.c
+++ src/diff.c
@@ -299,35 +299,40 @@
299 }
300 }
301 }
302
303 /*
304 ** Write a 6-digit line number into the buffer z[]. z[] is guaranteed to
305 ** have space for at least 7 characters.
306 */
307 static void sbsWriteLineno(char *z, int ln){
308 sqlite3_snprintf(7, z, "%6d", ln+1);
309 z[6] = ' ';
 
 
 
 
 
 
 
310 }
311
312 /*
313 ** Write up to width characters of pLine into z[]. Translate tabs into
314 ** spaces. If trunc is true, then append \n\000 after the last character
315 ** written.
316 */
317 static int sbsWriteText(char *z, DLine *pLine, int width, int trunc){
318 int n = pLine->h & LENGTH_MASK;
319 int i, j;
320 const char *zIn = pLine->z;
321 for(i=j=0; i<n && j<width; i++){
322 if( zIn[i]=='\t' ){
323 z[j++] = ' ';
324 while( (j&7)!=0 && j<width ) z[j++] = ' ';
325 }else{
326 z[j++] = zIn[i];
327 }
328 }
329 if( trunc ){
330 z[j++] = '\n';
331 z[j] = 0;
332 }
333 return j;
334 }
335
336
337 /*
338 ** Given a diff context in which the aEdit[] array has been filled
@@ -344,15 +349,18 @@
349 int mxr; /* Maximum value for r */
350 int na, nb; /* Number of lines shown from A and B */
351 int i, j; /* Loop counters */
352 int m, ma, mb;/* Number of lines to output */
353 int skip; /* Number of lines to skip */
354 int mxLine; /* Length of a line of text */
355 char *zLine; /* A line of text being formatted */
356 int len; /* Length of an output line */
357
358 mxLine = width*2 + 2*7 + 3 + 1;
359 zLine = fossil_malloc( mxLine + 1 );
360 if( zLine==0 ) return;
361 zLine[mxLine] = 0;
362 A = p->aFrom;
363 B = p->aTo;
364 R = p->aEdit;
365 mxr = p->nEdit;
366 while( mxr>2 && R[mxr-1]==0 && R[mxr-2]==0 ){ mxr -= 3; }
@@ -396,15 +404,16 @@
404 /* Show the initial common area */
405 a += skip;
406 b += skip;
407 m = R[r] - skip;
408 for(j=0; j<m; j++){
409 memset(zLine, ' ', mxLine);
410 sbsWriteLineno(zLine, a+j);
411 sbsWriteText(&zLine[7], &A[a+j], width, 0);
412 sbsWriteLineno(&zLine[width+10], b+j);
413 len = sbsWriteText(&zLine[width+17], &B[b+j], width, 1);
414 blob_append(pOut, zLine, len+width+17);
415 }
416 a += m;
417 b += m;
418
419 /* Show the differences */
@@ -411,41 +420,49 @@
420 for(i=0; i<nr; i++){
421 ma = R[r+i*3+1];
422 mb = R[r+i*3+2];
423 m = ma<mb ? ma : mb;
424 for(j=0; j<m; j++){
425 memset(zLine, ' ', mxLine);
426 sbsWriteLineno(zLine, a+j);
427 sbsWriteText(&zLine[7], &A[a+j], width, 0);
428 zLine[width+8] = '|';
429 sbsWriteLineno(&zLine[width+10], b+j);
430 len = sbsWriteText(&zLine[width+17], &B[b+j], width, 1);
431 blob_append(pOut, zLine, len+width+17);
432 }
433 a += m;
434 b += m;
435 ma -= m;
436 mb -= m;
437 for(j=0; j<ma; j++){
438 memset(zLine, ' ', width+7);
439 sbsWriteLineno(zLine, a+j);
440 sbsWriteText(&zLine[7], &A[a+j], width, 0);
441 zLine[width+8] = '<';
442 zLine[width+9] = '\n';
443 zLine[width+10] = 0;
444 blob_append(pOut, zLine, width+10);
445 }
446 a += ma;
447 for(j=0; j<mb; j++){
448 memset(zLine, ' ', mxLine);
449 zLine[width+8] = '>';
450 sbsWriteLineno(&zLine[width+10], b+j);
451 len = sbsWriteText(&zLine[width+17], &B[b+j], width, 1);
452 blob_append(pOut, zLine, len+width+17);
453 }
454 b += mb;
455 if( i<nr-1 ){
456 m = R[r+i*3+3];
457 for(j=0; j<m; j++){
458 memset(zLine, ' ', mxLine);
459 sbsWriteLineno(zLine, a+j);
460 sbsWriteText(&zLine[7], &A[a+j], width, 0);
461 sbsWriteLineno(&zLine[width+10], b+j);
462 len = sbsWriteText(&zLine[width+17], &B[b+j], width, 1);
463 blob_append(pOut, zLine, len+width+17);
464 }
465 b += m;
466 a += m;
467 }
468 }
@@ -453,17 +470,19 @@
470 /* Show the final common area */
471 assert( nr==i );
472 m = R[r+nr*3];
473 if( m>nContext ) m = nContext;
474 for(j=0; j<m; j++){
475 memset(zLine, ' ', mxLine);
476 sbsWriteLineno(zLine, a+j);
477 sbsWriteText(&zLine[7], &A[a+j], width, 0);
478 sbsWriteLineno(&zLine[width+10], b+j);
479 len = sbsWriteText(&zLine[width+17], &B[b+j], width, 1);
480 blob_append(pOut, zLine, len+width+17);
481 }
482 }
483 free(zLine);
484 }
485
486 /*
487 ** Compute the optimal longest common subsequence (LCS) using an
488 ** exhaustive search. This version of the LCS is only used for
489

Keyboard Shortcuts

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