Fossil SCM

Enhance the change descriptions in the "Changes" accordion panel title to provide information on the number of added and deleted files and similar.

drh 2026-05-31 19:04 UTC trunk
Commit 94e94bc3a61385937580731bbd96460c17c2826a89aaf15c2f356e7ffad4f057
1 file changed +83 -23
+83 -23
--- src/info.c
+++ src/info.c
@@ -371,10 +371,21 @@
371371
pCfg->zLeftHash = 0;
372372
blob_reset(&from);
373373
blob_reset(&to);
374374
}
375375
376
+/*
377
+** The append_file_change_line() routine updates an array of counts
378
+** for various kinds of changes.
379
+*/
380
+#define FCHNG_NEW 0
381
+#define FCHNG_DELETE 1
382
+#define FCHNG_RENAME 2
383
+#define FCHNG_MODE 3
384
+#define FCHNG_EDIT 4
385
+#define N_FCHNG 5
386
+
376387
/*
377388
** Write a line of web-page output that shows changes that have occurred
378389
** to a file between two check-ins.
379390
*/
380391
static void append_file_change_line(
@@ -382,32 +393,38 @@
382393
const char *zName, /* Name of the file that has changed */
383394
const char *zOld, /* blob.uuid before change. NULL for added files */
384395
const char *zNew, /* blob.uuid after change. NULL for deletes */
385396
const char *zOldName, /* Prior name. NULL if no name change. */
386397
DiffConfig *pCfg, /* Flags for text_diff() or NULL to omit all */
387
- int mperm /* executable or symlink permission for zNew */
398
+ int mperm, /* executable or symlink permission for zNew */
399
+ int *aChng /* Change count array */
388400
){
389401
@ <div class='file-change-line'><span>
390402
/* Maintenance reminder: the extra level of SPAN is for
391403
** arranging new elements via JS. */
392404
if( !g.perm.Hyperlink ){
393405
if( zNew==0 ){
394406
@ Deleted %h(zName).
407
+ aChng[FCHNG_DELETE]++;
395408
}else if( zOld==0 ){
396409
@ Added %h(zName).
410
+ aChng[FCHNG_NEW]++;
397411
}else if( zOldName!=0 && fossil_strcmp(zName,zOldName)!=0 ){
398412
@ Name change from %h(zOldName) to %h(zName).
413
+ aChng[FCHNG_RENAME]++;
399414
}else if( fossil_strcmp(zNew, zOld)==0 ){
400415
if( mperm==PERM_EXE ){
401416
@ %h(zName) became executable.
402417
}else if( mperm==PERM_LNK ){
403418
@ %h(zName) became a symlink.
404419
}else{
405420
@ %h(zName) became a regular file.
406421
}
422
+ aChng[FCHNG_MODE]++;
407423
}else{
408424
@ Changes to %h(zName).
425
+ aChng[FCHNG_EDIT]++;
409426
}
410427
@ </span></div>
411428
if( pCfg ){
412429
append_diff(zOld, zNew, pCfg);
413430
}
@@ -422,22 +439,25 @@
422439
@ %h(zOldName)</a>
423440
@ %z(href("%R/artifact/%!S",zOld))[%S(zOld)]</a>
424441
@ to %z(href("%R/finfo?name=%T&m=%!S&ci=%s",zName,zNew,zCkin2))\
425442
@ %h(zName)</a>
426443
@ %z(href("%R/artifact/%!S",zNew))[%S(zNew)]</a>.
444
+ aChng[FCHNG_RENAME]++;
427445
}else{
428446
@ Modified %z(href("%R/finfo?name=%T&m=%!S&ci=%s",zName,zNew,zCkin2))\
429447
@ %h(zName)</a>
430448
@ from %z(href("%R/artifact/%!S",zOld))[%S(zOld)]</a>
431449
@ to %z(href("%R/artifact/%!S",zNew))[%S(zNew)]</a>.
432450
}
451
+ aChng[FCHNG_EDIT]++;
433452
}else if( zOldName!=0 && fossil_strcmp(zName,zOldName)!=0 ){
434453
@ Name change
435454
@ from %z(href("%R/finfo?name=%T&m=%!S&ci=%s",zOldName,zOld,zCkin2))\
436455
@ %h(zOldName)</a>
437456
@ to %z(href("%R/finfo?name=%T&m=%!S&ci=%s",zName,zNew,zCkin2))\
438457
@ %h(zName)</a>.
458
+ aChng[FCHNG_RENAME]++;
439459
}else{
440460
@ %z(href("%R/finfo?name=%T&m=%!S&ci=%s",zName,zNew,zCkin2))\
441461
@ %h(zName)</a> became
442462
if( mperm==PERM_EXE ){
443463
@ executable with contents
@@ -445,17 +465,20 @@
445465
@ a symlink with target
446466
}else{
447467
@ a regular file with contents
448468
}
449469
@ %z(href("%R/artifact/%!S",zNew))[%S(zNew)]</a>.
470
+ aChng[FCHNG_MODE]++;
450471
}
451472
}else if( zOld ){
452473
@ Deleted %z(href("%R/finfo?name=%T&m=%!S&ci=%s",zName,zOld,zCkin2))\
453474
@ %h(zName)</a> version %z(href("%R/artifact/%!S",zOld))[%S(zOld)]</a>.
475
+ aChng[FCHNG_DELETE]++;
454476
}else{
455477
@ Added %z(href("%R/finfo?name=%T&m=%!S&ci=%s",zName,zNew,zCkin2))\
456478
@ %h(zName)</a> version %z(href("%R/artifact/%!S",zNew))[%S(zNew)]</a>.
479
+ aChng[FCHNG_NEW]++;
457480
}
458481
if( zOld && zNew && fossil_strcmp(zOld,zNew)!=0 ){
459482
if( pCfg ){
460483
@ </span></div>
461484
append_diff(zOld, zNew, pCfg);
@@ -624,10 +647,58 @@
624647
www_print_timeline(&q, TIMELINE_DISJOINT|TIMELINE_GRAPH|TIMELINE_NOSCROLL,
625648
&xtra);
626649
db_finalize(&q);
627650
style_finish_page();
628651
}
652
+
653
+/*
654
+** Generate JS code that will adjust the change counts in the title
655
+** of the "changes_section" panel where "changes_section" is a JS id.
656
+**
657
+** The change counts are taken from g.diffCnt[] for edits, and from
658
+** the aChng[] parameter for additions, deletions, and modifications.
659
+** The aChng parameter may be NULL, in which case those factors are
660
+** ignored.
661
+*/
662
+static void adjust_changes_section_title(
663
+ int iLine, /* Souce code line number of caller */
664
+ int *aChng /* Change categories */
665
+){
666
+ sqlite3_str *pTxt = sqlite3_str_new(0);
667
+ if( g.diffCnt[0]>0 ){
668
+ sqlite3_str_appendf(pTxt, "%d file%s edited [+%d -%d lines]",
669
+ g.diffCnt[0], g.diffCnt[0]==1 ? "" : "s",
670
+ g.diffCnt[1], g.diffCnt[2]);
671
+ }
672
+ if( aChng ){
673
+ static const int aiType[] =
674
+ { FCHNG_NEW, FCHNG_DELETE, FCHNG_RENAME, FCHNG_MODE };
675
+ static const char *azType[] =
676
+ { "added", "deleted", "renamed", "mode change"};
677
+ int i;
678
+ for(i=0; i<4; i++){
679
+ int j = aiType[i];
680
+ if( aChng[j] ){
681
+ const char *zFiles = "";
682
+ if( sqlite3_str_length(pTxt)>0 ){
683
+ sqlite3_str_append(pTxt,", ", 2);
684
+ }else{
685
+ zFiles = i<3 && aChng[j]>1 ? " files" : " file";
686
+ }
687
+ sqlite3_str_appendf(pTxt,"%d%s %s", aChng[j], zFiles, azType[i]);
688
+ if( i==3 && aChng[j]>1 ) sqlite3_str_appendf(pTxt, "s");
689
+ }
690
+ }
691
+ }
692
+ if( sqlite3_str_length(pTxt)>0 ){
693
+ @ <script nonce='%h(style_nonce())'>;/* info.c:%d(iLine) */
694
+ @ document.getElementById('changes_section').textContent = \
695
+ @ 'Changes (%h(sqlite3_str_value(pTxt)))'
696
+ @ </script>
697
+ }
698
+ sqlite3_str_free(pTxt);
699
+}
629700
630701
/*
631702
** Render a web-page diff of the changes in the working check-out
632703
*/
633704
static void ckout_normal_diff(int vid){
@@ -734,16 +805,11 @@
734805
blob_reset(&old);
735806
blob_reset(&new);
736807
}
737808
}
738809
db_finalize(&q);
739
- @ <script nonce='%h(style_nonce())'>;/* info.c:%d(__LINE__) */
740
- @ document.getElementById('changes_section').textContent = 'Changes ' +
741
- @ '(%d(g.diffCnt[0]) file' + (%d(g.diffCnt[0])===1 ? '' : 's') + ': ' +
742
- @ '+%d(g.diffCnt[1]) ' +
743
- @ '−%d(g.diffCnt[2]))'
744
- @ </script>
810
+ adjust_changes_section_title(__LINE__, 0);
745811
append_diff_javascript(diffType);
746812
}
747813
748814
/*
749815
** Render a web-page diff of the changes in the working check-out to
@@ -827,16 +893,11 @@
827893
}
828894
fossil_free(zLhs);
829895
fossil_free(zRhs);
830896
}
831897
db_finalize(&q);
832
- @ <script nonce='%h(style_nonce())'>;/* info.c:%d(__LINE__) */
833
- @ document.getElementById('changes_section').textContent = 'Changes ' +
834
- @ '(%d(g.diffCnt[0]) file' + (%d(g.diffCnt[0])===1 ? '' : 's') + ': ' +
835
- @ '+%d(g.diffCnt[1]) ' +
836
- @ '−%d(g.diffCnt[2]))'
837
- @ </script>
898
+ adjust_changes_section_title(__LINE__, 0);
838899
append_diff_javascript(diffType);
839900
}
840901
841902
/*
842903
** WEBPAGE: ckout
@@ -935,11 +996,13 @@
935996
ReCompiled *pRe = 0; /* regex */
936997
const char *zW; /* URL param for ignoring whitespace */
937998
const char *zPage = "vinfo"; /* Page that shows diffs */
938999
const char *zBrName; /* Branch name */
9391000
DiffConfig DCfg,*pCfg; /* Type of diff */
1001
+ int aChng[N_FCHNG]; /* Counts of change types */
9401002
1003
+ memset(aChng, 0, sizeof(aChng));
9411004
login_check_credentials();
9421005
if( !g.perm.Read ){ login_needed(g.anon.Read); return; }
9431006
style_set_current_feature("vinfo");
9441007
zName = P("name");
9451008
rid = name_to_rid_www("name");
@@ -1253,21 +1316,16 @@
12531316
int mperm = db_column_int(&q3, 1);
12541317
const char *zOld = db_column_text(&q3,2);
12551318
const char *zNew = db_column_text(&q3,3);
12561319
const char *zOldName = db_column_text(&q3, 4);
12571320
append_file_change_line(zUuid, zName, zOld, zNew, zOldName,
1258
- pCfg,mperm);
1321
+ pCfg,mperm,aChng);
12591322
}
12601323
db_finalize(&q3);
12611324
@ </div>
12621325
if( diffType!=0 ){
1263
- @ <script nonce='%h(style_nonce())'>;/* info.c:%d(__LINE__) */
1264
- @ document.getElementById('changes_section').textContent = 'Changes ' +
1265
- @ '(%d(g.diffCnt[0]) file' + (%d(g.diffCnt[0])===1 ? '' : 's') + ': ' +
1266
- @ '+%d(g.diffCnt[1]) ' +
1267
- @ '−%d(g.diffCnt[2]))'
1268
- @ </script>
1326
+ adjust_changes_section_title(__LINE__, aChng);
12691327
}
12701328
append_diff_javascript(diffType);
12711329
style_finish_page();
12721330
}
12731331
@@ -1449,11 +1507,13 @@
14491507
DiffConfig DCfg, *pCfg = 0;
14501508
int graphFlags = 0;
14511509
Blob qp; /* non-glob= query parameters for generated links */
14521510
Blob qpGlob; /* glob= query parameter for generated links */
14531511
int bInvert = PB("inv");
1512
+ int aChng[N_FCHNG]; /* Count of versiou change types */
14541513
1514
+ memset(aChng, 0, sizeof(aChng));
14551515
login_check_credentials();
14561516
if( !g.perm.Read ){ login_needed(g.anon.Read); return; }
14571517
if( robot_restrict("diff") ) return;
14581518
login_anonymous_available();
14591519
fossil_nice_default();
@@ -1594,18 +1654,18 @@
15941654
cmp = fossil_strcmp(pFileFrom->zName, pFileTo->zName);
15951655
}
15961656
if( cmp<0 ){
15971657
if( !pGlob || glob_match(pGlob, pFileFrom->zName) ){
15981658
append_file_change_line(zFrom, pFileFrom->zName,
1599
- pFileFrom->zUuid, 0, 0, pCfg, 0);
1659
+ pFileFrom->zUuid, 0, 0, pCfg, 0,aChng);
16001660
}
16011661
pFileFrom = manifest_file_next(pFrom, 0);
16021662
}else if( cmp>0 ){
16031663
if( !pGlob || glob_match(pGlob, pFileTo->zName) ){
16041664
append_file_change_line(zTo, pFileTo->zName,
16051665
0, pFileTo->zUuid, 0, pCfg,
1606
- manifest_file_mperm(pFileTo));
1666
+ manifest_file_mperm(pFileTo),aChng);
16071667
}
16081668
pFileTo = manifest_file_next(pTo, 0);
16091669
}else if( fossil_strcmp(pFileFrom->zUuid, pFileTo->zUuid)==0 ){
16101670
pFileFrom = manifest_file_next(pFrom, 0);
16111671
pFileTo = manifest_file_next(pTo, 0);
@@ -1613,11 +1673,11 @@
16131673
if(!pGlob || (glob_match(pGlob, pFileFrom->zName)
16141674
|| glob_match(pGlob, pFileTo->zName)) ){
16151675
append_file_change_line(zFrom, pFileFrom->zName,
16161676
pFileFrom->zUuid,
16171677
pFileTo->zUuid, 0, pCfg,
1618
- manifest_file_mperm(pFileTo));
1678
+ manifest_file_mperm(pFileTo),aChng);
16191679
}
16201680
pFileFrom = manifest_file_next(pFrom, 0);
16211681
pFileTo = manifest_file_next(pTo, 0);
16221682
}
16231683
}
16241684
--- src/info.c
+++ src/info.c
@@ -371,10 +371,21 @@
371 pCfg->zLeftHash = 0;
372 blob_reset(&from);
373 blob_reset(&to);
374 }
375
 
 
 
 
 
 
 
 
 
 
 
376 /*
377 ** Write a line of web-page output that shows changes that have occurred
378 ** to a file between two check-ins.
379 */
380 static void append_file_change_line(
@@ -382,32 +393,38 @@
382 const char *zName, /* Name of the file that has changed */
383 const char *zOld, /* blob.uuid before change. NULL for added files */
384 const char *zNew, /* blob.uuid after change. NULL for deletes */
385 const char *zOldName, /* Prior name. NULL if no name change. */
386 DiffConfig *pCfg, /* Flags for text_diff() or NULL to omit all */
387 int mperm /* executable or symlink permission for zNew */
 
388 ){
389 @ <div class='file-change-line'><span>
390 /* Maintenance reminder: the extra level of SPAN is for
391 ** arranging new elements via JS. */
392 if( !g.perm.Hyperlink ){
393 if( zNew==0 ){
394 @ Deleted %h(zName).
 
395 }else if( zOld==0 ){
396 @ Added %h(zName).
 
397 }else if( zOldName!=0 && fossil_strcmp(zName,zOldName)!=0 ){
398 @ Name change from %h(zOldName) to %h(zName).
 
399 }else if( fossil_strcmp(zNew, zOld)==0 ){
400 if( mperm==PERM_EXE ){
401 @ %h(zName) became executable.
402 }else if( mperm==PERM_LNK ){
403 @ %h(zName) became a symlink.
404 }else{
405 @ %h(zName) became a regular file.
406 }
 
407 }else{
408 @ Changes to %h(zName).
 
409 }
410 @ </span></div>
411 if( pCfg ){
412 append_diff(zOld, zNew, pCfg);
413 }
@@ -422,22 +439,25 @@
422 @ %h(zOldName)</a>
423 @ %z(href("%R/artifact/%!S",zOld))[%S(zOld)]</a>
424 @ to %z(href("%R/finfo?name=%T&m=%!S&ci=%s",zName,zNew,zCkin2))\
425 @ %h(zName)</a>
426 @ %z(href("%R/artifact/%!S",zNew))[%S(zNew)]</a>.
 
427 }else{
428 @ Modified %z(href("%R/finfo?name=%T&m=%!S&ci=%s",zName,zNew,zCkin2))\
429 @ %h(zName)</a>
430 @ from %z(href("%R/artifact/%!S",zOld))[%S(zOld)]</a>
431 @ to %z(href("%R/artifact/%!S",zNew))[%S(zNew)]</a>.
432 }
 
433 }else if( zOldName!=0 && fossil_strcmp(zName,zOldName)!=0 ){
434 @ Name change
435 @ from %z(href("%R/finfo?name=%T&m=%!S&ci=%s",zOldName,zOld,zCkin2))\
436 @ %h(zOldName)</a>
437 @ to %z(href("%R/finfo?name=%T&m=%!S&ci=%s",zName,zNew,zCkin2))\
438 @ %h(zName)</a>.
 
439 }else{
440 @ %z(href("%R/finfo?name=%T&m=%!S&ci=%s",zName,zNew,zCkin2))\
441 @ %h(zName)</a> became
442 if( mperm==PERM_EXE ){
443 @ executable with contents
@@ -445,17 +465,20 @@
445 @ a symlink with target
446 }else{
447 @ a regular file with contents
448 }
449 @ %z(href("%R/artifact/%!S",zNew))[%S(zNew)]</a>.
 
450 }
451 }else if( zOld ){
452 @ Deleted %z(href("%R/finfo?name=%T&m=%!S&ci=%s",zName,zOld,zCkin2))\
453 @ %h(zName)</a> version %z(href("%R/artifact/%!S",zOld))[%S(zOld)]</a>.
 
454 }else{
455 @ Added %z(href("%R/finfo?name=%T&m=%!S&ci=%s",zName,zNew,zCkin2))\
456 @ %h(zName)</a> version %z(href("%R/artifact/%!S",zNew))[%S(zNew)]</a>.
 
457 }
458 if( zOld && zNew && fossil_strcmp(zOld,zNew)!=0 ){
459 if( pCfg ){
460 @ </span></div>
461 append_diff(zOld, zNew, pCfg);
@@ -624,10 +647,58 @@
624 www_print_timeline(&q, TIMELINE_DISJOINT|TIMELINE_GRAPH|TIMELINE_NOSCROLL,
625 &xtra);
626 db_finalize(&q);
627 style_finish_page();
628 }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
629
630 /*
631 ** Render a web-page diff of the changes in the working check-out
632 */
633 static void ckout_normal_diff(int vid){
@@ -734,16 +805,11 @@
734 blob_reset(&old);
735 blob_reset(&new);
736 }
737 }
738 db_finalize(&q);
739 @ <script nonce='%h(style_nonce())'>;/* info.c:%d(__LINE__) */
740 @ document.getElementById('changes_section').textContent = 'Changes ' +
741 @ '(%d(g.diffCnt[0]) file' + (%d(g.diffCnt[0])===1 ? '' : 's') + ': ' +
742 @ '+%d(g.diffCnt[1]) ' +
743 @ '−%d(g.diffCnt[2]))'
744 @ </script>
745 append_diff_javascript(diffType);
746 }
747
748 /*
749 ** Render a web-page diff of the changes in the working check-out to
@@ -827,16 +893,11 @@
827 }
828 fossil_free(zLhs);
829 fossil_free(zRhs);
830 }
831 db_finalize(&q);
832 @ <script nonce='%h(style_nonce())'>;/* info.c:%d(__LINE__) */
833 @ document.getElementById('changes_section').textContent = 'Changes ' +
834 @ '(%d(g.diffCnt[0]) file' + (%d(g.diffCnt[0])===1 ? '' : 's') + ': ' +
835 @ '+%d(g.diffCnt[1]) ' +
836 @ '−%d(g.diffCnt[2]))'
837 @ </script>
838 append_diff_javascript(diffType);
839 }
840
841 /*
842 ** WEBPAGE: ckout
@@ -935,11 +996,13 @@
935 ReCompiled *pRe = 0; /* regex */
936 const char *zW; /* URL param for ignoring whitespace */
937 const char *zPage = "vinfo"; /* Page that shows diffs */
938 const char *zBrName; /* Branch name */
939 DiffConfig DCfg,*pCfg; /* Type of diff */
 
940
 
941 login_check_credentials();
942 if( !g.perm.Read ){ login_needed(g.anon.Read); return; }
943 style_set_current_feature("vinfo");
944 zName = P("name");
945 rid = name_to_rid_www("name");
@@ -1253,21 +1316,16 @@
1253 int mperm = db_column_int(&q3, 1);
1254 const char *zOld = db_column_text(&q3,2);
1255 const char *zNew = db_column_text(&q3,3);
1256 const char *zOldName = db_column_text(&q3, 4);
1257 append_file_change_line(zUuid, zName, zOld, zNew, zOldName,
1258 pCfg,mperm);
1259 }
1260 db_finalize(&q3);
1261 @ </div>
1262 if( diffType!=0 ){
1263 @ <script nonce='%h(style_nonce())'>;/* info.c:%d(__LINE__) */
1264 @ document.getElementById('changes_section').textContent = 'Changes ' +
1265 @ '(%d(g.diffCnt[0]) file' + (%d(g.diffCnt[0])===1 ? '' : 's') + ': ' +
1266 @ '+%d(g.diffCnt[1]) ' +
1267 @ '−%d(g.diffCnt[2]))'
1268 @ </script>
1269 }
1270 append_diff_javascript(diffType);
1271 style_finish_page();
1272 }
1273
@@ -1449,11 +1507,13 @@
1449 DiffConfig DCfg, *pCfg = 0;
1450 int graphFlags = 0;
1451 Blob qp; /* non-glob= query parameters for generated links */
1452 Blob qpGlob; /* glob= query parameter for generated links */
1453 int bInvert = PB("inv");
 
1454
 
1455 login_check_credentials();
1456 if( !g.perm.Read ){ login_needed(g.anon.Read); return; }
1457 if( robot_restrict("diff") ) return;
1458 login_anonymous_available();
1459 fossil_nice_default();
@@ -1594,18 +1654,18 @@
1594 cmp = fossil_strcmp(pFileFrom->zName, pFileTo->zName);
1595 }
1596 if( cmp<0 ){
1597 if( !pGlob || glob_match(pGlob, pFileFrom->zName) ){
1598 append_file_change_line(zFrom, pFileFrom->zName,
1599 pFileFrom->zUuid, 0, 0, pCfg, 0);
1600 }
1601 pFileFrom = manifest_file_next(pFrom, 0);
1602 }else if( cmp>0 ){
1603 if( !pGlob || glob_match(pGlob, pFileTo->zName) ){
1604 append_file_change_line(zTo, pFileTo->zName,
1605 0, pFileTo->zUuid, 0, pCfg,
1606 manifest_file_mperm(pFileTo));
1607 }
1608 pFileTo = manifest_file_next(pTo, 0);
1609 }else if( fossil_strcmp(pFileFrom->zUuid, pFileTo->zUuid)==0 ){
1610 pFileFrom = manifest_file_next(pFrom, 0);
1611 pFileTo = manifest_file_next(pTo, 0);
@@ -1613,11 +1673,11 @@
1613 if(!pGlob || (glob_match(pGlob, pFileFrom->zName)
1614 || glob_match(pGlob, pFileTo->zName)) ){
1615 append_file_change_line(zFrom, pFileFrom->zName,
1616 pFileFrom->zUuid,
1617 pFileTo->zUuid, 0, pCfg,
1618 manifest_file_mperm(pFileTo));
1619 }
1620 pFileFrom = manifest_file_next(pFrom, 0);
1621 pFileTo = manifest_file_next(pTo, 0);
1622 }
1623 }
1624
--- src/info.c
+++ src/info.c
@@ -371,10 +371,21 @@
371 pCfg->zLeftHash = 0;
372 blob_reset(&from);
373 blob_reset(&to);
374 }
375
376 /*
377 ** The append_file_change_line() routine updates an array of counts
378 ** for various kinds of changes.
379 */
380 #define FCHNG_NEW 0
381 #define FCHNG_DELETE 1
382 #define FCHNG_RENAME 2
383 #define FCHNG_MODE 3
384 #define FCHNG_EDIT 4
385 #define N_FCHNG 5
386
387 /*
388 ** Write a line of web-page output that shows changes that have occurred
389 ** to a file between two check-ins.
390 */
391 static void append_file_change_line(
@@ -382,32 +393,38 @@
393 const char *zName, /* Name of the file that has changed */
394 const char *zOld, /* blob.uuid before change. NULL for added files */
395 const char *zNew, /* blob.uuid after change. NULL for deletes */
396 const char *zOldName, /* Prior name. NULL if no name change. */
397 DiffConfig *pCfg, /* Flags for text_diff() or NULL to omit all */
398 int mperm, /* executable or symlink permission for zNew */
399 int *aChng /* Change count array */
400 ){
401 @ <div class='file-change-line'><span>
402 /* Maintenance reminder: the extra level of SPAN is for
403 ** arranging new elements via JS. */
404 if( !g.perm.Hyperlink ){
405 if( zNew==0 ){
406 @ Deleted %h(zName).
407 aChng[FCHNG_DELETE]++;
408 }else if( zOld==0 ){
409 @ Added %h(zName).
410 aChng[FCHNG_NEW]++;
411 }else if( zOldName!=0 && fossil_strcmp(zName,zOldName)!=0 ){
412 @ Name change from %h(zOldName) to %h(zName).
413 aChng[FCHNG_RENAME]++;
414 }else if( fossil_strcmp(zNew, zOld)==0 ){
415 if( mperm==PERM_EXE ){
416 @ %h(zName) became executable.
417 }else if( mperm==PERM_LNK ){
418 @ %h(zName) became a symlink.
419 }else{
420 @ %h(zName) became a regular file.
421 }
422 aChng[FCHNG_MODE]++;
423 }else{
424 @ Changes to %h(zName).
425 aChng[FCHNG_EDIT]++;
426 }
427 @ </span></div>
428 if( pCfg ){
429 append_diff(zOld, zNew, pCfg);
430 }
@@ -422,22 +439,25 @@
439 @ %h(zOldName)</a>
440 @ %z(href("%R/artifact/%!S",zOld))[%S(zOld)]</a>
441 @ to %z(href("%R/finfo?name=%T&m=%!S&ci=%s",zName,zNew,zCkin2))\
442 @ %h(zName)</a>
443 @ %z(href("%R/artifact/%!S",zNew))[%S(zNew)]</a>.
444 aChng[FCHNG_RENAME]++;
445 }else{
446 @ Modified %z(href("%R/finfo?name=%T&m=%!S&ci=%s",zName,zNew,zCkin2))\
447 @ %h(zName)</a>
448 @ from %z(href("%R/artifact/%!S",zOld))[%S(zOld)]</a>
449 @ to %z(href("%R/artifact/%!S",zNew))[%S(zNew)]</a>.
450 }
451 aChng[FCHNG_EDIT]++;
452 }else if( zOldName!=0 && fossil_strcmp(zName,zOldName)!=0 ){
453 @ Name change
454 @ from %z(href("%R/finfo?name=%T&m=%!S&ci=%s",zOldName,zOld,zCkin2))\
455 @ %h(zOldName)</a>
456 @ to %z(href("%R/finfo?name=%T&m=%!S&ci=%s",zName,zNew,zCkin2))\
457 @ %h(zName)</a>.
458 aChng[FCHNG_RENAME]++;
459 }else{
460 @ %z(href("%R/finfo?name=%T&m=%!S&ci=%s",zName,zNew,zCkin2))\
461 @ %h(zName)</a> became
462 if( mperm==PERM_EXE ){
463 @ executable with contents
@@ -445,17 +465,20 @@
465 @ a symlink with target
466 }else{
467 @ a regular file with contents
468 }
469 @ %z(href("%R/artifact/%!S",zNew))[%S(zNew)]</a>.
470 aChng[FCHNG_MODE]++;
471 }
472 }else if( zOld ){
473 @ Deleted %z(href("%R/finfo?name=%T&m=%!S&ci=%s",zName,zOld,zCkin2))\
474 @ %h(zName)</a> version %z(href("%R/artifact/%!S",zOld))[%S(zOld)]</a>.
475 aChng[FCHNG_DELETE]++;
476 }else{
477 @ Added %z(href("%R/finfo?name=%T&m=%!S&ci=%s",zName,zNew,zCkin2))\
478 @ %h(zName)</a> version %z(href("%R/artifact/%!S",zNew))[%S(zNew)]</a>.
479 aChng[FCHNG_NEW]++;
480 }
481 if( zOld && zNew && fossil_strcmp(zOld,zNew)!=0 ){
482 if( pCfg ){
483 @ </span></div>
484 append_diff(zOld, zNew, pCfg);
@@ -624,10 +647,58 @@
647 www_print_timeline(&q, TIMELINE_DISJOINT|TIMELINE_GRAPH|TIMELINE_NOSCROLL,
648 &xtra);
649 db_finalize(&q);
650 style_finish_page();
651 }
652
653 /*
654 ** Generate JS code that will adjust the change counts in the title
655 ** of the "changes_section" panel where "changes_section" is a JS id.
656 **
657 ** The change counts are taken from g.diffCnt[] for edits, and from
658 ** the aChng[] parameter for additions, deletions, and modifications.
659 ** The aChng parameter may be NULL, in which case those factors are
660 ** ignored.
661 */
662 static void adjust_changes_section_title(
663 int iLine, /* Souce code line number of caller */
664 int *aChng /* Change categories */
665 ){
666 sqlite3_str *pTxt = sqlite3_str_new(0);
667 if( g.diffCnt[0]>0 ){
668 sqlite3_str_appendf(pTxt, "%d file%s edited [+%d -%d lines]",
669 g.diffCnt[0], g.diffCnt[0]==1 ? "" : "s",
670 g.diffCnt[1], g.diffCnt[2]);
671 }
672 if( aChng ){
673 static const int aiType[] =
674 { FCHNG_NEW, FCHNG_DELETE, FCHNG_RENAME, FCHNG_MODE };
675 static const char *azType[] =
676 { "added", "deleted", "renamed", "mode change"};
677 int i;
678 for(i=0; i<4; i++){
679 int j = aiType[i];
680 if( aChng[j] ){
681 const char *zFiles = "";
682 if( sqlite3_str_length(pTxt)>0 ){
683 sqlite3_str_append(pTxt,", ", 2);
684 }else{
685 zFiles = i<3 && aChng[j]>1 ? " files" : " file";
686 }
687 sqlite3_str_appendf(pTxt,"%d%s %s", aChng[j], zFiles, azType[i]);
688 if( i==3 && aChng[j]>1 ) sqlite3_str_appendf(pTxt, "s");
689 }
690 }
691 }
692 if( sqlite3_str_length(pTxt)>0 ){
693 @ <script nonce='%h(style_nonce())'>;/* info.c:%d(iLine) */
694 @ document.getElementById('changes_section').textContent = \
695 @ 'Changes (%h(sqlite3_str_value(pTxt)))'
696 @ </script>
697 }
698 sqlite3_str_free(pTxt);
699 }
700
701 /*
702 ** Render a web-page diff of the changes in the working check-out
703 */
704 static void ckout_normal_diff(int vid){
@@ -734,16 +805,11 @@
805 blob_reset(&old);
806 blob_reset(&new);
807 }
808 }
809 db_finalize(&q);
810 adjust_changes_section_title(__LINE__, 0);
 
 
 
 
 
811 append_diff_javascript(diffType);
812 }
813
814 /*
815 ** Render a web-page diff of the changes in the working check-out to
@@ -827,16 +893,11 @@
893 }
894 fossil_free(zLhs);
895 fossil_free(zRhs);
896 }
897 db_finalize(&q);
898 adjust_changes_section_title(__LINE__, 0);
 
 
 
 
 
899 append_diff_javascript(diffType);
900 }
901
902 /*
903 ** WEBPAGE: ckout
@@ -935,11 +996,13 @@
996 ReCompiled *pRe = 0; /* regex */
997 const char *zW; /* URL param for ignoring whitespace */
998 const char *zPage = "vinfo"; /* Page that shows diffs */
999 const char *zBrName; /* Branch name */
1000 DiffConfig DCfg,*pCfg; /* Type of diff */
1001 int aChng[N_FCHNG]; /* Counts of change types */
1002
1003 memset(aChng, 0, sizeof(aChng));
1004 login_check_credentials();
1005 if( !g.perm.Read ){ login_needed(g.anon.Read); return; }
1006 style_set_current_feature("vinfo");
1007 zName = P("name");
1008 rid = name_to_rid_www("name");
@@ -1253,21 +1316,16 @@
1316 int mperm = db_column_int(&q3, 1);
1317 const char *zOld = db_column_text(&q3,2);
1318 const char *zNew = db_column_text(&q3,3);
1319 const char *zOldName = db_column_text(&q3, 4);
1320 append_file_change_line(zUuid, zName, zOld, zNew, zOldName,
1321 pCfg,mperm,aChng);
1322 }
1323 db_finalize(&q3);
1324 @ </div>
1325 if( diffType!=0 ){
1326 adjust_changes_section_title(__LINE__, aChng);
 
 
 
 
 
1327 }
1328 append_diff_javascript(diffType);
1329 style_finish_page();
1330 }
1331
@@ -1449,11 +1507,13 @@
1507 DiffConfig DCfg, *pCfg = 0;
1508 int graphFlags = 0;
1509 Blob qp; /* non-glob= query parameters for generated links */
1510 Blob qpGlob; /* glob= query parameter for generated links */
1511 int bInvert = PB("inv");
1512 int aChng[N_FCHNG]; /* Count of versiou change types */
1513
1514 memset(aChng, 0, sizeof(aChng));
1515 login_check_credentials();
1516 if( !g.perm.Read ){ login_needed(g.anon.Read); return; }
1517 if( robot_restrict("diff") ) return;
1518 login_anonymous_available();
1519 fossil_nice_default();
@@ -1594,18 +1654,18 @@
1654 cmp = fossil_strcmp(pFileFrom->zName, pFileTo->zName);
1655 }
1656 if( cmp<0 ){
1657 if( !pGlob || glob_match(pGlob, pFileFrom->zName) ){
1658 append_file_change_line(zFrom, pFileFrom->zName,
1659 pFileFrom->zUuid, 0, 0, pCfg, 0,aChng);
1660 }
1661 pFileFrom = manifest_file_next(pFrom, 0);
1662 }else if( cmp>0 ){
1663 if( !pGlob || glob_match(pGlob, pFileTo->zName) ){
1664 append_file_change_line(zTo, pFileTo->zName,
1665 0, pFileTo->zUuid, 0, pCfg,
1666 manifest_file_mperm(pFileTo),aChng);
1667 }
1668 pFileTo = manifest_file_next(pTo, 0);
1669 }else if( fossil_strcmp(pFileFrom->zUuid, pFileTo->zUuid)==0 ){
1670 pFileFrom = manifest_file_next(pFrom, 0);
1671 pFileTo = manifest_file_next(pTo, 0);
@@ -1613,11 +1673,11 @@
1673 if(!pGlob || (glob_match(pGlob, pFileFrom->zName)
1674 || glob_match(pGlob, pFileTo->zName)) ){
1675 append_file_change_line(zFrom, pFileFrom->zName,
1676 pFileFrom->zUuid,
1677 pFileTo->zUuid, 0, pCfg,
1678 manifest_file_mperm(pFileTo),aChng);
1679 }
1680 pFileFrom = manifest_file_next(pFrom, 0);
1681 pFileTo = manifest_file_next(pTo, 0);
1682 }
1683 }
1684

Keyboard Shortcuts

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