Fossil

Check-in [8670373321]
Login

Check-in [8670373321]

Many hyperlinks are disabled.
Use anonymous login to enable hyperlinks.

Overview
Comment: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.
Downloads: Tarball | ZIP archive
Timelines: family | ancestors | descendants | both | trunk
Files: files | file ages | folders
SHA1: 8670373321604573901fad634ef7fb2cef2ca46d
User & Date: drh 2011-10-22 03:37:43.910
Context
2011-10-22
11:55
Do not assume the CSS background color is "white". ... (check-in: a9fd1c7951 user: drh tags: trunk)
03:37
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. ... (check-in: 8670373321 user: drh tags: trunk)
2011-10-21
23:44
Improved formatting for command-line side-by-side diff. Extend command-line side-by-side diff to all diff operations, including stash diffs. ... (check-in: ab47cc73d7 user: drh tags: trunk)
Changes
Unified Diff Ignore Whitespace Patch
Changes to src/diff.c.
297
298
299
300
301
302
303

304
305
306

307
308
309
310
311
312
313
314
315
316
317
318


319
320
321
322
323

324
325



326
327

328






329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348


349
350
351
352
353



354
355
356
357
358
359
360
    for(j=0; j<m; j++){
      appendDiffLine(pOut, " ", &B[b+j]);
    }
  }
}

/*

** Append spaces to a blob
*/
static void appendSpace(Blob *pOut, int n){

  const char z100[101] = 
     "                                                  "
     "                                                  ";
  while( n>100 ){
    blob_append(pOut, z100, 100); n -= 100;
  }
  if( n>0 ){
    blob_append(pOut, z100, n);
  }
}

/*


** Append text to a sbs diff output
*/
static void appendSbsLine(Blob *pOut, DLine *pLine, int width, int pad){
  int sz = pLine->h & LENGTH_MASK;
  if( sz<width ){

    blob_append(pOut, pLine->z, sz);
    if( pad ) appendSpace(pOut, width-sz);



  }else{
    blob_append(pOut, pLine->z, width);

  }






}


/*
** Given a diff context in which the aEdit[] array has been filled
** in, compute a side-by-side diff into pOut.
*/
static void sbsDiff(DContext *p, Blob *pOut, int nContext, int width){
  DLine *A;     /* Left side of the diff */
  DLine *B;     /* Right side of the diff */  
  int a = 0;    /* Index of next line in A[] */
  int b = 0;    /* Index of next line in B[] */
  int *R;       /* Array of COPY/DELETE/INSERT triples */
  int r;        /* Index into R[] */
  int nr;       /* Number of COPY/DELETE/INSERT triples to process */
  int mxr;      /* Maximum value for r */
  int na, nb;   /* Number of lines shown from A and B */
  int i, j;     /* Loop counters */
  int m, ma, mb;/* Number of lines to output */
  int skip;     /* Number of lines to skip */


  char zFormat[50];  /* Output format */

  sqlite3_snprintf(sizeof(zFormat), zFormat,
                   "%%4d %%%d.%ds %%c %%4d %%.%ds\n",
                   width, width, width);



  A = p->aFrom;
  B = p->aTo;
  R = p->aEdit;
  mxr = p->nEdit;
  while( mxr>2 && R[mxr-1]==0 && R[mxr-2]==0 ){ mxr -= 3; }
  for(r=0; r<mxr; r += 3*nr){
    /* Figure out how many triples to show in a single block */







>
|

|
>
|
<
<
<
<
<
<
<
<



>
>
|

|
|
<
>
|
|
>
>
>
|
<
>
|
>
>
>
>
>
>




















>
>
|

<
<
|
>
>
>







297
298
299
300
301
302
303
304
305
306
307
308
309








310
311
312
313
314
315
316
317
318

319
320
321
322
323
324
325

326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357


358
359
360
361
362
363
364
365
366
367
368
    for(j=0; j<m; j++){
      appendDiffLine(pOut, " ", &B[b+j]);
    }
  }
}

/*
** Write a 6-digit line number into the buffer z[].  z[] is guaranteed to
** have space for at least 7 characters.
*/
static void sbsWriteLineno(char *z, int ln){
  sqlite3_snprintf(7, z, "%6d", ln+1);
  z[6] = ' ';








}

/*
** Write up to width characters of pLine into z[].  Translate tabs into
** spaces.  If trunc is true, then append \n\000 after the last character
** written.
*/
static int sbsWriteText(char *z, DLine *pLine, int width, int trunc){
  int n = pLine->h & LENGTH_MASK;

  int i, j;
  const char *zIn = pLine->z;
  for(i=j=0; i<n && j<width; i++){
    if( zIn[i]=='\t' ){
      z[j++] = ' ';
      while( (j&7)!=0 && j<width ) z[j++] = ' ';
    }else{

      z[j++] = zIn[i];
    }
  }
  if( trunc ){
    z[j++] = '\n';
    z[j] = 0;
  }
  return j;
}


/*
** Given a diff context in which the aEdit[] array has been filled
** in, compute a side-by-side diff into pOut.
*/
static void sbsDiff(DContext *p, Blob *pOut, int nContext, int width){
  DLine *A;     /* Left side of the diff */
  DLine *B;     /* Right side of the diff */  
  int a = 0;    /* Index of next line in A[] */
  int b = 0;    /* Index of next line in B[] */
  int *R;       /* Array of COPY/DELETE/INSERT triples */
  int r;        /* Index into R[] */
  int nr;       /* Number of COPY/DELETE/INSERT triples to process */
  int mxr;      /* Maximum value for r */
  int na, nb;   /* Number of lines shown from A and B */
  int i, j;     /* Loop counters */
  int m, ma, mb;/* Number of lines to output */
  int skip;     /* Number of lines to skip */
  int mxLine;   /* Length of a line of text */
  char *zLine;  /* A line of text being formatted */
  int len;      /* Length of an output line */



  mxLine = width*2 + 2*7 + 3 + 1;
  zLine = fossil_malloc( mxLine + 1 );
  if( zLine==0 ) return;
  zLine[mxLine] = 0;
  A = p->aFrom;
  B = p->aTo;
  R = p->aEdit;
  mxr = p->nEdit;
  while( mxr>2 && R[mxr-1]==0 && R[mxr-2]==0 ){ mxr -= 3; }
  for(r=0; r<mxr; r += 3*nr){
    /* Figure out how many triples to show in a single block */
394
395
396
397
398
399
400

401
402
403
404
405
406
407
408
409
410
411
412
413
414
415

416
417

418
419
420
421
422
423
424
425
426

427
428



429
430
431
432

433
434
435
436
437
438
439
440
441

442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457

458
459
460
461
462
463
464

465
466
467
468
469
470
471
    if( r>0 ) blob_appendf(pOut,"%.*c\n", width*2+16, '.');

    /* Show the initial common area */
    a += skip;
    b += skip;
    m = R[r] - skip;
    for(j=0; j<m; j++){

      blob_appendf(pOut, "%6d ", a+j);
      appendSbsLine(pOut, &A[a+j], width, 1);
      blob_appendf(pOut, "   %6d ", b+j);
      appendSbsLine(pOut, &B[b+j], width, 0);
      blob_append(pOut, "\n", 1);
    }
    a += m;
    b += m;

    /* Show the differences */
    for(i=0; i<nr; i++){
      ma = R[r+i*3+1];
      mb = R[r+i*3+2];
      m = ma<mb ? ma : mb;
      for(j=0; j<m; j++){

        blob_appendf(pOut, "%6d ", a+j);
        appendSbsLine(pOut, &A[a+j], width, 1);

        blob_appendf(pOut, " | %6d ", b+j);
        appendSbsLine(pOut, &B[b+j], width, 0);
        blob_append(pOut, "\n", 1);
      }
      a += m;
      b += m;
      ma -= m;
      mb -= m;
      for(j=0; j<ma; j++){

        blob_appendf(pOut, "%6d ", a+j);
        appendSbsLine(pOut, &A[a+j], width, 1);



        blob_append(pOut, " <\n", 3);
      }
      a += ma;
      for(j=0; j<mb; j++){

        appendSpace(pOut, width+7);
        blob_appendf(pOut, " > %6d ", b+j);
        appendSbsLine(pOut, &B[b+j], width, 0);
        blob_append(pOut, "\n", 1);
      }
      b += mb;
      if( i<nr-1 ){
        m = R[r+i*3+3];
        for(j=0; j<m; j++){

          blob_appendf(pOut, "%6d ", a+j);
          appendSbsLine(pOut, &A[a+j], width, 1);
          blob_appendf(pOut, "   %6d ", b+j);
          appendSbsLine(pOut, &B[b+j], width, 0);
          blob_append(pOut, "\n", 1);
        }
        b += m;
        a += m;
      }
    }

    /* Show the final common area */
    assert( nr==i );
    m = R[r+nr*3];
    if( m>nContext ) m = nContext;
    for(j=0; j<m; j++){

      blob_appendf(pOut, "%6d ", a+j);
      appendSbsLine(pOut, &A[a+j], width, 1);
      blob_appendf(pOut, "   %6d ", b+j);
      appendSbsLine(pOut, &B[b+j], width, 0);
      blob_append(pOut, "\n", 1);
    }
  }

}

/*
** Compute the optimal longest common subsequence (LCS) using an
** exhaustive search.  This version of the LCS is only used for
** shorter input strings since runtime is O(N*N) where N is the
** input string length.







>
|
|
|
|
|










>
|
|
>
|
|
|






>
|
|
>
>
>
|



>
|
|
|
|





>
|
|
|
|
|











>
|
|
|
|
|


>







402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
    if( r>0 ) blob_appendf(pOut,"%.*c\n", width*2+16, '.');

    /* Show the initial common area */
    a += skip;
    b += skip;
    m = R[r] - skip;
    for(j=0; j<m; j++){
      memset(zLine, ' ', mxLine);
      sbsWriteLineno(zLine, a+j);
      sbsWriteText(&zLine[7], &A[a+j], width, 0);
      sbsWriteLineno(&zLine[width+10], b+j);
      len = sbsWriteText(&zLine[width+17], &B[b+j], width, 1);
      blob_append(pOut, zLine, len+width+17);
    }
    a += m;
    b += m;

    /* Show the differences */
    for(i=0; i<nr; i++){
      ma = R[r+i*3+1];
      mb = R[r+i*3+2];
      m = ma<mb ? ma : mb;
      for(j=0; j<m; j++){
        memset(zLine, ' ', mxLine);
        sbsWriteLineno(zLine, a+j);
        sbsWriteText(&zLine[7], &A[a+j], width, 0);
        zLine[width+8] = '|';
        sbsWriteLineno(&zLine[width+10], b+j);
        len = sbsWriteText(&zLine[width+17], &B[b+j], width, 1);
        blob_append(pOut, zLine, len+width+17);
      }
      a += m;
      b += m;
      ma -= m;
      mb -= m;
      for(j=0; j<ma; j++){
        memset(zLine, ' ', width+7);
        sbsWriteLineno(zLine, a+j);
        sbsWriteText(&zLine[7], &A[a+j], width, 0);
        zLine[width+8] = '<';
        zLine[width+9] = '\n';
        zLine[width+10] = 0;
        blob_append(pOut, zLine, width+10);
      }
      a += ma;
      for(j=0; j<mb; j++){
        memset(zLine, ' ', mxLine);
        zLine[width+8] = '>';
        sbsWriteLineno(&zLine[width+10], b+j);
        len = sbsWriteText(&zLine[width+17], &B[b+j], width, 1);
        blob_append(pOut, zLine, len+width+17);
      }
      b += mb;
      if( i<nr-1 ){
        m = R[r+i*3+3];
        for(j=0; j<m; j++){
          memset(zLine, ' ', mxLine);
          sbsWriteLineno(zLine, a+j);
          sbsWriteText(&zLine[7], &A[a+j], width, 0);
          sbsWriteLineno(&zLine[width+10], b+j);
          len = sbsWriteText(&zLine[width+17], &B[b+j], width, 1);
          blob_append(pOut, zLine, len+width+17);
        }
        b += m;
        a += m;
      }
    }

    /* Show the final common area */
    assert( nr==i );
    m = R[r+nr*3];
    if( m>nContext ) m = nContext;
    for(j=0; j<m; j++){
      memset(zLine, ' ', mxLine);
      sbsWriteLineno(zLine, a+j);
      sbsWriteText(&zLine[7], &A[a+j], width, 0);
      sbsWriteLineno(&zLine[width+10], b+j);
      len = sbsWriteText(&zLine[width+17], &B[b+j], width, 1);
      blob_append(pOut, zLine, len+width+17);
    }
  }
  free(zLine);
}

/*
** Compute the optimal longest common subsequence (LCS) using an
** exhaustive search.  This version of the LCS is only used for
** shorter input strings since runtime is O(N*N) where N is the
** input string length.