Fossil SCM

Improved limit handling for annotation. The limit can now be expressed in compute-time seconds rather than versions analyzed, and defaults to "1.0s", which is enough to compute a complete annotation on most reasonable files.

drh 2017-09-25 17:24 trunk
Commit 517b9a5652649c95dbeae4c5f9f8621d6918d54c2f74c288c560ee8c3e38f86b
2 files changed +97 -61 +7
+97 -61
--- src/diff.c
+++ src/diff.c
@@ -41,11 +41,11 @@
4141
#define DIFF_NOOPT (((u64)0x01)<<32) /* Suppress optimizations (debug) */
4242
#define DIFF_INVERT (((u64)0x02)<<32) /* Invert the diff (debug) */
4343
#define DIFF_CONTEXT_EX (((u64)0x04)<<32) /* Use context even if zero */
4444
#define DIFF_NOTTOOBIG (((u64)0x08)<<32) /* Only display if not too big */
4545
#define DIFF_STRIP_EOLCR (((u64)0x10)<<32) /* Strip trailing CR */
46
-#define DIFF_SLOW_SBS (((u64)0x20)<<32) /* Better, but slower side-by-side */
46
+#define DIFF_SLOW_SBS (((u64)0x20)<<32) /* Better but slower side-by-side */
4747
4848
/*
4949
** These error messages are shared in multiple locations. They are defined
5050
** here for consistency.
5151
*/
@@ -2083,11 +2083,11 @@
20832083
short int n; /* Number of bytes (omitting trailing \n) */
20842084
short int iVers; /* Level at which tag was set */
20852085
} *aOrig;
20862086
int nOrig; /* Number of elements in aOrig[] */
20872087
int nVers; /* Number of versions analyzed */
2088
- int bLimit; /* True if the iLimit was reached */
2088
+ int bMoreToDo; /* True if the limit was reached */
20892089
struct AnnVers {
20902090
const char *zFUuid; /* File being analyzed */
20912091
const char *zMUuid; /* Check-in containing the file */
20922092
const char *zDate; /* Date of the check-in */
20932093
const char *zBgColor; /* Suggested background color */
@@ -2176,32 +2176,64 @@
21762176
21772177
/* Return no errors */
21782178
return 0;
21792179
}
21802180
2181
+/* Return the current time as milliseconds since the Julian epoch */
2182
+static sqlite3_int64 current_time_in_milliseconds(void){
2183
+ static sqlite3_vfs *clockVfs = 0;
2184
+ sqlite3_int64 t;
2185
+ if( clockVfs==0 ) clockVfs = sqlite3_vfs_find(0);
2186
+ if( clockVfs->iVersion>=2 && clockVfs->xCurrentTimeInt64!=0 ){
2187
+ clockVfs->xCurrentTimeInt64(clockVfs, &t);
2188
+ }else{
2189
+ double r;
2190
+ clockVfs->xCurrentTime(clockVfs, &r);
2191
+ t = (sqlite3_int64)(r*86400000.0);
2192
+ }
2193
+ return t;
2194
+}
21812195
21822196
/*
21832197
** Compute a complete annotation on a file. The file is identified by its
21842198
** filename and check-in name (NULL for current check-in).
21852199
*/
21862200
static void annotate_file(
2187
- Annotator *p, /* The annotator */
2188
- const char *zFilename,/* The name of the file to be annotated */
2189
- const char *zRevision,/* Use the version of the file in this check-in */
2190
- int iLimit, /* Limit the number of levels if greater than zero */
2191
- u64 annFlags /* Flags to alter the annotation */
2201
+ Annotator *p, /* The annotator */
2202
+ const char *zFilename, /* The name of the file to be annotated */
2203
+ const char *zRevision, /* Use the version of the file in this check-in */
2204
+ const char *zLimit, /* Limit the number of versions analyzed */
2205
+ u64 annFlags /* Flags to alter the annotation */
21922206
){
2193
- Blob toAnnotate; /* Text of the final (mid) version of the file */
2194
- Blob step; /* Text of previous revision */
2195
- Blob treename; /* FILENAME translated to canonical form */
2196
- int cid; /* Selected check-in ID */
2197
- int rid; /* Artifact ID of the file being annotated */
2198
- int fnid; /* Filename ID */
2199
- Stmt q; /* Query returning all ancestor versions */
2200
- int cnt = 0; /* Number of versions analyzed */
2201
-
2202
- if( iLimit<=0 ) iLimit = 1000000000; /* A negative limit means no limit */
2207
+ Blob toAnnotate; /* Text of the final (mid) version of the file */
2208
+ Blob step; /* Text of previous revision */
2209
+ Blob treename; /* FILENAME translated to canonical form */
2210
+ int cid; /* Selected check-in ID */
2211
+ int rid; /* Artifact ID of the file being annotated */
2212
+ int fnid; /* Filename ID */
2213
+ Stmt q; /* Query returning all ancestor versions */
2214
+ int cnt = 0; /* Number of versions analyzed */
2215
+ int iLimit; /* Maximum number of versions to analyze */
2216
+ sqlite3_int64 mxTime; /* Halt at this time if not already complete */
2217
+
2218
+ if( zLimit ){
2219
+ if( strcmp(zLimit,"none")==0 ){
2220
+ iLimit = 0;
2221
+ mxTime = 0;
2222
+ }else if( sqlite3_strglob("*[0-9]s", zLimit)==0 ){
2223
+ iLimit = 0;
2224
+ mxTime = current_time_in_milliseconds() + 1000.0*atof(zLimit);
2225
+ }else{
2226
+ iLimit = atoi(zLimit);
2227
+ if( iLimit<=0 ) iLimit = 30;
2228
+ mxTime = 0;
2229
+ }
2230
+ }else{
2231
+ /* Default limit is as much as we can do in 1.000 seconds */
2232
+ iLimit = 0;
2233
+ mxTime = current_time_in_milliseconds()+1000;
2234
+ }
22032235
db_begin_transaction();
22042236
22052237
/* Get the artificate ID for the check-in begin analyzed */
22062238
if( zRevision ){
22072239
cid = name_to_typed_rid(zRevision, "ci");
@@ -2233,19 +2265,27 @@
22332265
" AND mlink.mid!=mlink.pid"
22342266
" ORDER BY ancestor.generation;",
22352267
fnid
22362268
);
22372269
2238
- if( iLimit==0 ) iLimit = 1000000000;
2239
- while( iLimit>cnt && db_step(&q)==SQLITE_ROW ){
2270
+ while( db_step(&q)==SQLITE_ROW ){
2271
+ if( cnt>=3 ){ /* Process at least 3 rows before imposing limits */
2272
+ if( (iLimit>0 && cnt>=iLimit)
2273
+ || (cnt>0 && mxTime>0 && current_time_in_milliseconds()>mxTime)
2274
+ ){
2275
+ p->bMoreToDo = 1;
2276
+ break;
2277
+ }
2278
+ }
22402279
rid = db_column_int(&q, 4);
22412280
if( cnt==0 ){
22422281
if( !content_get(rid, &toAnnotate) ){
22432282
fossil_fatal("unable to retrieve content of artifact #%d", rid);
22442283
}
22452284
blob_to_utf8_no_bom(&toAnnotate, 0);
22462285
annotation_start(p, &toAnnotate, annFlags);
2286
+ p->bMoreToDo = 0;
22472287
}
22482288
p->aVers = fossil_realloc(p->aVers, (p->nVers+1)*sizeof(p->aVers[0]));
22492289
p->aVers[p->nVers].zFUuid = fossil_strdup(db_column_text(&q, 0));
22502290
p->aVers[p->nVers].zMUuid = fossil_strdup(db_column_text(&q, 1));
22512291
p->aVers[p->nVers].zDate = fossil_strdup(db_column_text(&q, 2));
@@ -2257,11 +2297,10 @@
22572297
annotation_step(p, &step, p->nVers-1, annFlags);
22582298
blob_reset(&step);
22592299
}
22602300
cnt++;
22612301
}
2262
- p->bLimit = iLimit==cnt;
22632302
db_finalize(&q);
22642303
db_end_transaction(0);
22652304
}
22662305
22672306
/*
@@ -2300,25 +2339,29 @@
23002339
** Query parameters:
23012340
**
23022341
** checkin=ID The manifest ID at which to start the annotation
23032342
** filename=FILENAME The filename.
23042343
** filevers=BOOLEAN Show file versions rather than check-in versions
2305
-** limit=N Limit the search depth to N ancestors
2344
+** limit=LIMIT Limit the amount of analysis:
2345
+** "none" No limit
2346
+** "Xs" As much as can be computed in X seconds
2347
+** "N" N versions
23062348
** log=BOOLEAN Show a log of versions analyzed
23072349
** w=BOOLEAN Ignore whitespace
23082350
**
23092351
*/
23102352
void annotation_page(void){
23112353
int i;
2312
- int iLimit; /* Depth limit */
2354
+ const char *zLimit; /* Depth limit */
23132355
u64 annFlags = DIFF_STRIP_EOLCR;
23142356
int showLog; /* True to display the log */
23152357
int fileVers; /* Show file version instead of check-in versions */
23162358
int ignoreWs; /* Ignore whitespace */
23172359
const char *zFilename; /* Name of file to annotate */
23182360
const char *zRevision; /* Name of check-in from which to start annotation */
23192361
const char *zCI; /* The check-in containing zFilename */
2362
+ int szHash; /* Number of characters in %S display */
23202363
char *zLink;
23212364
Annotator ann;
23222365
HQuery url;
23232366
struct AnnVers *p;
23242367
unsigned clr1, clr2, clr;
@@ -2329,18 +2372,18 @@
23292372
if( !g.perm.Read ){ login_needed(g.anon.Read); return; }
23302373
if( exclude_spiders() ) return;
23312374
load_control();
23322375
zFilename = P("filename");
23332376
zRevision = PD("checkin",0);
2334
- iLimit = atoi(PD("limit","20"));
2377
+ zLimit = P("limit");
23352378
showLog = PB("log");
23362379
fileVers = PB("filevers");
23372380
ignoreWs = PB("w");
23382381
if( ignoreWs ) annFlags |= DIFF_IGNORE_ALLWS;
23392382
23402383
/* compute the annotation */
2341
- annotate_file(&ann, zFilename, zRevision, iLimit, annFlags);
2384
+ annotate_file(&ann, zFilename, zRevision, zLimit, annFlags);
23422385
zCI = ann.aVers[0].zMUuid;
23432386
23442387
/* generate the web page */
23452388
style_header("Annotation For %h", zFilename);
23462389
if( bBlame ){
@@ -2348,30 +2391,22 @@
23482391
}else{
23492392
url_initialize(&url, "annotate");
23502393
}
23512394
url_add_parameter(&url, "checkin", P("checkin"));
23522395
url_add_parameter(&url, "filename", zFilename);
2353
- if( iLimit!=20 ){
2354
- url_add_parameter(&url, "limit", sqlite3_mprintf("%d", iLimit));
2396
+ if( zLimit ){
2397
+ url_add_parameter(&url, "limit", zLimit);
23552398
}
23562399
url_add_parameter(&url, "w", ignoreWs ? "1" : "0");
23572400
url_add_parameter(&url, "log", showLog ? "1" : "0");
23582401
url_add_parameter(&url, "filevers", fileVers ? "1" : "0");
23592402
style_submenu_checkbox("w", "Ignore Whitespace", 0, 0);
23602403
style_submenu_checkbox("log", "Log", 0, "toggle_annotation_log()");
23612404
style_submenu_checkbox("filevers", "Link to Files", 0, 0);
2362
- if( ann.bLimit ){
2363
- char *z1, *z2;
2405
+ if( ann.bMoreToDo ){
23642406
style_submenu_element("All Ancestors", "%s",
2365
- url_render(&url, "limit", "-1", 0, 0));
2366
- z1 = sqlite3_mprintf("%d Ancestors", iLimit+20);
2367
- z2 = sqlite3_mprintf("%d", iLimit+20);
2368
- style_submenu_element(z1, "%s", url_render(&url, "limit", z2, 0, 0));
2369
- }
2370
- if( iLimit>20 ){
2371
- style_submenu_element("20 Ancestors", "%s",
2372
- url_render(&url, "limit", "20", 0, 0));
2407
+ url_render(&url, "limit", "none", 0, 0));
23732408
}
23742409
if( skin_detail_boolean("white-foreground") ){
23752410
clr1 = 0xa04040;
23762411
clr2 = 0x4059a0;
23772412
}else{
@@ -2381,11 +2416,11 @@
23812416
for(p=ann.aVers, i=0; i<ann.nVers; i++, p++){
23822417
clr = gradient_color(clr1, clr2, ann.nVers-1, i);
23832418
ann.aVers[i].zBgColor = mprintf("#%06x", clr);
23842419
}
23852420
2386
- @ <div id="annotation_log" style='display:%s(showLog?"block":"none")'>
2421
+ @ <div id="annotation_log" style='display:%s(showLog?"block":"none");'>
23872422
zLink = href("%R/finfo?name=%t&ci=%!S",zFilename,zCI);
23882423
@ <h2>Versions of %z(zLink)%h(zFilename)</a> analyzed:</h2>
23892424
@ <ol>
23902425
for(p=ann.aVers, i=0; i<ann.nVers; i++, p++){
23912426
@ <li><span style='background-color:%s(p->zBgColor);'>%s(p->zDate)
@@ -2402,28 +2437,28 @@
24022437
@ var x = document.forms["f01"].elements["log"].checked
24032438
@ w.style.display = x ? "block" : "none";
24042439
@ }
24052440
@ </script>
24062441
2407
- if( !ann.bLimit ){
2442
+ if( !ann.bMoreToDo ){
24082443
@ <h2>Origin for each line in
24092444
@ %z(href("%R/finfo?name=%h&ci=%!S", zFilename, zCI))%h(zFilename)</a>
24102445
@ from check-in %z(href("%R/info/%!S",zCI))%S(zCI)</a>:</h2>
2411
- iLimit = ann.nVers+10;
24122446
}else{
2413
- @ <h2>Lines added by the %d(iLimit) most recent ancestors of
2447
+ @ <h2>Lines added by the %d(ann.nVers) most recent ancestors of
24142448
@ %z(href("%R/finfo?name=%h&ci=%!S", zFilename, zCI))%h(zFilename)</a>
24152449
@ from check-in %z(href("%R/info/%!S",zCI))%S(zCI)</a>:</h2>
24162450
}
24172451
@ <pre>
2452
+ szHash = length_of_S_display();
24182453
for(i=0; i<ann.nOrig; i++){
24192454
int iVers = ann.aOrig[i].iVers;
24202455
char *z = (char*)ann.aOrig[i].z;
24212456
int n = ann.aOrig[i].n;
24222457
char zPrefix[300];
24232458
z[n] = 0;
2424
- if( iLimit>ann.nVers && iVers<0 ) iVers = ann.nVers-1;
2459
+ if( iVers<0 && !ann.bMoreToDo ) iVers = ann.nVers-1;
24252460
24262461
if( bBlame ){
24272462
if( iVers>=0 ){
24282463
struct AnnVers *p = ann.aVers+iVers;
24292464
const char *zUuid = fileVers ? p->zFUuid : p->zMUuid;
@@ -2432,11 +2467,11 @@
24322467
"<span style='background-color:%s'>"
24332468
"%s%.10s</a> %s</span> %13.13s:",
24342469
p->zBgColor, zLink, zUuid, p->zDate, p->zUser);
24352470
fossil_free(zLink);
24362471
}else{
2437
- sqlite3_snprintf(sizeof(zPrefix), zPrefix, "%36s", "");
2472
+ sqlite3_snprintf(sizeof(zPrefix), zPrefix, "%*s", szHash+28, "");
24382473
}
24392474
}else{
24402475
if( iVers>=0 ){
24412476
struct AnnVers *p = ann.aVers+iVers;
24422477
const char *zUuid = fileVers ? p->zFUuid : p->zMUuid;
@@ -2445,11 +2480,11 @@
24452480
"<span style='background-color:%s'>"
24462481
"%s%.10s</a> %s</span> %4d:",
24472482
p->zBgColor, zLink, zUuid, p->zDate, i+1);
24482483
fossil_free(zLink);
24492484
}else{
2450
- sqlite3_snprintf(sizeof(zPrefix), zPrefix, "%22s%4d:", "", i+1);
2485
+ sqlite3_snprintf(sizeof(zPrefix), zPrefix, "%*s%4d:",szHash+14,"",i+1);
24512486
}
24522487
}
24532488
@ %s(zPrefix) %h(z)
24542489
24552490
}
@@ -2473,33 +2508,33 @@
24732508
** Options:
24742509
** --filevers Show file version numbers rather than
24752510
** check-in versions
24762511
** -r|--revision VERSION The specific check-in containing the file
24772512
** -l|--log List all versions analyzed
2478
-** -n|--limit N Only look backwards in time by N versions
2513
+** -n|--limit LIMIT Limit the amount of analysis:
2514
+** N Up to N versions
2515
+** Xs As much as possible in X seconds
2516
+** none No limit
24792517
** -w|--ignore-all-space Ignore white space when comparing lines
24802518
** -Z|--ignore-trailing-space Ignore whitespace at line end
24812519
**
24822520
** See also: info, finfo, timeline
24832521
*/
24842522
void annotate_cmd(void){
24852523
const char *zRevision; /* Revision name, or NULL for current check-in */
2486
- Annotator ann; /* The annotation of the file */
2487
- int i; /* Loop counter */
2488
- const char *zLimit; /* The value to the -n|--limit option */
2489
- int iLimit; /* How far back in time to look */
2490
- int showLog; /* True to show the log */
2491
- int fileVers; /* Show file version instead of check-in versions */
2492
- u64 annFlags = 0; /* Flags to control annotation properties */
2493
- int bBlame = 0; /* True for BLAME output. False for ANNOTATE. */
2524
+ Annotator ann; /* The annotation of the file */
2525
+ int i; /* Loop counter */
2526
+ const char *zLimit; /* The value to the -n|--limit option */
2527
+ int showLog; /* True to show the log */
2528
+ int fileVers; /* Show file version instead of check-in versions */
2529
+ u64 annFlags = 0; /* Flags to control annotation properties */
2530
+ int bBlame = 0; /* True for BLAME output. False for ANNOTATE. */
2531
+ int szHash; /* Display size of a version hash */
24942532
24952533
bBlame = g.argv[1][0]!='a';
24962534
zRevision = find_option("r","revision",1);
24972535
zLimit = find_option("limit","n",1);
2498
- if( zLimit==0 || zLimit[0]==0 ) zLimit = "-1";
2499
- iLimit = atoi(zLimit);
2500
- if( iLimit<=0 ) iLimit = 1000000000;
25012536
showLog = find_option("log","l",0)!=0;
25022537
if( find_option("ignore-trailing-space","Z",0)!=0 ){
25032538
annFlags = DIFF_IGNORE_EOLWS;
25042539
}
25052540
if( find_option("ignore-all-space","w",0)!=0 ){
@@ -2514,39 +2549,40 @@
25142549
if( g.argc<3 ) {
25152550
usage("FILENAME");
25162551
}
25172552
25182553
annFlags |= DIFF_STRIP_EOLCR;
2519
- annotate_file(&ann, g.argv[2], zRevision, iLimit, annFlags);
2554
+ annotate_file(&ann, g.argv[2], zRevision, zLimit, annFlags);
25202555
if( showLog ){
25212556
struct AnnVers *p;
25222557
for(p=ann.aVers, i=0; i<ann.nVers; i++, p++){
25232558
fossil_print("version %3d: %s %S file %S\n",
25242559
i+1, p->zDate, p->zMUuid, p->zFUuid);
25252560
}
25262561
fossil_print("---------------------------------------------------\n");
25272562
}
2563
+ szHash = length_of_S_display();
25282564
for(i=0; i<ann.nOrig; i++){
25292565
int iVers = ann.aOrig[i].iVers;
25302566
char *z = (char*)ann.aOrig[i].z;
25312567
int n = ann.aOrig[i].n;
25322568
struct AnnVers *p;
2533
- if( iLimit>ann.nVers && iVers<0 ) iVers = ann.nVers-1;
2534
- p = ann.aVers + iVers;
2569
+ if( iVers<0 && !ann.bMoreToDo ) iVers = ann.nVers-1;
25352570
if( bBlame ){
25362571
if( iVers>=0 ){
2572
+ p = ann.aVers + iVers;
25372573
fossil_print("%S %s %13.13s: %.*s\n",
25382574
fileVers ? p->zFUuid : p->zMUuid, p->zDate, p->zUser, n, z);
25392575
}else{
2540
- fossil_print("%35s %.*s\n", "", n, z);
2576
+ fossil_print("%*s %.*s\n", szHash+26, "", n, z);
25412577
}
25422578
}else{
25432579
if( iVers>=0 ){
2580
+ p = ann.aVers + iVers;
25442581
fossil_print("%S %s %5d: %.*s\n",
25452582
fileVers ? p->zFUuid : p->zMUuid, p->zDate, i+1, n, z);
25462583
}else{
2547
- fossil_print("%21s %5d: %.*s\n",
2548
- "", i+1, n, z);
2584
+ fossil_print("%*s %5d: %.*s\n", szHash+11, "", i+1, n, z);
25492585
}
25502586
}
25512587
}
25522588
}
25532589
--- src/diff.c
+++ src/diff.c
@@ -41,11 +41,11 @@
41 #define DIFF_NOOPT (((u64)0x01)<<32) /* Suppress optimizations (debug) */
42 #define DIFF_INVERT (((u64)0x02)<<32) /* Invert the diff (debug) */
43 #define DIFF_CONTEXT_EX (((u64)0x04)<<32) /* Use context even if zero */
44 #define DIFF_NOTTOOBIG (((u64)0x08)<<32) /* Only display if not too big */
45 #define DIFF_STRIP_EOLCR (((u64)0x10)<<32) /* Strip trailing CR */
46 #define DIFF_SLOW_SBS (((u64)0x20)<<32) /* Better, but slower side-by-side */
47
48 /*
49 ** These error messages are shared in multiple locations. They are defined
50 ** here for consistency.
51 */
@@ -2083,11 +2083,11 @@
2083 short int n; /* Number of bytes (omitting trailing \n) */
2084 short int iVers; /* Level at which tag was set */
2085 } *aOrig;
2086 int nOrig; /* Number of elements in aOrig[] */
2087 int nVers; /* Number of versions analyzed */
2088 int bLimit; /* True if the iLimit was reached */
2089 struct AnnVers {
2090 const char *zFUuid; /* File being analyzed */
2091 const char *zMUuid; /* Check-in containing the file */
2092 const char *zDate; /* Date of the check-in */
2093 const char *zBgColor; /* Suggested background color */
@@ -2176,32 +2176,64 @@
2176
2177 /* Return no errors */
2178 return 0;
2179 }
2180
 
 
 
 
 
 
 
 
 
 
 
 
 
 
2181
2182 /*
2183 ** Compute a complete annotation on a file. The file is identified by its
2184 ** filename and check-in name (NULL for current check-in).
2185 */
2186 static void annotate_file(
2187 Annotator *p, /* The annotator */
2188 const char *zFilename,/* The name of the file to be annotated */
2189 const char *zRevision,/* Use the version of the file in this check-in */
2190 int iLimit, /* Limit the number of levels if greater than zero */
2191 u64 annFlags /* Flags to alter the annotation */
2192 ){
2193 Blob toAnnotate; /* Text of the final (mid) version of the file */
2194 Blob step; /* Text of previous revision */
2195 Blob treename; /* FILENAME translated to canonical form */
2196 int cid; /* Selected check-in ID */
2197 int rid; /* Artifact ID of the file being annotated */
2198 int fnid; /* Filename ID */
2199 Stmt q; /* Query returning all ancestor versions */
2200 int cnt = 0; /* Number of versions analyzed */
2201
2202 if( iLimit<=0 ) iLimit = 1000000000; /* A negative limit means no limit */
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
2203 db_begin_transaction();
2204
2205 /* Get the artificate ID for the check-in begin analyzed */
2206 if( zRevision ){
2207 cid = name_to_typed_rid(zRevision, "ci");
@@ -2233,19 +2265,27 @@
2233 " AND mlink.mid!=mlink.pid"
2234 " ORDER BY ancestor.generation;",
2235 fnid
2236 );
2237
2238 if( iLimit==0 ) iLimit = 1000000000;
2239 while( iLimit>cnt && db_step(&q)==SQLITE_ROW ){
 
 
 
 
 
 
 
2240 rid = db_column_int(&q, 4);
2241 if( cnt==0 ){
2242 if( !content_get(rid, &toAnnotate) ){
2243 fossil_fatal("unable to retrieve content of artifact #%d", rid);
2244 }
2245 blob_to_utf8_no_bom(&toAnnotate, 0);
2246 annotation_start(p, &toAnnotate, annFlags);
 
2247 }
2248 p->aVers = fossil_realloc(p->aVers, (p->nVers+1)*sizeof(p->aVers[0]));
2249 p->aVers[p->nVers].zFUuid = fossil_strdup(db_column_text(&q, 0));
2250 p->aVers[p->nVers].zMUuid = fossil_strdup(db_column_text(&q, 1));
2251 p->aVers[p->nVers].zDate = fossil_strdup(db_column_text(&q, 2));
@@ -2257,11 +2297,10 @@
2257 annotation_step(p, &step, p->nVers-1, annFlags);
2258 blob_reset(&step);
2259 }
2260 cnt++;
2261 }
2262 p->bLimit = iLimit==cnt;
2263 db_finalize(&q);
2264 db_end_transaction(0);
2265 }
2266
2267 /*
@@ -2300,25 +2339,29 @@
2300 ** Query parameters:
2301 **
2302 ** checkin=ID The manifest ID at which to start the annotation
2303 ** filename=FILENAME The filename.
2304 ** filevers=BOOLEAN Show file versions rather than check-in versions
2305 ** limit=N Limit the search depth to N ancestors
 
 
 
2306 ** log=BOOLEAN Show a log of versions analyzed
2307 ** w=BOOLEAN Ignore whitespace
2308 **
2309 */
2310 void annotation_page(void){
2311 int i;
2312 int iLimit; /* Depth limit */
2313 u64 annFlags = DIFF_STRIP_EOLCR;
2314 int showLog; /* True to display the log */
2315 int fileVers; /* Show file version instead of check-in versions */
2316 int ignoreWs; /* Ignore whitespace */
2317 const char *zFilename; /* Name of file to annotate */
2318 const char *zRevision; /* Name of check-in from which to start annotation */
2319 const char *zCI; /* The check-in containing zFilename */
 
2320 char *zLink;
2321 Annotator ann;
2322 HQuery url;
2323 struct AnnVers *p;
2324 unsigned clr1, clr2, clr;
@@ -2329,18 +2372,18 @@
2329 if( !g.perm.Read ){ login_needed(g.anon.Read); return; }
2330 if( exclude_spiders() ) return;
2331 load_control();
2332 zFilename = P("filename");
2333 zRevision = PD("checkin",0);
2334 iLimit = atoi(PD("limit","20"));
2335 showLog = PB("log");
2336 fileVers = PB("filevers");
2337 ignoreWs = PB("w");
2338 if( ignoreWs ) annFlags |= DIFF_IGNORE_ALLWS;
2339
2340 /* compute the annotation */
2341 annotate_file(&ann, zFilename, zRevision, iLimit, annFlags);
2342 zCI = ann.aVers[0].zMUuid;
2343
2344 /* generate the web page */
2345 style_header("Annotation For %h", zFilename);
2346 if( bBlame ){
@@ -2348,30 +2391,22 @@
2348 }else{
2349 url_initialize(&url, "annotate");
2350 }
2351 url_add_parameter(&url, "checkin", P("checkin"));
2352 url_add_parameter(&url, "filename", zFilename);
2353 if( iLimit!=20 ){
2354 url_add_parameter(&url, "limit", sqlite3_mprintf("%d", iLimit));
2355 }
2356 url_add_parameter(&url, "w", ignoreWs ? "1" : "0");
2357 url_add_parameter(&url, "log", showLog ? "1" : "0");
2358 url_add_parameter(&url, "filevers", fileVers ? "1" : "0");
2359 style_submenu_checkbox("w", "Ignore Whitespace", 0, 0);
2360 style_submenu_checkbox("log", "Log", 0, "toggle_annotation_log()");
2361 style_submenu_checkbox("filevers", "Link to Files", 0, 0);
2362 if( ann.bLimit ){
2363 char *z1, *z2;
2364 style_submenu_element("All Ancestors", "%s",
2365 url_render(&url, "limit", "-1", 0, 0));
2366 z1 = sqlite3_mprintf("%d Ancestors", iLimit+20);
2367 z2 = sqlite3_mprintf("%d", iLimit+20);
2368 style_submenu_element(z1, "%s", url_render(&url, "limit", z2, 0, 0));
2369 }
2370 if( iLimit>20 ){
2371 style_submenu_element("20 Ancestors", "%s",
2372 url_render(&url, "limit", "20", 0, 0));
2373 }
2374 if( skin_detail_boolean("white-foreground") ){
2375 clr1 = 0xa04040;
2376 clr2 = 0x4059a0;
2377 }else{
@@ -2381,11 +2416,11 @@
2381 for(p=ann.aVers, i=0; i<ann.nVers; i++, p++){
2382 clr = gradient_color(clr1, clr2, ann.nVers-1, i);
2383 ann.aVers[i].zBgColor = mprintf("#%06x", clr);
2384 }
2385
2386 @ <div id="annotation_log" style='display:%s(showLog?"block":"none")'>
2387 zLink = href("%R/finfo?name=%t&ci=%!S",zFilename,zCI);
2388 @ <h2>Versions of %z(zLink)%h(zFilename)</a> analyzed:</h2>
2389 @ <ol>
2390 for(p=ann.aVers, i=0; i<ann.nVers; i++, p++){
2391 @ <li><span style='background-color:%s(p->zBgColor);'>%s(p->zDate)
@@ -2402,28 +2437,28 @@
2402 @ var x = document.forms["f01"].elements["log"].checked
2403 @ w.style.display = x ? "block" : "none";
2404 @ }
2405 @ </script>
2406
2407 if( !ann.bLimit ){
2408 @ <h2>Origin for each line in
2409 @ %z(href("%R/finfo?name=%h&ci=%!S", zFilename, zCI))%h(zFilename)</a>
2410 @ from check-in %z(href("%R/info/%!S",zCI))%S(zCI)</a>:</h2>
2411 iLimit = ann.nVers+10;
2412 }else{
2413 @ <h2>Lines added by the %d(iLimit) most recent ancestors of
2414 @ %z(href("%R/finfo?name=%h&ci=%!S", zFilename, zCI))%h(zFilename)</a>
2415 @ from check-in %z(href("%R/info/%!S",zCI))%S(zCI)</a>:</h2>
2416 }
2417 @ <pre>
 
2418 for(i=0; i<ann.nOrig; i++){
2419 int iVers = ann.aOrig[i].iVers;
2420 char *z = (char*)ann.aOrig[i].z;
2421 int n = ann.aOrig[i].n;
2422 char zPrefix[300];
2423 z[n] = 0;
2424 if( iLimit>ann.nVers && iVers<0 ) iVers = ann.nVers-1;
2425
2426 if( bBlame ){
2427 if( iVers>=0 ){
2428 struct AnnVers *p = ann.aVers+iVers;
2429 const char *zUuid = fileVers ? p->zFUuid : p->zMUuid;
@@ -2432,11 +2467,11 @@
2432 "<span style='background-color:%s'>"
2433 "%s%.10s</a> %s</span> %13.13s:",
2434 p->zBgColor, zLink, zUuid, p->zDate, p->zUser);
2435 fossil_free(zLink);
2436 }else{
2437 sqlite3_snprintf(sizeof(zPrefix), zPrefix, "%36s", "");
2438 }
2439 }else{
2440 if( iVers>=0 ){
2441 struct AnnVers *p = ann.aVers+iVers;
2442 const char *zUuid = fileVers ? p->zFUuid : p->zMUuid;
@@ -2445,11 +2480,11 @@
2445 "<span style='background-color:%s'>"
2446 "%s%.10s</a> %s</span> %4d:",
2447 p->zBgColor, zLink, zUuid, p->zDate, i+1);
2448 fossil_free(zLink);
2449 }else{
2450 sqlite3_snprintf(sizeof(zPrefix), zPrefix, "%22s%4d:", "", i+1);
2451 }
2452 }
2453 @ %s(zPrefix) %h(z)
2454
2455 }
@@ -2473,33 +2508,33 @@
2473 ** Options:
2474 ** --filevers Show file version numbers rather than
2475 ** check-in versions
2476 ** -r|--revision VERSION The specific check-in containing the file
2477 ** -l|--log List all versions analyzed
2478 ** -n|--limit N Only look backwards in time by N versions
 
 
 
2479 ** -w|--ignore-all-space Ignore white space when comparing lines
2480 ** -Z|--ignore-trailing-space Ignore whitespace at line end
2481 **
2482 ** See also: info, finfo, timeline
2483 */
2484 void annotate_cmd(void){
2485 const char *zRevision; /* Revision name, or NULL for current check-in */
2486 Annotator ann; /* The annotation of the file */
2487 int i; /* Loop counter */
2488 const char *zLimit; /* The value to the -n|--limit option */
2489 int iLimit; /* How far back in time to look */
2490 int showLog; /* True to show the log */
2491 int fileVers; /* Show file version instead of check-in versions */
2492 u64 annFlags = 0; /* Flags to control annotation properties */
2493 int bBlame = 0; /* True for BLAME output. False for ANNOTATE. */
2494
2495 bBlame = g.argv[1][0]!='a';
2496 zRevision = find_option("r","revision",1);
2497 zLimit = find_option("limit","n",1);
2498 if( zLimit==0 || zLimit[0]==0 ) zLimit = "-1";
2499 iLimit = atoi(zLimit);
2500 if( iLimit<=0 ) iLimit = 1000000000;
2501 showLog = find_option("log","l",0)!=0;
2502 if( find_option("ignore-trailing-space","Z",0)!=0 ){
2503 annFlags = DIFF_IGNORE_EOLWS;
2504 }
2505 if( find_option("ignore-all-space","w",0)!=0 ){
@@ -2514,39 +2549,40 @@
2514 if( g.argc<3 ) {
2515 usage("FILENAME");
2516 }
2517
2518 annFlags |= DIFF_STRIP_EOLCR;
2519 annotate_file(&ann, g.argv[2], zRevision, iLimit, annFlags);
2520 if( showLog ){
2521 struct AnnVers *p;
2522 for(p=ann.aVers, i=0; i<ann.nVers; i++, p++){
2523 fossil_print("version %3d: %s %S file %S\n",
2524 i+1, p->zDate, p->zMUuid, p->zFUuid);
2525 }
2526 fossil_print("---------------------------------------------------\n");
2527 }
 
2528 for(i=0; i<ann.nOrig; i++){
2529 int iVers = ann.aOrig[i].iVers;
2530 char *z = (char*)ann.aOrig[i].z;
2531 int n = ann.aOrig[i].n;
2532 struct AnnVers *p;
2533 if( iLimit>ann.nVers && iVers<0 ) iVers = ann.nVers-1;
2534 p = ann.aVers + iVers;
2535 if( bBlame ){
2536 if( iVers>=0 ){
 
2537 fossil_print("%S %s %13.13s: %.*s\n",
2538 fileVers ? p->zFUuid : p->zMUuid, p->zDate, p->zUser, n, z);
2539 }else{
2540 fossil_print("%35s %.*s\n", "", n, z);
2541 }
2542 }else{
2543 if( iVers>=0 ){
 
2544 fossil_print("%S %s %5d: %.*s\n",
2545 fileVers ? p->zFUuid : p->zMUuid, p->zDate, i+1, n, z);
2546 }else{
2547 fossil_print("%21s %5d: %.*s\n",
2548 "", i+1, n, z);
2549 }
2550 }
2551 }
2552 }
2553
--- src/diff.c
+++ src/diff.c
@@ -41,11 +41,11 @@
41 #define DIFF_NOOPT (((u64)0x01)<<32) /* Suppress optimizations (debug) */
42 #define DIFF_INVERT (((u64)0x02)<<32) /* Invert the diff (debug) */
43 #define DIFF_CONTEXT_EX (((u64)0x04)<<32) /* Use context even if zero */
44 #define DIFF_NOTTOOBIG (((u64)0x08)<<32) /* Only display if not too big */
45 #define DIFF_STRIP_EOLCR (((u64)0x10)<<32) /* Strip trailing CR */
46 #define DIFF_SLOW_SBS (((u64)0x20)<<32) /* Better but slower side-by-side */
47
48 /*
49 ** These error messages are shared in multiple locations. They are defined
50 ** here for consistency.
51 */
@@ -2083,11 +2083,11 @@
2083 short int n; /* Number of bytes (omitting trailing \n) */
2084 short int iVers; /* Level at which tag was set */
2085 } *aOrig;
2086 int nOrig; /* Number of elements in aOrig[] */
2087 int nVers; /* Number of versions analyzed */
2088 int bMoreToDo; /* True if the limit was reached */
2089 struct AnnVers {
2090 const char *zFUuid; /* File being analyzed */
2091 const char *zMUuid; /* Check-in containing the file */
2092 const char *zDate; /* Date of the check-in */
2093 const char *zBgColor; /* Suggested background color */
@@ -2176,32 +2176,64 @@
2176
2177 /* Return no errors */
2178 return 0;
2179 }
2180
2181 /* Return the current time as milliseconds since the Julian epoch */
2182 static sqlite3_int64 current_time_in_milliseconds(void){
2183 static sqlite3_vfs *clockVfs = 0;
2184 sqlite3_int64 t;
2185 if( clockVfs==0 ) clockVfs = sqlite3_vfs_find(0);
2186 if( clockVfs->iVersion>=2 && clockVfs->xCurrentTimeInt64!=0 ){
2187 clockVfs->xCurrentTimeInt64(clockVfs, &t);
2188 }else{
2189 double r;
2190 clockVfs->xCurrentTime(clockVfs, &r);
2191 t = (sqlite3_int64)(r*86400000.0);
2192 }
2193 return t;
2194 }
2195
2196 /*
2197 ** Compute a complete annotation on a file. The file is identified by its
2198 ** filename and check-in name (NULL for current check-in).
2199 */
2200 static void annotate_file(
2201 Annotator *p, /* The annotator */
2202 const char *zFilename, /* The name of the file to be annotated */
2203 const char *zRevision, /* Use the version of the file in this check-in */
2204 const char *zLimit, /* Limit the number of versions analyzed */
2205 u64 annFlags /* Flags to alter the annotation */
2206 ){
2207 Blob toAnnotate; /* Text of the final (mid) version of the file */
2208 Blob step; /* Text of previous revision */
2209 Blob treename; /* FILENAME translated to canonical form */
2210 int cid; /* Selected check-in ID */
2211 int rid; /* Artifact ID of the file being annotated */
2212 int fnid; /* Filename ID */
2213 Stmt q; /* Query returning all ancestor versions */
2214 int cnt = 0; /* Number of versions analyzed */
2215 int iLimit; /* Maximum number of versions to analyze */
2216 sqlite3_int64 mxTime; /* Halt at this time if not already complete */
2217
2218 if( zLimit ){
2219 if( strcmp(zLimit,"none")==0 ){
2220 iLimit = 0;
2221 mxTime = 0;
2222 }else if( sqlite3_strglob("*[0-9]s", zLimit)==0 ){
2223 iLimit = 0;
2224 mxTime = current_time_in_milliseconds() + 1000.0*atof(zLimit);
2225 }else{
2226 iLimit = atoi(zLimit);
2227 if( iLimit<=0 ) iLimit = 30;
2228 mxTime = 0;
2229 }
2230 }else{
2231 /* Default limit is as much as we can do in 1.000 seconds */
2232 iLimit = 0;
2233 mxTime = current_time_in_milliseconds()+1000;
2234 }
2235 db_begin_transaction();
2236
2237 /* Get the artificate ID for the check-in begin analyzed */
2238 if( zRevision ){
2239 cid = name_to_typed_rid(zRevision, "ci");
@@ -2233,19 +2265,27 @@
2265 " AND mlink.mid!=mlink.pid"
2266 " ORDER BY ancestor.generation;",
2267 fnid
2268 );
2269
2270 while( db_step(&q)==SQLITE_ROW ){
2271 if( cnt>=3 ){ /* Process at least 3 rows before imposing limits */
2272 if( (iLimit>0 && cnt>=iLimit)
2273 || (cnt>0 && mxTime>0 && current_time_in_milliseconds()>mxTime)
2274 ){
2275 p->bMoreToDo = 1;
2276 break;
2277 }
2278 }
2279 rid = db_column_int(&q, 4);
2280 if( cnt==0 ){
2281 if( !content_get(rid, &toAnnotate) ){
2282 fossil_fatal("unable to retrieve content of artifact #%d", rid);
2283 }
2284 blob_to_utf8_no_bom(&toAnnotate, 0);
2285 annotation_start(p, &toAnnotate, annFlags);
2286 p->bMoreToDo = 0;
2287 }
2288 p->aVers = fossil_realloc(p->aVers, (p->nVers+1)*sizeof(p->aVers[0]));
2289 p->aVers[p->nVers].zFUuid = fossil_strdup(db_column_text(&q, 0));
2290 p->aVers[p->nVers].zMUuid = fossil_strdup(db_column_text(&q, 1));
2291 p->aVers[p->nVers].zDate = fossil_strdup(db_column_text(&q, 2));
@@ -2257,11 +2297,10 @@
2297 annotation_step(p, &step, p->nVers-1, annFlags);
2298 blob_reset(&step);
2299 }
2300 cnt++;
2301 }
 
2302 db_finalize(&q);
2303 db_end_transaction(0);
2304 }
2305
2306 /*
@@ -2300,25 +2339,29 @@
2339 ** Query parameters:
2340 **
2341 ** checkin=ID The manifest ID at which to start the annotation
2342 ** filename=FILENAME The filename.
2343 ** filevers=BOOLEAN Show file versions rather than check-in versions
2344 ** limit=LIMIT Limit the amount of analysis:
2345 ** "none" No limit
2346 ** "Xs" As much as can be computed in X seconds
2347 ** "N" N versions
2348 ** log=BOOLEAN Show a log of versions analyzed
2349 ** w=BOOLEAN Ignore whitespace
2350 **
2351 */
2352 void annotation_page(void){
2353 int i;
2354 const char *zLimit; /* Depth limit */
2355 u64 annFlags = DIFF_STRIP_EOLCR;
2356 int showLog; /* True to display the log */
2357 int fileVers; /* Show file version instead of check-in versions */
2358 int ignoreWs; /* Ignore whitespace */
2359 const char *zFilename; /* Name of file to annotate */
2360 const char *zRevision; /* Name of check-in from which to start annotation */
2361 const char *zCI; /* The check-in containing zFilename */
2362 int szHash; /* Number of characters in %S display */
2363 char *zLink;
2364 Annotator ann;
2365 HQuery url;
2366 struct AnnVers *p;
2367 unsigned clr1, clr2, clr;
@@ -2329,18 +2372,18 @@
2372 if( !g.perm.Read ){ login_needed(g.anon.Read); return; }
2373 if( exclude_spiders() ) return;
2374 load_control();
2375 zFilename = P("filename");
2376 zRevision = PD("checkin",0);
2377 zLimit = P("limit");
2378 showLog = PB("log");
2379 fileVers = PB("filevers");
2380 ignoreWs = PB("w");
2381 if( ignoreWs ) annFlags |= DIFF_IGNORE_ALLWS;
2382
2383 /* compute the annotation */
2384 annotate_file(&ann, zFilename, zRevision, zLimit, annFlags);
2385 zCI = ann.aVers[0].zMUuid;
2386
2387 /* generate the web page */
2388 style_header("Annotation For %h", zFilename);
2389 if( bBlame ){
@@ -2348,30 +2391,22 @@
2391 }else{
2392 url_initialize(&url, "annotate");
2393 }
2394 url_add_parameter(&url, "checkin", P("checkin"));
2395 url_add_parameter(&url, "filename", zFilename);
2396 if( zLimit ){
2397 url_add_parameter(&url, "limit", zLimit);
2398 }
2399 url_add_parameter(&url, "w", ignoreWs ? "1" : "0");
2400 url_add_parameter(&url, "log", showLog ? "1" : "0");
2401 url_add_parameter(&url, "filevers", fileVers ? "1" : "0");
2402 style_submenu_checkbox("w", "Ignore Whitespace", 0, 0);
2403 style_submenu_checkbox("log", "Log", 0, "toggle_annotation_log()");
2404 style_submenu_checkbox("filevers", "Link to Files", 0, 0);
2405 if( ann.bMoreToDo ){
 
2406 style_submenu_element("All Ancestors", "%s",
2407 url_render(&url, "limit", "none", 0, 0));
 
 
 
 
 
 
 
2408 }
2409 if( skin_detail_boolean("white-foreground") ){
2410 clr1 = 0xa04040;
2411 clr2 = 0x4059a0;
2412 }else{
@@ -2381,11 +2416,11 @@
2416 for(p=ann.aVers, i=0; i<ann.nVers; i++, p++){
2417 clr = gradient_color(clr1, clr2, ann.nVers-1, i);
2418 ann.aVers[i].zBgColor = mprintf("#%06x", clr);
2419 }
2420
2421 @ <div id="annotation_log" style='display:%s(showLog?"block":"none");'>
2422 zLink = href("%R/finfo?name=%t&ci=%!S",zFilename,zCI);
2423 @ <h2>Versions of %z(zLink)%h(zFilename)</a> analyzed:</h2>
2424 @ <ol>
2425 for(p=ann.aVers, i=0; i<ann.nVers; i++, p++){
2426 @ <li><span style='background-color:%s(p->zBgColor);'>%s(p->zDate)
@@ -2402,28 +2437,28 @@
2437 @ var x = document.forms["f01"].elements["log"].checked
2438 @ w.style.display = x ? "block" : "none";
2439 @ }
2440 @ </script>
2441
2442 if( !ann.bMoreToDo ){
2443 @ <h2>Origin for each line in
2444 @ %z(href("%R/finfo?name=%h&ci=%!S", zFilename, zCI))%h(zFilename)</a>
2445 @ from check-in %z(href("%R/info/%!S",zCI))%S(zCI)</a>:</h2>
 
2446 }else{
2447 @ <h2>Lines added by the %d(ann.nVers) most recent ancestors of
2448 @ %z(href("%R/finfo?name=%h&ci=%!S", zFilename, zCI))%h(zFilename)</a>
2449 @ from check-in %z(href("%R/info/%!S",zCI))%S(zCI)</a>:</h2>
2450 }
2451 @ <pre>
2452 szHash = length_of_S_display();
2453 for(i=0; i<ann.nOrig; i++){
2454 int iVers = ann.aOrig[i].iVers;
2455 char *z = (char*)ann.aOrig[i].z;
2456 int n = ann.aOrig[i].n;
2457 char zPrefix[300];
2458 z[n] = 0;
2459 if( iVers<0 && !ann.bMoreToDo ) iVers = ann.nVers-1;
2460
2461 if( bBlame ){
2462 if( iVers>=0 ){
2463 struct AnnVers *p = ann.aVers+iVers;
2464 const char *zUuid = fileVers ? p->zFUuid : p->zMUuid;
@@ -2432,11 +2467,11 @@
2467 "<span style='background-color:%s'>"
2468 "%s%.10s</a> %s</span> %13.13s:",
2469 p->zBgColor, zLink, zUuid, p->zDate, p->zUser);
2470 fossil_free(zLink);
2471 }else{
2472 sqlite3_snprintf(sizeof(zPrefix), zPrefix, "%*s", szHash+28, "");
2473 }
2474 }else{
2475 if( iVers>=0 ){
2476 struct AnnVers *p = ann.aVers+iVers;
2477 const char *zUuid = fileVers ? p->zFUuid : p->zMUuid;
@@ -2445,11 +2480,11 @@
2480 "<span style='background-color:%s'>"
2481 "%s%.10s</a> %s</span> %4d:",
2482 p->zBgColor, zLink, zUuid, p->zDate, i+1);
2483 fossil_free(zLink);
2484 }else{
2485 sqlite3_snprintf(sizeof(zPrefix), zPrefix, "%*s%4d:",szHash+14,"",i+1);
2486 }
2487 }
2488 @ %s(zPrefix) %h(z)
2489
2490 }
@@ -2473,33 +2508,33 @@
2508 ** Options:
2509 ** --filevers Show file version numbers rather than
2510 ** check-in versions
2511 ** -r|--revision VERSION The specific check-in containing the file
2512 ** -l|--log List all versions analyzed
2513 ** -n|--limit LIMIT Limit the amount of analysis:
2514 ** N Up to N versions
2515 ** Xs As much as possible in X seconds
2516 ** none No limit
2517 ** -w|--ignore-all-space Ignore white space when comparing lines
2518 ** -Z|--ignore-trailing-space Ignore whitespace at line end
2519 **
2520 ** See also: info, finfo, timeline
2521 */
2522 void annotate_cmd(void){
2523 const char *zRevision; /* Revision name, or NULL for current check-in */
2524 Annotator ann; /* The annotation of the file */
2525 int i; /* Loop counter */
2526 const char *zLimit; /* The value to the -n|--limit option */
2527 int showLog; /* True to show the log */
2528 int fileVers; /* Show file version instead of check-in versions */
2529 u64 annFlags = 0; /* Flags to control annotation properties */
2530 int bBlame = 0; /* True for BLAME output. False for ANNOTATE. */
2531 int szHash; /* Display size of a version hash */
2532
2533 bBlame = g.argv[1][0]!='a';
2534 zRevision = find_option("r","revision",1);
2535 zLimit = find_option("limit","n",1);
 
 
 
2536 showLog = find_option("log","l",0)!=0;
2537 if( find_option("ignore-trailing-space","Z",0)!=0 ){
2538 annFlags = DIFF_IGNORE_EOLWS;
2539 }
2540 if( find_option("ignore-all-space","w",0)!=0 ){
@@ -2514,39 +2549,40 @@
2549 if( g.argc<3 ) {
2550 usage("FILENAME");
2551 }
2552
2553 annFlags |= DIFF_STRIP_EOLCR;
2554 annotate_file(&ann, g.argv[2], zRevision, zLimit, annFlags);
2555 if( showLog ){
2556 struct AnnVers *p;
2557 for(p=ann.aVers, i=0; i<ann.nVers; i++, p++){
2558 fossil_print("version %3d: %s %S file %S\n",
2559 i+1, p->zDate, p->zMUuid, p->zFUuid);
2560 }
2561 fossil_print("---------------------------------------------------\n");
2562 }
2563 szHash = length_of_S_display();
2564 for(i=0; i<ann.nOrig; i++){
2565 int iVers = ann.aOrig[i].iVers;
2566 char *z = (char*)ann.aOrig[i].z;
2567 int n = ann.aOrig[i].n;
2568 struct AnnVers *p;
2569 if( iVers<0 && !ann.bMoreToDo ) iVers = ann.nVers-1;
 
2570 if( bBlame ){
2571 if( iVers>=0 ){
2572 p = ann.aVers + iVers;
2573 fossil_print("%S %s %13.13s: %.*s\n",
2574 fileVers ? p->zFUuid : p->zMUuid, p->zDate, p->zUser, n, z);
2575 }else{
2576 fossil_print("%*s %.*s\n", szHash+26, "", n, z);
2577 }
2578 }else{
2579 if( iVers>=0 ){
2580 p = ann.aVers + iVers;
2581 fossil_print("%S %s %5d: %.*s\n",
2582 fileVers ? p->zFUuid : p->zMUuid, p->zDate, i+1, n, z);
2583 }else{
2584 fossil_print("%*s %5d: %.*s\n", szHash+11, "", i+1, n, z);
 
2585 }
2586 }
2587 }
2588 }
2589
--- src/printf.c
+++ src/printf.c
@@ -61,10 +61,17 @@
6161
if( nDigitUrl < FOSSIL_HASH_DIGITS_URL ) nDigitUrl = FOSSIL_HASH_DIGITS_URL;
6262
if( nDigitUrl > 40 ) nDigitUrl = 40;
6363
}
6464
return bForUrl ? nDigitUrl : nDigitHuman;
6565
}
66
+
67
+/*
68
+** Return the number of characters in a %S output.
69
+*/
70
+int length_of_S_display(void){
71
+ return hashDigits(0);
72
+}
6673
6774
/*
6875
** Conversion types fall into various categories as defined by the
6976
** following enumeration.
7077
*/
7178
--- src/printf.c
+++ src/printf.c
@@ -61,10 +61,17 @@
61 if( nDigitUrl < FOSSIL_HASH_DIGITS_URL ) nDigitUrl = FOSSIL_HASH_DIGITS_URL;
62 if( nDigitUrl > 40 ) nDigitUrl = 40;
63 }
64 return bForUrl ? nDigitUrl : nDigitHuman;
65 }
 
 
 
 
 
 
 
66
67 /*
68 ** Conversion types fall into various categories as defined by the
69 ** following enumeration.
70 */
71
--- src/printf.c
+++ src/printf.c
@@ -61,10 +61,17 @@
61 if( nDigitUrl < FOSSIL_HASH_DIGITS_URL ) nDigitUrl = FOSSIL_HASH_DIGITS_URL;
62 if( nDigitUrl > 40 ) nDigitUrl = 40;
63 }
64 return bForUrl ? nDigitUrl : nDigitHuman;
65 }
66
67 /*
68 ** Return the number of characters in a %S output.
69 */
70 int length_of_S_display(void){
71 return hashDigits(0);
72 }
73
74 /*
75 ** Conversion types fall into various categories as defined by the
76 ** following enumeration.
77 */
78

Keyboard Shortcuts

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