Fossil SCM

Merge miscellaneous changes that have accumulated on the annotation-enhancements branch. See a log of the whole branch for details.

drh 2017-09-25 15:18 trunk merge
Commit ab8ed318e782cc731a4154707d39607be4b537b88bbf7de9248201561d9bf252
4 files changed +2 -2 +85 -155 +17 -45 +46 -55
+2 -2
--- src/db.c
+++ src/db.c
@@ -2843,11 +2843,11 @@
28432843
** differ only in case are the same file. Defaults to
28442844
** TRUE for unix and FALSE for Cygwin, Mac and Windows.
28452845
*/
28462846
#endif
28472847
/*
2848
-** STTING: clean-glob width=40 versionable block-text
2848
+** SETTING: clean-glob width=40 versionable block-text
28492849
** The VALUE of this setting is a comma or newline-separated list of GLOB
28502850
** patterns specifying files that the "clean" command will
28512851
** delete without prompting or allowing undo.
28522852
** Example: *.a,*.lib,*.o
28532853
*/
@@ -2957,11 +2957,11 @@
29572957
*/
29582958
/*
29592959
** SETTING: ignore-glob width=40 versionable block-text
29602960
** The value is a comma or newline-separated list of GLOB
29612961
** patterns specifying files that the "add", "addremove",
2962
-** "clean", and "extra" commands will ignore.
2962
+** "clean", and "extras" commands will ignore.
29632963
**
29642964
** Example: *.log customCode.c notes.txt
29652965
*/
29662966
/*
29672967
** SETTING: keep-glob width=40 versionable block-text
29682968
--- src/db.c
+++ src/db.c
@@ -2843,11 +2843,11 @@
2843 ** differ only in case are the same file. Defaults to
2844 ** TRUE for unix and FALSE for Cygwin, Mac and Windows.
2845 */
2846 #endif
2847 /*
2848 ** STTING: clean-glob width=40 versionable block-text
2849 ** The VALUE of this setting is a comma or newline-separated list of GLOB
2850 ** patterns specifying files that the "clean" command will
2851 ** delete without prompting or allowing undo.
2852 ** Example: *.a,*.lib,*.o
2853 */
@@ -2957,11 +2957,11 @@
2957 */
2958 /*
2959 ** SETTING: ignore-glob width=40 versionable block-text
2960 ** The value is a comma or newline-separated list of GLOB
2961 ** patterns specifying files that the "add", "addremove",
2962 ** "clean", and "extra" commands will ignore.
2963 **
2964 ** Example: *.log customCode.c notes.txt
2965 */
2966 /*
2967 ** SETTING: keep-glob width=40 versionable block-text
2968
--- src/db.c
+++ src/db.c
@@ -2843,11 +2843,11 @@
2843 ** differ only in case are the same file. Defaults to
2844 ** TRUE for unix and FALSE for Cygwin, Mac and Windows.
2845 */
2846 #endif
2847 /*
2848 ** SETTING: clean-glob width=40 versionable block-text
2849 ** The VALUE of this setting is a comma or newline-separated list of GLOB
2850 ** patterns specifying files that the "clean" command will
2851 ** delete without prompting or allowing undo.
2852 ** Example: *.a,*.lib,*.o
2853 */
@@ -2957,11 +2957,11 @@
2957 */
2958 /*
2959 ** SETTING: ignore-glob width=40 versionable block-text
2960 ** The value is a comma or newline-separated list of GLOB
2961 ** patterns specifying files that the "add", "addremove",
2962 ** "clean", and "extras" commands will ignore.
2963 **
2964 ** Example: *.log customCode.c notes.txt
2965 */
2966 /*
2967 ** SETTING: keep-glob width=40 versionable block-text
2968
+85 -155
--- src/diff.c
+++ src/diff.c
@@ -43,13 +43,10 @@
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 */
4646
#define DIFF_SLOW_SBS (((u64)0x20)<<32) /* Better, but slower side-by-side */
4747
48
-/* Annotation flags (any DIFF flag can be used as Annotation flag as well) */
49
-#define ANN_FILE_VERS (((u64)0x40)<<32) /* File vers not commit vers */
50
-
5148
/*
5249
** These error messages are shared in multiple locations. They are defined
5350
** here for consistency.
5451
*/
5552
#define DIFF_CANNOT_COMPUTE_BINARY \
@@ -2181,86 +2178,91 @@
21812178
return 0;
21822179
}
21832180
21842181
21852182
/*
2186
-** Compute a complete annotation on a file. The file is identified
2187
-** by its filename number (filename.fnid) and check-in (mlink.mid).
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).
21882185
*/
21892186
static void annotate_file(
21902187
Annotator *p, /* The annotator */
2191
- int fnid, /* The name of the file to be annotated */
2192
- int mid, /* Use the version of the file in this check-in */
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 */
21932190
int iLimit, /* Limit the number of levels if greater than zero */
21942191
u64 annFlags /* Flags to alter the annotation */
21952192
){
21962193
Blob toAnnotate; /* Text of the final (mid) version of the file */
21972194
Blob step; /* Text of previous revision */
2198
- int rid; /* Artifact ID of the file being annotated */
2199
- Stmt q; /* Query returning all ancestor versions */
2200
- Stmt ins; /* Inserts into the temporary VSEEN table */
2201
- int cnt = 0; /* Number of versions examined */
2202
-
2203
- /* Initialize the annotation */
2204
- rid = db_int(0, "SELECT fid FROM mlink WHERE mid=%d AND fnid=%d",mid,fnid);
2205
- if( rid==0 ){
2206
- fossil_fatal("file #%d is unchanged in manifest #%d", fnid, mid);
2207
- }
2208
- if( !content_get(rid, &toAnnotate) ){
2209
- fossil_fatal("unable to retrieve content of artifact #%d", rid);
2210
- }
2211
- if( iLimit<=0 ) iLimit = 1000000000;
2212
- blob_to_utf8_no_bom(&toAnnotate, 0);
2213
- annotation_start(p, &toAnnotate, annFlags);
2214
- db_begin_transaction();
2215
- db_multi_exec(
2216
- "CREATE TEMP TABLE IF NOT EXISTS vseen(rid INTEGER PRIMARY KEY);"
2217
- "DELETE FROM vseen;"
2218
- );
2219
-
2220
- db_prepare(&ins, "INSERT OR IGNORE INTO vseen(rid) VALUES(:rid)");
2221
- db_prepare(&q,
2222
- "SELECT (SELECT uuid FROM blob WHERE rid=mlink.fid),"
2223
- " (SELECT uuid FROM blob WHERE rid=mlink.mid),"
2224
- " date(event.mtime),"
2225
- " coalesce(event.euser,event.user),"
2226
- " mlink.pid"
2227
- " FROM mlink, event, ancestor"
2228
- " WHERE mlink.fid=:rid"
2229
- " AND event.objid=mlink.mid"
2230
- " AND mlink.pid NOT IN vseen"
2231
- " AND ancestor.rid=mlink.mid"
2232
- " ORDER BY ancestor.generation;"
2233
- );
2234
-
2235
- db_bind_int(&q, ":rid", rid);
2236
- if( iLimit==0 ) iLimit = 1000000000;
2237
- while( rid && iLimit>cnt && db_step(&q)==SQLITE_ROW ){
2238
- int prevId = db_column_int(&q, 4);
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");
2208
+ }else{
2209
+ db_must_be_within_tree();
2210
+ cid = db_lget_int("checkout", 0);
2211
+ }
2212
+
2213
+ /* Compute all direct ancestors of the check-in being analyzed into
2214
+ ** the "ancestor" table. */
2215
+ compute_direct_ancestors(cid);
2216
+
2217
+ /* Get filename ID */
2218
+ file_tree_name(zFilename, &treename, 0, 1);
2219
+ zFilename = blob_str(&treename);
2220
+ fnid = db_int(0, "SELECT fnid FROM filename WHERE name=%Q", zFilename);
2221
+
2222
+ db_prepare(&q,
2223
+ "SELECT"
2224
+ " (SELECT uuid FROM blob WHERE rid=mlink.fid),"
2225
+ " (SELECT uuid FROM blob WHERE rid=mlink.mid),"
2226
+ " date(event.mtime),"
2227
+ " coalesce(event.euser,event.user),"
2228
+ " mlink.fid"
2229
+ " FROM mlink, event, ancestor"
2230
+ " WHERE mlink.fnid=%d"
2231
+ " AND ancestor.rid=mlink.mid"
2232
+ " AND event.objid=mlink.mid"
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
+ }
22392248
p->aVers = fossil_realloc(p->aVers, (p->nVers+1)*sizeof(p->aVers[0]));
22402249
p->aVers[p->nVers].zFUuid = fossil_strdup(db_column_text(&q, 0));
22412250
p->aVers[p->nVers].zMUuid = fossil_strdup(db_column_text(&q, 1));
22422251
p->aVers[p->nVers].zDate = fossil_strdup(db_column_text(&q, 2));
22432252
p->aVers[p->nVers].zUser = fossil_strdup(db_column_text(&q, 3));
2244
- if( p->nVers ){
2253
+ p->nVers++;
2254
+ if( cnt>0 ){
22452255
content_get(rid, &step);
22462256
blob_to_utf8_no_bom(&step, 0);
22472257
annotation_step(p, &step, p->nVers-1, annFlags);
22482258
blob_reset(&step);
22492259
}
2250
- p->nVers++;
2251
- db_bind_int(&ins, ":rid", rid);
2252
- db_step(&ins);
2253
- db_reset(&ins);
2254
- db_reset(&q);
2255
- rid = prevId;
2256
- db_bind_int(&q, ":rid", prevId);
22572260
cnt++;
22582261
}
22592262
p->bLimit = iLimit==cnt;
22602263
db_finalize(&q);
2261
- db_finalize(&ins);
22622264
db_end_transaction(0);
22632265
}
22642266
22652267
/*
22662268
** Return a color from a gradient.
@@ -2297,53 +2299,47 @@
22972299
**
22982300
** Query parameters:
22992301
**
23002302
** checkin=ID The manifest ID at which to start the annotation
23012303
** filename=FILENAME The filename.
2302
-** filevers Show file versions rather than check-in versions
2304
+** filevers=BOOLEAN Show file versions rather than check-in versions
23032305
** limit=N Limit the search depth to N ancestors
23042306
** log=BOOLEAN Show a log of versions analyzed
2305
-** w Ignore whitespace
2307
+** w=BOOLEAN Ignore whitespace
23062308
**
23072309
*/
23082310
void annotation_page(void){
2309
- int mid;
2310
- int fnid;
23112311
int i;
23122312
int iLimit; /* Depth limit */
23132313
u64 annFlags = DIFF_STRIP_EOLCR;
2314
- int showLog = 0; /* True to display the log */
2315
- int ignoreWs = 0; /* Ignore whitespace */
2314
+ int showLog; /* True to display the log */
2315
+ int fileVers; /* Show file version instead of check-in versions */
2316
+ int ignoreWs; /* Ignore whitespace */
23162317
const char *zFilename; /* Name of file to annotate */
2318
+ const char *zRevision; /* Name of check-in from which to start annotation */
23172319
const char *zCI; /* The check-in containing zFilename */
23182320
Annotator ann;
23192321
HQuery url;
23202322
struct AnnVers *p;
23212323
unsigned clr1, clr2, clr;
23222324
int bBlame = g.zPath[0]!='a';/* True for BLAME output. False for ANNOTATE. */
23232325
23242326
/* Gather query parameters */
2325
- showLog = atoi(PD("log","1"));
23262327
login_check_credentials();
23272328
if( !g.perm.Read ){ login_needed(g.anon.Read); return; }
23282329
if( exclude_spiders() ) return;
23292330
load_control();
2330
- mid = name_to_typed_rid(PD("checkin","0"),"ci");
23312331
zFilename = P("filename");
2332
- fnid = db_int(0, "SELECT fnid FROM filename WHERE name=%Q", zFilename);
2333
- if( mid==0 || fnid==0 ){ fossil_redirect_home(); }
2332
+ zRevision = PD("checkin",0);
23342333
iLimit = atoi(PD("limit","20"));
2335
- if( P("filevers") ) annFlags |= ANN_FILE_VERS;
2336
- ignoreWs = P("w")!=0;
2334
+ showLog = PB("log");
2335
+ fileVers = PB("filevers");
2336
+ ignoreWs = PB("w");
23372337
if( ignoreWs ) annFlags |= DIFF_IGNORE_ALLWS;
2338
- if( !db_exists("SELECT 1 FROM mlink WHERE mid=%d AND fnid=%d",mid,fnid) ){
2339
- fossil_redirect_home();
2340
- }
23412338
23422339
/* compute the annotation */
2343
- compute_direct_ancestors(mid);
2344
- annotate_file(&ann, fnid, mid, iLimit, annFlags);
2340
+ annotate_file(&ann, zFilename, zRevision, iLimit, annFlags);
23452341
zCI = ann.aVers[0].zMUuid;
23462342
23472343
/* generate the web page */
23482344
style_header("Annotation For %h", zFilename);
23492345
if( bBlame ){
@@ -2354,24 +2350,16 @@
23542350
url_add_parameter(&url, "checkin", P("checkin"));
23552351
url_add_parameter(&url, "filename", zFilename);
23562352
if( iLimit!=20 ){
23572353
url_add_parameter(&url, "limit", sqlite3_mprintf("%d", iLimit));
23582354
}
2355
+ url_add_parameter(&url, "w", ignoreWs ? "1" : "0");
23592356
url_add_parameter(&url, "log", showLog ? "1" : "0");
2360
- if( ignoreWs ){
2361
- url_add_parameter(&url, "w", "");
2362
- style_submenu_element("Show Whitespace Changes", "%s",
2363
- url_render(&url, "w", 0, 0, 0));
2364
- }else{
2365
- style_submenu_element("Ignore Whitespace", "%s",
2366
- url_render(&url, "w", "", 0, 0));
2367
- }
2368
- if( showLog ){
2369
- style_submenu_element("Hide Log", "%s", url_render(&url, "log", "0", 0, 0));
2370
- }else{
2371
- style_submenu_element("Show Log", "%s", url_render(&url, "log", "1", 0, 0));
2372
- }
2357
+ url_add_parameter(&url, "filevers", fileVers ? "1" : "0");
2358
+ style_submenu_checkbox("w", "Ignore Whitespace", 0);
2359
+ style_submenu_checkbox("log", "Log", 0);
2360
+ style_submenu_checkbox("filevers", "Link to Files", 0);
23732361
if( ann.bLimit ){
23742362
char *z1, *z2;
23752363
style_submenu_element("All Ancestors", "%s",
23762364
url_render(&url, "limit", "-1", 0, 0));
23772365
z1 = sqlite3_mprintf("%d Ancestors", iLimit+20);
@@ -2441,27 +2429,29 @@
24412429
if( iLimit>ann.nVers && iVers<0 ) iVers = ann.nVers-1;
24422430
24432431
if( bBlame ){
24442432
if( iVers>=0 ){
24452433
struct AnnVers *p = ann.aVers+iVers;
2446
- char *zLink = xhref("target='infowindow'", "%R/info/%!S", p->zMUuid);
2434
+ const char *zUuid = fileVers ? p->zFUuid : p->zMUuid;
2435
+ char *zLink = xhref("target='infowindow'", "%R/info/%!S", zUuid);
24472436
sqlite3_snprintf(sizeof(zPrefix), zPrefix,
24482437
"<span style='background-color:%s'>"
24492438
"%s%.10s</a> %s</span> %13.13s:",
2450
- p->zBgColor, zLink, p->zMUuid, p->zDate, p->zUser);
2439
+ p->zBgColor, zLink, zUuid, p->zDate, p->zUser);
24512440
fossil_free(zLink);
24522441
}else{
24532442
sqlite3_snprintf(sizeof(zPrefix), zPrefix, "%36s", "");
24542443
}
24552444
}else{
24562445
if( iVers>=0 ){
24572446
struct AnnVers *p = ann.aVers+iVers;
2458
- char *zLink = xhref("target='infowindow'", "%R/info/%!S", p->zMUuid);
2447
+ const char *zUuid = fileVers ? p->zFUuid : p->zMUuid;
2448
+ char *zLink = xhref("target='infowindow'", "%R/info/%!S", zUuid);
24592449
sqlite3_snprintf(sizeof(zPrefix), zPrefix,
24602450
"<span style='background-color:%s'>"
24612451
"%s%.10s</a> %s</span> %4d:",
2462
- p->zBgColor, zLink, p->zMUuid, p->zDate, i+1);
2452
+ p->zBgColor, zLink, zUuid, p->zDate, i+1);
24632453
fossil_free(zLink);
24642454
}else{
24652455
sqlite3_snprintf(sizeof(zPrefix), zPrefix, "%22s%4d:", "", i+1);
24662456
}
24672457
}
@@ -2495,33 +2485,26 @@
24952485
** -Z|--ignore-trailing-space Ignore whitespace at line end
24962486
**
24972487
** See also: info, finfo, timeline
24982488
*/
24992489
void annotate_cmd(void){
2500
- int fnid; /* Filename ID */
2501
- int fid; /* File instance ID */
2502
- int mid; /* Manifest where file was checked in */
2503
- int cid; /* Checkout or selected check-in ID */
2504
- Blob treename; /* FILENAME translated to canonical form */
2505
- const char *zRev; /* Revision name, or NULL for current check-in */
2506
- char *zFilename; /* Canonical filename */
2490
+ const char *zRevision; /* Revision name, or NULL for current check-in */
25072491
Annotator ann; /* The annotation of the file */
25082492
int i; /* Loop counter */
25092493
const char *zLimit; /* The value to the -n|--limit option */
25102494
int iLimit; /* How far back in time to look */
25112495
int showLog; /* True to show the log */
25122496
int fileVers; /* Show file version instead of check-in versions */
25132497
u64 annFlags = 0; /* Flags to control annotation properties */
25142498
int bBlame = 0; /* True for BLAME output. False for ANNOTATE. */
2515
- Manifest *pManifest; /* Manifest structure */
2516
- ManifestFile *pFile; /* Manifest file pointer */
25172499
25182500
bBlame = g.argv[1][0]!='a';
2519
- zRev = find_option("r","revision",1);
2501
+ zRevision = find_option("r","revision",1);
25202502
zLimit = find_option("limit","n",1);
25212503
if( zLimit==0 || zLimit[0]==0 ) zLimit = "-1";
25222504
iLimit = atoi(zLimit);
2505
+ if( iLimit<=0 ) iLimit = 1000000000;
25232506
showLog = find_option("log","l",0)!=0;
25242507
if( find_option("ignore-trailing-space","Z",0)!=0 ){
25252508
annFlags = DIFF_IGNORE_EOLWS;
25262509
}
25272510
if( find_option("ignore-all-space","w",0)!=0 ){
@@ -2535,65 +2518,12 @@
25352518
25362519
if( g.argc<3 ) {
25372520
usage("FILENAME");
25382521
}
25392522
2540
- /* Get filename ID */
2541
- file_tree_name(g.argv[2], &treename, 0, 1);
2542
- zFilename = blob_str(&treename);
2543
- fnid = db_int(0, "SELECT fnid FROM filename WHERE name=%Q", zFilename);
2544
- if( fnid==0 ){
2545
- fossil_fatal("no such file: %s", zFilename);
2546
- }
2547
-
2548
- /* Get artifact IDs of selected check-in and file */
2549
- if( zRev ){
2550
- /* Get artifact ID of selected check-in manifest */
2551
- cid = name_to_typed_rid(zRev, "ci");
2552
-
2553
- /* Get manifest structure for selected check-in */
2554
- pManifest = manifest_get(cid, CFTYPE_MANIFEST, 0);
2555
- if( !pManifest ){
2556
- fossil_fatal("could not parse manifest for check-in: %s", zRev);
2557
- }
2558
-
2559
- /* Get selected file in manifest */
2560
- pFile = manifest_file_find(pManifest, zFilename);
2561
- if( !pFile ){
2562
- fossil_fatal("file %s does not exist in check-in %s", zFilename, zRev);
2563
- }
2564
- manifest_destroy(pManifest);
2565
-
2566
- /* Get file instance ID from manifest file record */
2567
- fid = fast_uuid_to_rid(pFile->zUuid);
2568
- }else{
2569
- /* Get artifact ID of current checkout manifest */
2570
- cid = db_lget_int("checkout", 0);
2571
- if( cid == 0 ){
2572
- fossil_fatal("not in a checkout");
2573
- }
2574
-
2575
- /* Get file instance ID from current checkout file table */
2576
- fid = db_int(0, "SELECT rid FROM vfile WHERE pathname=%Q", zFilename);
2577
- if( fid==0 ){
2578
- fossil_fatal("not part of current checkout: %s", zFilename);
2579
- }
2580
- }
2581
-
2582
- /* Get ID of most recent manifest containing a change to the selected file */
2583
- compute_direct_ancestors(cid);
2584
- mid = db_int(0, "SELECT mlink.mid FROM mlink, ancestor "
2585
- " WHERE mlink.fid=%d AND mlink.fnid=%d AND mlink.mid=ancestor.rid"
2586
- " ORDER BY ancestor.generation ASC LIMIT 1",
2587
- fid, fnid);
2588
- if( mid==0 ){
2589
- fossil_fatal("unable to find manifest");
2590
- }
2591
-
2592
- if( iLimit<=0 ) iLimit = 1000000000;
25932523
annFlags |= DIFF_STRIP_EOLCR;
2594
- annotate_file(&ann, fnid, mid, iLimit, annFlags);
2524
+ annotate_file(&ann, g.argv[2], zRevision, iLimit, annFlags);
25952525
if( showLog ){
25962526
struct AnnVers *p;
25972527
for(p=ann.aVers, i=0; i<ann.nVers; i++, p++){
25982528
fossil_print("version %3d: %s %S file %S\n",
25992529
i+1, p->zDate, p->zMUuid, p->zFUuid);
26002530
--- src/diff.c
+++ src/diff.c
@@ -43,13 +43,10 @@
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 /* Annotation flags (any DIFF flag can be used as Annotation flag as well) */
49 #define ANN_FILE_VERS (((u64)0x40)<<32) /* File vers not commit vers */
50
51 /*
52 ** These error messages are shared in multiple locations. They are defined
53 ** here for consistency.
54 */
55 #define DIFF_CANNOT_COMPUTE_BINARY \
@@ -2181,86 +2178,91 @@
2181 return 0;
2182 }
2183
2184
2185 /*
2186 ** Compute a complete annotation on a file. The file is identified
2187 ** by its filename number (filename.fnid) and check-in (mlink.mid).
2188 */
2189 static void annotate_file(
2190 Annotator *p, /* The annotator */
2191 int fnid, /* The name of the file to be annotated */
2192 int mid, /* Use the version of the file in this check-in */
2193 int iLimit, /* Limit the number of levels if greater than zero */
2194 u64 annFlags /* Flags to alter the annotation */
2195 ){
2196 Blob toAnnotate; /* Text of the final (mid) version of the file */
2197 Blob step; /* Text of previous revision */
2198 int rid; /* Artifact ID of the file being annotated */
2199 Stmt q; /* Query returning all ancestor versions */
2200 Stmt ins; /* Inserts into the temporary VSEEN table */
2201 int cnt = 0; /* Number of versions examined */
2202
2203 /* Initialize the annotation */
2204 rid = db_int(0, "SELECT fid FROM mlink WHERE mid=%d AND fnid=%d",mid,fnid);
2205 if( rid==0 ){
2206 fossil_fatal("file #%d is unchanged in manifest #%d", fnid, mid);
2207 }
2208 if( !content_get(rid, &toAnnotate) ){
2209 fossil_fatal("unable to retrieve content of artifact #%d", rid);
2210 }
2211 if( iLimit<=0 ) iLimit = 1000000000;
2212 blob_to_utf8_no_bom(&toAnnotate, 0);
2213 annotation_start(p, &toAnnotate, annFlags);
2214 db_begin_transaction();
2215 db_multi_exec(
2216 "CREATE TEMP TABLE IF NOT EXISTS vseen(rid INTEGER PRIMARY KEY);"
2217 "DELETE FROM vseen;"
2218 );
2219
2220 db_prepare(&ins, "INSERT OR IGNORE INTO vseen(rid) VALUES(:rid)");
2221 db_prepare(&q,
2222 "SELECT (SELECT uuid FROM blob WHERE rid=mlink.fid),"
2223 " (SELECT uuid FROM blob WHERE rid=mlink.mid),"
2224 " date(event.mtime),"
2225 " coalesce(event.euser,event.user),"
2226 " mlink.pid"
2227 " FROM mlink, event, ancestor"
2228 " WHERE mlink.fid=:rid"
2229 " AND event.objid=mlink.mid"
2230 " AND mlink.pid NOT IN vseen"
2231 " AND ancestor.rid=mlink.mid"
2232 " ORDER BY ancestor.generation;"
2233 );
2234
2235 db_bind_int(&q, ":rid", rid);
2236 if( iLimit==0 ) iLimit = 1000000000;
2237 while( rid && iLimit>cnt && db_step(&q)==SQLITE_ROW ){
2238 int prevId = db_column_int(&q, 4);
 
 
 
 
 
 
 
 
 
 
 
 
2239 p->aVers = fossil_realloc(p->aVers, (p->nVers+1)*sizeof(p->aVers[0]));
2240 p->aVers[p->nVers].zFUuid = fossil_strdup(db_column_text(&q, 0));
2241 p->aVers[p->nVers].zMUuid = fossil_strdup(db_column_text(&q, 1));
2242 p->aVers[p->nVers].zDate = fossil_strdup(db_column_text(&q, 2));
2243 p->aVers[p->nVers].zUser = fossil_strdup(db_column_text(&q, 3));
2244 if( p->nVers ){
 
2245 content_get(rid, &step);
2246 blob_to_utf8_no_bom(&step, 0);
2247 annotation_step(p, &step, p->nVers-1, annFlags);
2248 blob_reset(&step);
2249 }
2250 p->nVers++;
2251 db_bind_int(&ins, ":rid", rid);
2252 db_step(&ins);
2253 db_reset(&ins);
2254 db_reset(&q);
2255 rid = prevId;
2256 db_bind_int(&q, ":rid", prevId);
2257 cnt++;
2258 }
2259 p->bLimit = iLimit==cnt;
2260 db_finalize(&q);
2261 db_finalize(&ins);
2262 db_end_transaction(0);
2263 }
2264
2265 /*
2266 ** Return a color from a gradient.
@@ -2297,53 +2299,47 @@
2297 **
2298 ** Query parameters:
2299 **
2300 ** checkin=ID The manifest ID at which to start the annotation
2301 ** filename=FILENAME The filename.
2302 ** filevers Show file versions rather than check-in versions
2303 ** limit=N Limit the search depth to N ancestors
2304 ** log=BOOLEAN Show a log of versions analyzed
2305 ** w Ignore whitespace
2306 **
2307 */
2308 void annotation_page(void){
2309 int mid;
2310 int fnid;
2311 int i;
2312 int iLimit; /* Depth limit */
2313 u64 annFlags = DIFF_STRIP_EOLCR;
2314 int showLog = 0; /* True to display the log */
2315 int ignoreWs = 0; /* Ignore whitespace */
 
2316 const char *zFilename; /* Name of file to annotate */
 
2317 const char *zCI; /* The check-in containing zFilename */
2318 Annotator ann;
2319 HQuery url;
2320 struct AnnVers *p;
2321 unsigned clr1, clr2, clr;
2322 int bBlame = g.zPath[0]!='a';/* True for BLAME output. False for ANNOTATE. */
2323
2324 /* Gather query parameters */
2325 showLog = atoi(PD("log","1"));
2326 login_check_credentials();
2327 if( !g.perm.Read ){ login_needed(g.anon.Read); return; }
2328 if( exclude_spiders() ) return;
2329 load_control();
2330 mid = name_to_typed_rid(PD("checkin","0"),"ci");
2331 zFilename = P("filename");
2332 fnid = db_int(0, "SELECT fnid FROM filename WHERE name=%Q", zFilename);
2333 if( mid==0 || fnid==0 ){ fossil_redirect_home(); }
2334 iLimit = atoi(PD("limit","20"));
2335 if( P("filevers") ) annFlags |= ANN_FILE_VERS;
2336 ignoreWs = P("w")!=0;
 
2337 if( ignoreWs ) annFlags |= DIFF_IGNORE_ALLWS;
2338 if( !db_exists("SELECT 1 FROM mlink WHERE mid=%d AND fnid=%d",mid,fnid) ){
2339 fossil_redirect_home();
2340 }
2341
2342 /* compute the annotation */
2343 compute_direct_ancestors(mid);
2344 annotate_file(&ann, fnid, mid, iLimit, annFlags);
2345 zCI = ann.aVers[0].zMUuid;
2346
2347 /* generate the web page */
2348 style_header("Annotation For %h", zFilename);
2349 if( bBlame ){
@@ -2354,24 +2350,16 @@
2354 url_add_parameter(&url, "checkin", P("checkin"));
2355 url_add_parameter(&url, "filename", zFilename);
2356 if( iLimit!=20 ){
2357 url_add_parameter(&url, "limit", sqlite3_mprintf("%d", iLimit));
2358 }
 
2359 url_add_parameter(&url, "log", showLog ? "1" : "0");
2360 if( ignoreWs ){
2361 url_add_parameter(&url, "w", "");
2362 style_submenu_element("Show Whitespace Changes", "%s",
2363 url_render(&url, "w", 0, 0, 0));
2364 }else{
2365 style_submenu_element("Ignore Whitespace", "%s",
2366 url_render(&url, "w", "", 0, 0));
2367 }
2368 if( showLog ){
2369 style_submenu_element("Hide Log", "%s", url_render(&url, "log", "0", 0, 0));
2370 }else{
2371 style_submenu_element("Show Log", "%s", url_render(&url, "log", "1", 0, 0));
2372 }
2373 if( ann.bLimit ){
2374 char *z1, *z2;
2375 style_submenu_element("All Ancestors", "%s",
2376 url_render(&url, "limit", "-1", 0, 0));
2377 z1 = sqlite3_mprintf("%d Ancestors", iLimit+20);
@@ -2441,27 +2429,29 @@
2441 if( iLimit>ann.nVers && iVers<0 ) iVers = ann.nVers-1;
2442
2443 if( bBlame ){
2444 if( iVers>=0 ){
2445 struct AnnVers *p = ann.aVers+iVers;
2446 char *zLink = xhref("target='infowindow'", "%R/info/%!S", p->zMUuid);
 
2447 sqlite3_snprintf(sizeof(zPrefix), zPrefix,
2448 "<span style='background-color:%s'>"
2449 "%s%.10s</a> %s</span> %13.13s:",
2450 p->zBgColor, zLink, p->zMUuid, p->zDate, p->zUser);
2451 fossil_free(zLink);
2452 }else{
2453 sqlite3_snprintf(sizeof(zPrefix), zPrefix, "%36s", "");
2454 }
2455 }else{
2456 if( iVers>=0 ){
2457 struct AnnVers *p = ann.aVers+iVers;
2458 char *zLink = xhref("target='infowindow'", "%R/info/%!S", p->zMUuid);
 
2459 sqlite3_snprintf(sizeof(zPrefix), zPrefix,
2460 "<span style='background-color:%s'>"
2461 "%s%.10s</a> %s</span> %4d:",
2462 p->zBgColor, zLink, p->zMUuid, p->zDate, i+1);
2463 fossil_free(zLink);
2464 }else{
2465 sqlite3_snprintf(sizeof(zPrefix), zPrefix, "%22s%4d:", "", i+1);
2466 }
2467 }
@@ -2495,33 +2485,26 @@
2495 ** -Z|--ignore-trailing-space Ignore whitespace at line end
2496 **
2497 ** See also: info, finfo, timeline
2498 */
2499 void annotate_cmd(void){
2500 int fnid; /* Filename ID */
2501 int fid; /* File instance ID */
2502 int mid; /* Manifest where file was checked in */
2503 int cid; /* Checkout or selected check-in ID */
2504 Blob treename; /* FILENAME translated to canonical form */
2505 const char *zRev; /* Revision name, or NULL for current check-in */
2506 char *zFilename; /* Canonical filename */
2507 Annotator ann; /* The annotation of the file */
2508 int i; /* Loop counter */
2509 const char *zLimit; /* The value to the -n|--limit option */
2510 int iLimit; /* How far back in time to look */
2511 int showLog; /* True to show the log */
2512 int fileVers; /* Show file version instead of check-in versions */
2513 u64 annFlags = 0; /* Flags to control annotation properties */
2514 int bBlame = 0; /* True for BLAME output. False for ANNOTATE. */
2515 Manifest *pManifest; /* Manifest structure */
2516 ManifestFile *pFile; /* Manifest file pointer */
2517
2518 bBlame = g.argv[1][0]!='a';
2519 zRev = find_option("r","revision",1);
2520 zLimit = find_option("limit","n",1);
2521 if( zLimit==0 || zLimit[0]==0 ) zLimit = "-1";
2522 iLimit = atoi(zLimit);
 
2523 showLog = find_option("log","l",0)!=0;
2524 if( find_option("ignore-trailing-space","Z",0)!=0 ){
2525 annFlags = DIFF_IGNORE_EOLWS;
2526 }
2527 if( find_option("ignore-all-space","w",0)!=0 ){
@@ -2535,65 +2518,12 @@
2535
2536 if( g.argc<3 ) {
2537 usage("FILENAME");
2538 }
2539
2540 /* Get filename ID */
2541 file_tree_name(g.argv[2], &treename, 0, 1);
2542 zFilename = blob_str(&treename);
2543 fnid = db_int(0, "SELECT fnid FROM filename WHERE name=%Q", zFilename);
2544 if( fnid==0 ){
2545 fossil_fatal("no such file: %s", zFilename);
2546 }
2547
2548 /* Get artifact IDs of selected check-in and file */
2549 if( zRev ){
2550 /* Get artifact ID of selected check-in manifest */
2551 cid = name_to_typed_rid(zRev, "ci");
2552
2553 /* Get manifest structure for selected check-in */
2554 pManifest = manifest_get(cid, CFTYPE_MANIFEST, 0);
2555 if( !pManifest ){
2556 fossil_fatal("could not parse manifest for check-in: %s", zRev);
2557 }
2558
2559 /* Get selected file in manifest */
2560 pFile = manifest_file_find(pManifest, zFilename);
2561 if( !pFile ){
2562 fossil_fatal("file %s does not exist in check-in %s", zFilename, zRev);
2563 }
2564 manifest_destroy(pManifest);
2565
2566 /* Get file instance ID from manifest file record */
2567 fid = fast_uuid_to_rid(pFile->zUuid);
2568 }else{
2569 /* Get artifact ID of current checkout manifest */
2570 cid = db_lget_int("checkout", 0);
2571 if( cid == 0 ){
2572 fossil_fatal("not in a checkout");
2573 }
2574
2575 /* Get file instance ID from current checkout file table */
2576 fid = db_int(0, "SELECT rid FROM vfile WHERE pathname=%Q", zFilename);
2577 if( fid==0 ){
2578 fossil_fatal("not part of current checkout: %s", zFilename);
2579 }
2580 }
2581
2582 /* Get ID of most recent manifest containing a change to the selected file */
2583 compute_direct_ancestors(cid);
2584 mid = db_int(0, "SELECT mlink.mid FROM mlink, ancestor "
2585 " WHERE mlink.fid=%d AND mlink.fnid=%d AND mlink.mid=ancestor.rid"
2586 " ORDER BY ancestor.generation ASC LIMIT 1",
2587 fid, fnid);
2588 if( mid==0 ){
2589 fossil_fatal("unable to find manifest");
2590 }
2591
2592 if( iLimit<=0 ) iLimit = 1000000000;
2593 annFlags |= DIFF_STRIP_EOLCR;
2594 annotate_file(&ann, fnid, mid, iLimit, annFlags);
2595 if( showLog ){
2596 struct AnnVers *p;
2597 for(p=ann.aVers, i=0; i<ann.nVers; i++, p++){
2598 fossil_print("version %3d: %s %S file %S\n",
2599 i+1, p->zDate, p->zMUuid, p->zFUuid);
2600
--- src/diff.c
+++ src/diff.c
@@ -43,13 +43,10 @@
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 */
52 #define DIFF_CANNOT_COMPUTE_BINARY \
@@ -2181,86 +2178,91 @@
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");
2208 }else{
2209 db_must_be_within_tree();
2210 cid = db_lget_int("checkout", 0);
2211 }
2212
2213 /* Compute all direct ancestors of the check-in being analyzed into
2214 ** the "ancestor" table. */
2215 compute_direct_ancestors(cid);
2216
2217 /* Get filename ID */
2218 file_tree_name(zFilename, &treename, 0, 1);
2219 zFilename = blob_str(&treename);
2220 fnid = db_int(0, "SELECT fnid FROM filename WHERE name=%Q", zFilename);
2221
2222 db_prepare(&q,
2223 "SELECT"
2224 " (SELECT uuid FROM blob WHERE rid=mlink.fid),"
2225 " (SELECT uuid FROM blob WHERE rid=mlink.mid),"
2226 " date(event.mtime),"
2227 " coalesce(event.euser,event.user),"
2228 " mlink.fid"
2229 " FROM mlink, event, ancestor"
2230 " WHERE mlink.fnid=%d"
2231 " AND ancestor.rid=mlink.mid"
2232 " AND event.objid=mlink.mid"
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));
2252 p->aVers[p->nVers].zUser = fossil_strdup(db_column_text(&q, 3));
2253 p->nVers++;
2254 if( cnt>0 ){
2255 content_get(rid, &step);
2256 blob_to_utf8_no_bom(&step, 0);
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 /*
2268 ** Return a color from a gradient.
@@ -2297,53 +2299,47 @@
2299 **
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 Annotator ann;
2321 HQuery url;
2322 struct AnnVers *p;
2323 unsigned clr1, clr2, clr;
2324 int bBlame = g.zPath[0]!='a';/* True for BLAME output. False for ANNOTATE. */
2325
2326 /* Gather query parameters */
 
2327 login_check_credentials();
2328 if( !g.perm.Read ){ login_needed(g.anon.Read); return; }
2329 if( exclude_spiders() ) return;
2330 load_control();
 
2331 zFilename = P("filename");
2332 zRevision = PD("checkin",0);
 
2333 iLimit = atoi(PD("limit","20"));
2334 showLog = PB("log");
2335 fileVers = PB("filevers");
2336 ignoreWs = PB("w");
2337 if( ignoreWs ) annFlags |= DIFF_IGNORE_ALLWS;
 
 
 
2338
2339 /* compute the annotation */
2340 annotate_file(&ann, zFilename, zRevision, iLimit, annFlags);
 
2341 zCI = ann.aVers[0].zMUuid;
2342
2343 /* generate the web page */
2344 style_header("Annotation For %h", zFilename);
2345 if( bBlame ){
@@ -2354,24 +2350,16 @@
2350 url_add_parameter(&url, "checkin", P("checkin"));
2351 url_add_parameter(&url, "filename", zFilename);
2352 if( iLimit!=20 ){
2353 url_add_parameter(&url, "limit", sqlite3_mprintf("%d", iLimit));
2354 }
2355 url_add_parameter(&url, "w", ignoreWs ? "1" : "0");
2356 url_add_parameter(&url, "log", showLog ? "1" : "0");
2357 url_add_parameter(&url, "filevers", fileVers ? "1" : "0");
2358 style_submenu_checkbox("w", "Ignore Whitespace", 0);
2359 style_submenu_checkbox("log", "Log", 0);
2360 style_submenu_checkbox("filevers", "Link to Files", 0);
 
 
 
 
 
 
 
 
 
2361 if( ann.bLimit ){
2362 char *z1, *z2;
2363 style_submenu_element("All Ancestors", "%s",
2364 url_render(&url, "limit", "-1", 0, 0));
2365 z1 = sqlite3_mprintf("%d Ancestors", iLimit+20);
@@ -2441,27 +2429,29 @@
2429 if( iLimit>ann.nVers && iVers<0 ) iVers = ann.nVers-1;
2430
2431 if( bBlame ){
2432 if( iVers>=0 ){
2433 struct AnnVers *p = ann.aVers+iVers;
2434 const char *zUuid = fileVers ? p->zFUuid : p->zMUuid;
2435 char *zLink = xhref("target='infowindow'", "%R/info/%!S", zUuid);
2436 sqlite3_snprintf(sizeof(zPrefix), zPrefix,
2437 "<span style='background-color:%s'>"
2438 "%s%.10s</a> %s</span> %13.13s:",
2439 p->zBgColor, zLink, zUuid, p->zDate, p->zUser);
2440 fossil_free(zLink);
2441 }else{
2442 sqlite3_snprintf(sizeof(zPrefix), zPrefix, "%36s", "");
2443 }
2444 }else{
2445 if( iVers>=0 ){
2446 struct AnnVers *p = ann.aVers+iVers;
2447 const char *zUuid = fileVers ? p->zFUuid : p->zMUuid;
2448 char *zLink = xhref("target='infowindow'", "%R/info/%!S", zUuid);
2449 sqlite3_snprintf(sizeof(zPrefix), zPrefix,
2450 "<span style='background-color:%s'>"
2451 "%s%.10s</a> %s</span> %4d:",
2452 p->zBgColor, zLink, zUuid, p->zDate, i+1);
2453 fossil_free(zLink);
2454 }else{
2455 sqlite3_snprintf(sizeof(zPrefix), zPrefix, "%22s%4d:", "", i+1);
2456 }
2457 }
@@ -2495,33 +2485,26 @@
2485 ** -Z|--ignore-trailing-space Ignore whitespace at line end
2486 **
2487 ** See also: info, finfo, timeline
2488 */
2489 void annotate_cmd(void){
2490 const char *zRevision; /* Revision name, or NULL for current check-in */
 
 
 
 
 
 
2491 Annotator ann; /* The annotation of the file */
2492 int i; /* Loop counter */
2493 const char *zLimit; /* The value to the -n|--limit option */
2494 int iLimit; /* How far back in time to look */
2495 int showLog; /* True to show the log */
2496 int fileVers; /* Show file version instead of check-in versions */
2497 u64 annFlags = 0; /* Flags to control annotation properties */
2498 int bBlame = 0; /* True for BLAME output. False for ANNOTATE. */
 
 
2499
2500 bBlame = g.argv[1][0]!='a';
2501 zRevision = find_option("r","revision",1);
2502 zLimit = find_option("limit","n",1);
2503 if( zLimit==0 || zLimit[0]==0 ) zLimit = "-1";
2504 iLimit = atoi(zLimit);
2505 if( iLimit<=0 ) iLimit = 1000000000;
2506 showLog = find_option("log","l",0)!=0;
2507 if( find_option("ignore-trailing-space","Z",0)!=0 ){
2508 annFlags = DIFF_IGNORE_EOLWS;
2509 }
2510 if( find_option("ignore-all-space","w",0)!=0 ){
@@ -2535,65 +2518,12 @@
2518
2519 if( g.argc<3 ) {
2520 usage("FILENAME");
2521 }
2522
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
2523 annFlags |= DIFF_STRIP_EOLCR;
2524 annotate_file(&ann, g.argv[2], zRevision, iLimit, annFlags);
2525 if( showLog ){
2526 struct AnnVers *p;
2527 for(p=ann.aVers, i=0; i<ann.nVers; i++, p++){
2528 fossil_print("version %3d: %s %S file %S\n",
2529 i+1, p->zDate, p->zMUuid, p->zFUuid);
2530
+17 -45
--- src/info.c
+++ src/info.c
@@ -1071,20 +1071,20 @@
10711071
** branch=TAG Show all changes on a particular branch
10721072
** v=BOOLEAN Default true. If false, only list files that have changed
10731073
** sbs=BOOLEAN Side-by-side diff if true. Unified diff if false
10741074
** glob=STRING only diff files matching this glob
10751075
** dc=N show N lines of context around each diff
1076
-** w ignore whitespace when computing diffs
1076
+** w=BOOLEAN ignore whitespace when computing diffs
10771077
** nohdr omit the description at the top of the page
10781078
**
10791079
**
10801080
** Show all differences between two check-ins.
10811081
*/
10821082
void vdiff_page(void){
10831083
int ridFrom, ridTo;
1084
- int verboseFlag = 0;
1085
- int sideBySide = 0;
1084
+ int verboseFlag;
1085
+ int sideBySide;
10861086
u64 diffFlags = 0;
10871087
Manifest *pFrom, *pTo;
10881088
ManifestFile *pFileFrom, *pFileTo;
10891089
const char *zBranch;
10901090
const char *zFrom;
@@ -1154,21 +1154,11 @@
11541154
sideBySide, (verboseFlag && !sideBySide)?"&v":"", zW);
11551155
}else{
11561156
style_submenu_element("Patch", "%R/vpatch?from=%T&to=%T%s", zFrom, zTo, zW);
11571157
}
11581158
if( sideBySide || verboseFlag ){
1159
- if( *zW ){
1160
- style_submenu_element("Show Whitespace Differences",
1161
- "%R/vdiff?from=%T&to=%T&sbs=%d%s%s%T", zFrom, zTo,
1162
- sideBySide, (verboseFlag && !sideBySide)?"&v":"",
1163
- zGlob ? "&glob=" : "", zGlob ? zGlob : "");
1164
- }else{
1165
- style_submenu_element("Ignore Whitespace",
1166
- "%R/vdiff?from=%T&to=%T&sbs=%d%s%s%T&w", zFrom, zTo,
1167
- sideBySide, (verboseFlag && !sideBySide)?"&v":"",
1168
- zGlob ? "&glob=" : "", zGlob ? zGlob : "");
1169
- }
1159
+ style_submenu_checkbox("w", "Ignore Whitespace", 0);
11701160
}
11711161
style_header("Check-in Differences");
11721162
if( P("nohdr")==0 ){
11731163
@ <h2>Difference From:</h2><blockquote>
11741164
checkin_description(ridFrom);
@@ -1546,25 +1536,25 @@
15461536
** "ci" parameter is omitted, then the most recent check-in ("tip") is
15471537
** used.
15481538
**
15491539
** Additional parameters:
15501540
**
1551
-** dc=N Show N lines of context around each diff
1552
-** patch Use the patch diff format
1553
-** regex=REGEX Only show differences that match REGEX
1554
-** sbs=BOOLEAN Turn side-by-side diffs on and off (default: on)
1555
-** verbose Show more detail when describing artifacts
1556
-** w Ignore whitespace
1541
+** dc=N Show N lines of context around each diff
1542
+** patch Use the patch diff format
1543
+** regex=REGEX Only show differences that match REGEX
1544
+** sbs=BOOLEAN Turn side-by-side diffs on and off (default: on)
1545
+** verbose=BOOLEAN Show more detail when describing artifacts
1546
+** w=BOOLEAN Ignore whitespace
15571547
*/
15581548
void diff_page(void){
15591549
int v1, v2;
1560
- int isPatch;
1561
- int sideBySide;
1550
+ int isPatch = P("patch")!=0;
1551
+ int sideBySide = PB("sbs");
1552
+ int verbose = PB("verbose");
15621553
char *zV1;
15631554
char *zV2;
15641555
const char *zRe;
1565
- const char *zW; /* URL param for ignoring whitespace */
15661556
ReCompiled *pRe = 0;
15671557
u64 diffFlags;
15681558
u32 objdescFlags = 0;
15691559
15701560
login_check_credentials();
@@ -1577,12 +1567,11 @@
15771567
v2 = name_to_rid_www("v2");
15781568
}
15791569
if( v1==0 || v2==0 ) fossil_redirect_home();
15801570
zRe = P("regex");
15811571
if( zRe ) re_compile(&pRe, zRe, 0);
1582
- if( P("verbose")!=0 ) objdescFlags |= OBJDESC_DETAIL;
1583
- isPatch = P("patch")!=0;
1572
+ if( verbose ) objdescFlags |= OBJDESC_DETAIL;
15841573
if( isPatch ){
15851574
Blob c1, c2, *pOut;
15861575
pOut = cgi_output_blob();
15871576
cgi_set_content_type("text/plain");
15881577
diffFlags = 4;
@@ -1592,37 +1581,20 @@
15921581
blob_reset(&c1);
15931582
blob_reset(&c2);
15941583
return;
15951584
}
15961585
1597
- sideBySide = !is_false(PD("sbs","1"));
15981586
zV1 = db_text(0, "SELECT uuid FROM blob WHERE rid=%d", v1);
15991587
zV2 = db_text(0, "SELECT uuid FROM blob WHERE rid=%d", v2);
16001588
diffFlags = construct_diff_flags(1, sideBySide) | DIFF_HTML;
16011589
16021590
style_header("Diff");
1603
- zW = (diffFlags&DIFF_IGNORE_ALLWS)?"&w":"";
1604
- if( *zW ){
1605
- style_submenu_element("Show Whitespace Changes",
1606
- "%s/fdiff?v1=%T&v2=%T&sbs=%d",
1607
- g.zTop, P("v1"), P("v2"), sideBySide);
1608
- }else{
1609
- style_submenu_element("Ignore Whitespace",
1610
- "%s/fdiff?v1=%T&v2=%T&sbs=%d&w",
1611
- g.zTop, P("v1"), P("v2"), sideBySide);
1612
- }
1591
+ style_submenu_checkbox("w", "Ignore Whitespace", 0);
1592
+ style_submenu_checkbox("sbs", "Side-by-Side Diff", 0);
1593
+ style_submenu_checkbox("verbose", "Verbose", 0);
16131594
style_submenu_element("Patch", "%s/fdiff?v1=%T&v2=%T&patch",
16141595
g.zTop, P("v1"), P("v2"));
1615
- if( !sideBySide ){
1616
- style_submenu_element("Side-by-Side Diff",
1617
- "%s/fdiff?v1=%T&v2=%T&sbs=1%s",
1618
- g.zTop, P("v1"), P("v2"), zW);
1619
- }else{
1620
- style_submenu_element("Unified Diff",
1621
- "%s/fdiff?v1=%T&v2=%T&sbs=0%s",
1622
- g.zTop, P("v1"), P("v2"), zW);
1623
- }
16241596
16251597
if( P("smhdr")!=0 ){
16261598
@ <h2>Differences From Artifact
16271599
@ %z(href("%R/artifact/%!S",zV1))[%S(zV1)]</a> To
16281600
@ %z(href("%R/artifact/%!S",zV2))[%S(zV2)]</a>.</h2>
16291601
--- src/info.c
+++ src/info.c
@@ -1071,20 +1071,20 @@
1071 ** branch=TAG Show all changes on a particular branch
1072 ** v=BOOLEAN Default true. If false, only list files that have changed
1073 ** sbs=BOOLEAN Side-by-side diff if true. Unified diff if false
1074 ** glob=STRING only diff files matching this glob
1075 ** dc=N show N lines of context around each diff
1076 ** w ignore whitespace when computing diffs
1077 ** nohdr omit the description at the top of the page
1078 **
1079 **
1080 ** Show all differences between two check-ins.
1081 */
1082 void vdiff_page(void){
1083 int ridFrom, ridTo;
1084 int verboseFlag = 0;
1085 int sideBySide = 0;
1086 u64 diffFlags = 0;
1087 Manifest *pFrom, *pTo;
1088 ManifestFile *pFileFrom, *pFileTo;
1089 const char *zBranch;
1090 const char *zFrom;
@@ -1154,21 +1154,11 @@
1154 sideBySide, (verboseFlag && !sideBySide)?"&v":"", zW);
1155 }else{
1156 style_submenu_element("Patch", "%R/vpatch?from=%T&to=%T%s", zFrom, zTo, zW);
1157 }
1158 if( sideBySide || verboseFlag ){
1159 if( *zW ){
1160 style_submenu_element("Show Whitespace Differences",
1161 "%R/vdiff?from=%T&to=%T&sbs=%d%s%s%T", zFrom, zTo,
1162 sideBySide, (verboseFlag && !sideBySide)?"&v":"",
1163 zGlob ? "&glob=" : "", zGlob ? zGlob : "");
1164 }else{
1165 style_submenu_element("Ignore Whitespace",
1166 "%R/vdiff?from=%T&to=%T&sbs=%d%s%s%T&w", zFrom, zTo,
1167 sideBySide, (verboseFlag && !sideBySide)?"&v":"",
1168 zGlob ? "&glob=" : "", zGlob ? zGlob : "");
1169 }
1170 }
1171 style_header("Check-in Differences");
1172 if( P("nohdr")==0 ){
1173 @ <h2>Difference From:</h2><blockquote>
1174 checkin_description(ridFrom);
@@ -1546,25 +1536,25 @@
1546 ** "ci" parameter is omitted, then the most recent check-in ("tip") is
1547 ** used.
1548 **
1549 ** Additional parameters:
1550 **
1551 ** dc=N Show N lines of context around each diff
1552 ** patch Use the patch diff format
1553 ** regex=REGEX Only show differences that match REGEX
1554 ** sbs=BOOLEAN Turn side-by-side diffs on and off (default: on)
1555 ** verbose Show more detail when describing artifacts
1556 ** w Ignore whitespace
1557 */
1558 void diff_page(void){
1559 int v1, v2;
1560 int isPatch;
1561 int sideBySide;
 
1562 char *zV1;
1563 char *zV2;
1564 const char *zRe;
1565 const char *zW; /* URL param for ignoring whitespace */
1566 ReCompiled *pRe = 0;
1567 u64 diffFlags;
1568 u32 objdescFlags = 0;
1569
1570 login_check_credentials();
@@ -1577,12 +1567,11 @@
1577 v2 = name_to_rid_www("v2");
1578 }
1579 if( v1==0 || v2==0 ) fossil_redirect_home();
1580 zRe = P("regex");
1581 if( zRe ) re_compile(&pRe, zRe, 0);
1582 if( P("verbose")!=0 ) objdescFlags |= OBJDESC_DETAIL;
1583 isPatch = P("patch")!=0;
1584 if( isPatch ){
1585 Blob c1, c2, *pOut;
1586 pOut = cgi_output_blob();
1587 cgi_set_content_type("text/plain");
1588 diffFlags = 4;
@@ -1592,37 +1581,20 @@
1592 blob_reset(&c1);
1593 blob_reset(&c2);
1594 return;
1595 }
1596
1597 sideBySide = !is_false(PD("sbs","1"));
1598 zV1 = db_text(0, "SELECT uuid FROM blob WHERE rid=%d", v1);
1599 zV2 = db_text(0, "SELECT uuid FROM blob WHERE rid=%d", v2);
1600 diffFlags = construct_diff_flags(1, sideBySide) | DIFF_HTML;
1601
1602 style_header("Diff");
1603 zW = (diffFlags&DIFF_IGNORE_ALLWS)?"&w":"";
1604 if( *zW ){
1605 style_submenu_element("Show Whitespace Changes",
1606 "%s/fdiff?v1=%T&v2=%T&sbs=%d",
1607 g.zTop, P("v1"), P("v2"), sideBySide);
1608 }else{
1609 style_submenu_element("Ignore Whitespace",
1610 "%s/fdiff?v1=%T&v2=%T&sbs=%d&w",
1611 g.zTop, P("v1"), P("v2"), sideBySide);
1612 }
1613 style_submenu_element("Patch", "%s/fdiff?v1=%T&v2=%T&patch",
1614 g.zTop, P("v1"), P("v2"));
1615 if( !sideBySide ){
1616 style_submenu_element("Side-by-Side Diff",
1617 "%s/fdiff?v1=%T&v2=%T&sbs=1%s",
1618 g.zTop, P("v1"), P("v2"), zW);
1619 }else{
1620 style_submenu_element("Unified Diff",
1621 "%s/fdiff?v1=%T&v2=%T&sbs=0%s",
1622 g.zTop, P("v1"), P("v2"), zW);
1623 }
1624
1625 if( P("smhdr")!=0 ){
1626 @ <h2>Differences From Artifact
1627 @ %z(href("%R/artifact/%!S",zV1))[%S(zV1)]</a> To
1628 @ %z(href("%R/artifact/%!S",zV2))[%S(zV2)]</a>.</h2>
1629
--- src/info.c
+++ src/info.c
@@ -1071,20 +1071,20 @@
1071 ** branch=TAG Show all changes on a particular branch
1072 ** v=BOOLEAN Default true. If false, only list files that have changed
1073 ** sbs=BOOLEAN Side-by-side diff if true. Unified diff if false
1074 ** glob=STRING only diff files matching this glob
1075 ** dc=N show N lines of context around each diff
1076 ** w=BOOLEAN ignore whitespace when computing diffs
1077 ** nohdr omit the description at the top of the page
1078 **
1079 **
1080 ** Show all differences between two check-ins.
1081 */
1082 void vdiff_page(void){
1083 int ridFrom, ridTo;
1084 int verboseFlag;
1085 int sideBySide;
1086 u64 diffFlags = 0;
1087 Manifest *pFrom, *pTo;
1088 ManifestFile *pFileFrom, *pFileTo;
1089 const char *zBranch;
1090 const char *zFrom;
@@ -1154,21 +1154,11 @@
1154 sideBySide, (verboseFlag && !sideBySide)?"&v":"", zW);
1155 }else{
1156 style_submenu_element("Patch", "%R/vpatch?from=%T&to=%T%s", zFrom, zTo, zW);
1157 }
1158 if( sideBySide || verboseFlag ){
1159 style_submenu_checkbox("w", "Ignore Whitespace", 0);
 
 
 
 
 
 
 
 
 
 
1160 }
1161 style_header("Check-in Differences");
1162 if( P("nohdr")==0 ){
1163 @ <h2>Difference From:</h2><blockquote>
1164 checkin_description(ridFrom);
@@ -1546,25 +1536,25 @@
1536 ** "ci" parameter is omitted, then the most recent check-in ("tip") is
1537 ** used.
1538 **
1539 ** Additional parameters:
1540 **
1541 ** dc=N Show N lines of context around each diff
1542 ** patch Use the patch diff format
1543 ** regex=REGEX Only show differences that match REGEX
1544 ** sbs=BOOLEAN Turn side-by-side diffs on and off (default: on)
1545 ** verbose=BOOLEAN Show more detail when describing artifacts
1546 ** w=BOOLEAN Ignore whitespace
1547 */
1548 void diff_page(void){
1549 int v1, v2;
1550 int isPatch = P("patch")!=0;
1551 int sideBySide = PB("sbs");
1552 int verbose = PB("verbose");
1553 char *zV1;
1554 char *zV2;
1555 const char *zRe;
 
1556 ReCompiled *pRe = 0;
1557 u64 diffFlags;
1558 u32 objdescFlags = 0;
1559
1560 login_check_credentials();
@@ -1577,12 +1567,11 @@
1567 v2 = name_to_rid_www("v2");
1568 }
1569 if( v1==0 || v2==0 ) fossil_redirect_home();
1570 zRe = P("regex");
1571 if( zRe ) re_compile(&pRe, zRe, 0);
1572 if( verbose ) objdescFlags |= OBJDESC_DETAIL;
 
1573 if( isPatch ){
1574 Blob c1, c2, *pOut;
1575 pOut = cgi_output_blob();
1576 cgi_set_content_type("text/plain");
1577 diffFlags = 4;
@@ -1592,37 +1581,20 @@
1581 blob_reset(&c1);
1582 blob_reset(&c2);
1583 return;
1584 }
1585
 
1586 zV1 = db_text(0, "SELECT uuid FROM blob WHERE rid=%d", v1);
1587 zV2 = db_text(0, "SELECT uuid FROM blob WHERE rid=%d", v2);
1588 diffFlags = construct_diff_flags(1, sideBySide) | DIFF_HTML;
1589
1590 style_header("Diff");
1591 style_submenu_checkbox("w", "Ignore Whitespace", 0);
1592 style_submenu_checkbox("sbs", "Side-by-Side Diff", 0);
1593 style_submenu_checkbox("verbose", "Verbose", 0);
 
 
 
 
 
 
 
1594 style_submenu_element("Patch", "%s/fdiff?v1=%T&v2=%T&patch",
1595 g.zTop, P("v1"), P("v2"));
 
 
 
 
 
 
 
 
 
1596
1597 if( P("smhdr")!=0 ){
1598 @ <h2>Differences From Artifact
1599 @ %z(href("%R/artifact/%!S",zV1))[%S(zV1)]</a> To
1600 @ %z(href("%R/artifact/%!S",zV2))[%S(zV2)]</a>.</h2>
1601
+46 -55
--- www/globs.md
+++ www/globs.md
@@ -48,14 +48,16 @@
4848
4949
Special characters (and special character sequences) consume zero or
5050
more characters from the target and describe what matches. The special
5151
characters (and sequences) are:
5252
53
- * `*` Matches any sequence of zero or more characters;
54
- * `?` Matches exactly one character;
55
- * `[...]` Matches one character from the enclosed list of characters; and
56
- * `[^...]` Matches one character not in the enclosed list.
53
+:Pattern |:Effect
54
+---------------------------------------------------------------------
55
+`*` | Matches any sequence of zero or more characters
56
+`?` | Matches exactly one character
57
+`[...]` | Matches one character from the enclosed list of characters
58
+`[^...]` | Matches one character not in the enclosed list
5759
5860
Special character sequences have some additional features:
5961
6062
* A range of characters may be specified with `-`, so `[a-d]` matches
6163
exactly the same characters as `[abcd]`. Ranges reflect Unicode
@@ -77,19 +79,20 @@
7779
separators as well as the initial `.` in the name of a hidden
7880
file or directory.
7981
8082
Some examples of character lists:
8183
82
- * `[a-d]` Matches any one of `a`, `b`, `c`, or `d` but not `ä`;
83
- * `[^a-d]` Matches exactly one character other than `a`, `b`, `c`,
84
- or `d`;
85
- * `[0-9a-fA-F]` Matches exactly one hexadecimal digit;
86
- * `[a-]` Matches either `a` or `-`;
87
- * `[][]` Matches either `]` or `[`;
88
- * `[^]]` Matches exactly one character other than `]`;
89
- * `[]^]` Matches either `]` or `^`; and
90
- * `[^-]` Matches exactly one character other than `-`.
84
+:Pattern |:Effect
85
+---------------------------------------------------------------------
86
+`[a-d]` | Matches any one of `a`, `b`, `c`, or `d` but not `ä`
87
+`[^a-d]` | Matches exactly one character other than `a`, `b`, `c`, or `d`
88
+`[0-9a-fA-F]` | Matches exactly one hexadecimal digit
89
+`[a-]` | Matches either `a` or `-`
90
+`[][]` | Matches either `]` or `[`
91
+`[^]]` | Matches exactly one character other than `]`
92
+`[]^]` | Matches either `]` or `^`
93
+`[^-]` | Matches exactly one character other than `-`
9194
9295
White space means the specific ASCII characters TAB, LF, VT, FF, CR,
9396
and SPACE. Note that this does not include any of the many additional
9497
spacing characters available in Unicode, and specifically does not
9598
include U+00A0 NO-BREAK SPACE.
@@ -127,44 +130,33 @@
127130
case insensitive. That is, on Windows, the names `ReadMe` and `README`
128131
are names of the same file; on Unix they are different files.
129132
130133
Some example cases:
131134
132
- * The glob `README` matches only a file named `README` in the root of
133
- the tree. It does not match a file named `src/README` because it
134
- does not include any characters that consume (and match) the
135
- `src/` part.
136
- * The glob `*/README` does match `src/README`. Unlike Unix file
137
- globs, it also matches `src/library/README`. However it does not
138
- match the file `README` in the root of the tree.
139
- * The glob `*README` does match `src/README` as well as the file
140
- `README` in the root of the tree as well as `foo/bar/README` or
141
- any other file named `README` in the tree. However, it also
142
- matches `A-DIFFERENT-README` and `src/DO-NOT-README`, or any other
143
- file whose name ends with `README`.
144
- * The glob `src/README` does match the file named `src\README` on
145
- Windows because all directory separators are rewritten as `/` in
146
- the canonical name before the glob is matched. This makes it much
147
- easier to write globs that work on both Unix and Windows.
148
- * The glob `*.[ch]` matches every C source or header file in the
149
- tree at the root or at any depth. Again, this is (deliberately)
150
- different from Unix file globs and Windows wild cards.
151
-
135
+:Pattern |:Effect
136
+--------------------------------------------------------------------------------
137
+`README` | Matches only a file named `README` in the root of the tree. It does not match a file named `src/README` because it does not include any characters that consume (and match) the `src/` part.
138
+`*/README` | Matches `src/README`. Unlike Unix file globs, it also matches `src/library/README`. However it does not match the file `README` in the root of the tree.
139
+`*README` | Matches `src/README` as well as the file `README` in the root of the tree as well as `foo/bar/README` or any other file named `README` in the tree. However, it also matches `A-DIFFERENT-README` and `src/DO-NOT-README`, or any other file whose name ends with `README`.
140
+`src/README` | Matches `src\README` on Windows because all directory separators are rewritten as `/` in the canonical name before the glob is matched. This makes it much easier to write globs that work on both Unix and Windows.
141
+`*.[ch]` | Matches every C source or header file in the tree at the root or at any depth. Again, this is (deliberately) different from Unix file globs and Windows wild cards.
152142
153143
## Where Globs are Used
154144
155145
### Settings that are Globs
156146
157147
These settings are all lists of glob patterns:
158148
159
- * `binary-glob`
160
- * `clean-glob`
161
- * `crlf-glob`
162
- * `crnl-glob`
163
- * `encoding-glob`
164
- * `ignore-glob`
165
- * `keep-glob`
149
+:Setting |:Description
150
+--------------------------------------------------------------------------------
151
+`binary-glob` | Files that should be treated as binary files for committing and merging purposes
152
+`clean-glob` | Files that the [`clean`][] command will delete without prompting or allowing undo
153
+`crlf-glob` | Files in which it is okay to have `CR`, `CR`+`LF` or mixed line endings. Set to "`*`" to disable CR+LF checking
154
+`crnl-glob` | Alias for the `crlf-glob` setting
155
+`encoding-glob` | Files that the [`commit`][] command will ignore when issuing warnings about text files that may use another encoding than ASCII or UTF-8. Set to "`*`" to disable encoding checking
156
+`ignore-glob` | Files that the [`add`][], [`addremove`][], [`clean`][], and [`extras`][] commands will ignore
157
+`keep-glob` | Files that the [`clean`][] command will keep
166158
167159
All may be [versioned, local, or global](settings.wiki). Use `fossil
168160
settings` to manage local and global settings, or a file in the
169161
repository's `.fossil-settings/` folder at the root of the tree named
170162
for each for versioned setting.
@@ -191,10 +183,11 @@
191183
192184
* [`add`][]
193185
* [`addremove`][]
194186
* [`changes`][]
195187
* [`clean`][]
188
+ * [`commit`][]
196189
* [`extras`][]
197190
* [`merge`][]
198191
* [`settings`][]
199192
* [`status`][]
200193
* [`unset`][]
@@ -211,10 +204,11 @@
211204
212205
[`add`]: /help?cmd=add
213206
[`addremove`]: /help?cmd=addremove
214207
[`changes`]: /help?cmd=changes
215208
[`clean`]: /help?cmd=clean
209
+[`commit`]: /help?cmd=commit
216210
[`extras`]: /help?cmd=extras
217211
[`merge`]: /help?cmd=merge
218212
[`settings`]: /help?cmd=settings
219213
[`status`]: /help?cmd=status
220214
[`unset`]: /help?cmd=unset
@@ -517,24 +511,21 @@
517511
front of the function that implements the command or page in files
518512
`src/*.c`. (Fossil's build system creates the tables used to dispatch
519513
commands at build time by searching the sources for those comments.) A
520514
few starting points:
521515
522
- * [`src/glob.c`][glob.c] implements glob pattern list loading,
523
- parsing, and matching.
524
- * [`src/file.c`][file.c] implements various kinds of canonical
525
- names of a file.
526
-
527
-
528
-[glob.c]: https://www.fossil-scm.org/index.html/file/src/glob.c
529
-[file.c]: https://www.fossil-scm.org/index.html/file/src/file.c
516
+:File |:Description
517
+--------------------------------------------------------------------------------
518
+[`src/glob.c`][] | Implementation of glob pattern list loading, parsing, and matching.
519
+[`src/file.c`][] | Implementation of various kinds of canonical names of a file.
520
+
521
+[`src/glob.c`]: https://www.fossil-scm.org/index.html/file/src/glob.c
522
+[`src/file.c`]: https://www.fossil-scm.org/index.html/file/src/file.c
530523
531524
The actual pattern matching is implemented in SQL, so the
532525
documentation for `GLOB` and the other string matching operators in
533526
[SQLite] (https://sqlite.org/lang_expr.html#like) is useful. Of
534
-course, the SQLite source code and test harnesses also make
535
-entertaining reading:
536
-
537
- * `src/func.c` [lines 570-768]
538
- (https://www.sqlite.org/src/artifact?name=9d52522cc8ae7f5c&ln=570-768)
539
- * `test/expr.test` [lines 586-673]
540
- (https://www.sqlite.org/src/artifact?name=66a2c9ac34f74f03&ln=586-673)
527
+course, the SQLite [source code]
528
+(https://www.sqlite.org/src/artifact?name=9d52522cc8ae7f5c&ln=570-768)
529
+and [test harnesses]
530
+(https://www.sqlite.org/src/artifact?name=66a2c9ac34f74f03&ln=586-673)
531
+also make entertaining reading.
541532
--- www/globs.md
+++ www/globs.md
@@ -48,14 +48,16 @@
48
49 Special characters (and special character sequences) consume zero or
50 more characters from the target and describe what matches. The special
51 characters (and sequences) are:
52
53 * `*` Matches any sequence of zero or more characters;
54 * `?` Matches exactly one character;
55 * `[...]` Matches one character from the enclosed list of characters; and
56 * `[^...]` Matches one character not in the enclosed list.
 
 
57
58 Special character sequences have some additional features:
59
60 * A range of characters may be specified with `-`, so `[a-d]` matches
61 exactly the same characters as `[abcd]`. Ranges reflect Unicode
@@ -77,19 +79,20 @@
77 separators as well as the initial `.` in the name of a hidden
78 file or directory.
79
80 Some examples of character lists:
81
82 * `[a-d]` Matches any one of `a`, `b`, `c`, or `d` but not `ä`;
83 * `[^a-d]` Matches exactly one character other than `a`, `b`, `c`,
84 or `d`;
85 * `[0-9a-fA-F]` Matches exactly one hexadecimal digit;
86 * `[a-]` Matches either `a` or `-`;
87 * `[][]` Matches either `]` or `[`;
88 * `[^]]` Matches exactly one character other than `]`;
89 * `[]^]` Matches either `]` or `^`; and
90 * `[^-]` Matches exactly one character other than `-`.
 
91
92 White space means the specific ASCII characters TAB, LF, VT, FF, CR,
93 and SPACE. Note that this does not include any of the many additional
94 spacing characters available in Unicode, and specifically does not
95 include U+00A0 NO-BREAK SPACE.
@@ -127,44 +130,33 @@
127 case insensitive. That is, on Windows, the names `ReadMe` and `README`
128 are names of the same file; on Unix they are different files.
129
130 Some example cases:
131
132 * The glob `README` matches only a file named `README` in the root of
133 the tree. It does not match a file named `src/README` because it
134 does not include any characters that consume (and match) the
135 `src/` part.
136 * The glob `*/README` does match `src/README`. Unlike Unix file
137 globs, it also matches `src/library/README`. However it does not
138 match the file `README` in the root of the tree.
139 * The glob `*README` does match `src/README` as well as the file
140 `README` in the root of the tree as well as `foo/bar/README` or
141 any other file named `README` in the tree. However, it also
142 matches `A-DIFFERENT-README` and `src/DO-NOT-README`, or any other
143 file whose name ends with `README`.
144 * The glob `src/README` does match the file named `src\README` on
145 Windows because all directory separators are rewritten as `/` in
146 the canonical name before the glob is matched. This makes it much
147 easier to write globs that work on both Unix and Windows.
148 * The glob `*.[ch]` matches every C source or header file in the
149 tree at the root or at any depth. Again, this is (deliberately)
150 different from Unix file globs and Windows wild cards.
151
152
153 ## Where Globs are Used
154
155 ### Settings that are Globs
156
157 These settings are all lists of glob patterns:
158
159 * `binary-glob`
160 * `clean-glob`
161 * `crlf-glob`
162 * `crnl-glob`
163 * `encoding-glob`
164 * `ignore-glob`
165 * `keep-glob`
 
 
166
167 All may be [versioned, local, or global](settings.wiki). Use `fossil
168 settings` to manage local and global settings, or a file in the
169 repository's `.fossil-settings/` folder at the root of the tree named
170 for each for versioned setting.
@@ -191,10 +183,11 @@
191
192 * [`add`][]
193 * [`addremove`][]
194 * [`changes`][]
195 * [`clean`][]
 
196 * [`extras`][]
197 * [`merge`][]
198 * [`settings`][]
199 * [`status`][]
200 * [`unset`][]
@@ -211,10 +204,11 @@
211
212 [`add`]: /help?cmd=add
213 [`addremove`]: /help?cmd=addremove
214 [`changes`]: /help?cmd=changes
215 [`clean`]: /help?cmd=clean
 
216 [`extras`]: /help?cmd=extras
217 [`merge`]: /help?cmd=merge
218 [`settings`]: /help?cmd=settings
219 [`status`]: /help?cmd=status
220 [`unset`]: /help?cmd=unset
@@ -517,24 +511,21 @@
517 front of the function that implements the command or page in files
518 `src/*.c`. (Fossil's build system creates the tables used to dispatch
519 commands at build time by searching the sources for those comments.) A
520 few starting points:
521
522 * [`src/glob.c`][glob.c] implements glob pattern list loading,
523 parsing, and matching.
524 * [`src/file.c`][file.c] implements various kinds of canonical
525 names of a file.
526
527
528 [glob.c]: https://www.fossil-scm.org/index.html/file/src/glob.c
529 [file.c]: https://www.fossil-scm.org/index.html/file/src/file.c
530
531 The actual pattern matching is implemented in SQL, so the
532 documentation for `GLOB` and the other string matching operators in
533 [SQLite] (https://sqlite.org/lang_expr.html#like) is useful. Of
534 course, the SQLite source code and test harnesses also make
535 entertaining reading:
536
537 * `src/func.c` [lines 570-768]
538 (https://www.sqlite.org/src/artifact?name=9d52522cc8ae7f5c&ln=570-768)
539 * `test/expr.test` [lines 586-673]
540 (https://www.sqlite.org/src/artifact?name=66a2c9ac34f74f03&ln=586-673)
541
--- www/globs.md
+++ www/globs.md
@@ -48,14 +48,16 @@
48
49 Special characters (and special character sequences) consume zero or
50 more characters from the target and describe what matches. The special
51 characters (and sequences) are:
52
53 :Pattern |:Effect
54 ---------------------------------------------------------------------
55 `*` | Matches any sequence of zero or more characters
56 `?` | Matches exactly one character
57 `[...]` | Matches one character from the enclosed list of characters
58 `[^...]` | Matches one character not in the enclosed list
59
60 Special character sequences have some additional features:
61
62 * A range of characters may be specified with `-`, so `[a-d]` matches
63 exactly the same characters as `[abcd]`. Ranges reflect Unicode
@@ -77,19 +79,20 @@
79 separators as well as the initial `.` in the name of a hidden
80 file or directory.
81
82 Some examples of character lists:
83
84 :Pattern |:Effect
85 ---------------------------------------------------------------------
86 `[a-d]` | Matches any one of `a`, `b`, `c`, or `d` but not `ä`
87 `[^a-d]` | Matches exactly one character other than `a`, `b`, `c`, or `d`
88 `[0-9a-fA-F]` | Matches exactly one hexadecimal digit
89 `[a-]` | Matches either `a` or `-`
90 `[][]` | Matches either `]` or `[`
91 `[^]]` | Matches exactly one character other than `]`
92 `[]^]` | Matches either `]` or `^`
93 `[^-]` | Matches exactly one character other than `-`
94
95 White space means the specific ASCII characters TAB, LF, VT, FF, CR,
96 and SPACE. Note that this does not include any of the many additional
97 spacing characters available in Unicode, and specifically does not
98 include U+00A0 NO-BREAK SPACE.
@@ -127,44 +130,33 @@
130 case insensitive. That is, on Windows, the names `ReadMe` and `README`
131 are names of the same file; on Unix they are different files.
132
133 Some example cases:
134
135 :Pattern |:Effect
136 --------------------------------------------------------------------------------
137 `README` | Matches only a file named `README` in the root of the tree. It does not match a file named `src/README` because it does not include any characters that consume (and match) the `src/` part.
138 `*/README` | Matches `src/README`. Unlike Unix file globs, it also matches `src/library/README`. However it does not match the file `README` in the root of the tree.
139 `*README` | Matches `src/README` as well as the file `README` in the root of the tree as well as `foo/bar/README` or any other file named `README` in the tree. However, it also matches `A-DIFFERENT-README` and `src/DO-NOT-README`, or any other file whose name ends with `README`.
140 `src/README` | Matches `src\README` on Windows because all directory separators are rewritten as `/` in the canonical name before the glob is matched. This makes it much easier to write globs that work on both Unix and Windows.
141 `*.[ch]` | Matches every C source or header file in the tree at the root or at any depth. Again, this is (deliberately) different from Unix file globs and Windows wild cards.
 
 
 
 
 
 
 
 
 
 
 
 
 
142
143 ## Where Globs are Used
144
145 ### Settings that are Globs
146
147 These settings are all lists of glob patterns:
148
149 :Setting |:Description
150 --------------------------------------------------------------------------------
151 `binary-glob` | Files that should be treated as binary files for committing and merging purposes
152 `clean-glob` | Files that the [`clean`][] command will delete without prompting or allowing undo
153 `crlf-glob` | Files in which it is okay to have `CR`, `CR`+`LF` or mixed line endings. Set to "`*`" to disable CR+LF checking
154 `crnl-glob` | Alias for the `crlf-glob` setting
155 `encoding-glob` | Files that the [`commit`][] command will ignore when issuing warnings about text files that may use another encoding than ASCII or UTF-8. Set to "`*`" to disable encoding checking
156 `ignore-glob` | Files that the [`add`][], [`addremove`][], [`clean`][], and [`extras`][] commands will ignore
157 `keep-glob` | Files that the [`clean`][] command will keep
158
159 All may be [versioned, local, or global](settings.wiki). Use `fossil
160 settings` to manage local and global settings, or a file in the
161 repository's `.fossil-settings/` folder at the root of the tree named
162 for each for versioned setting.
@@ -191,10 +183,11 @@
183
184 * [`add`][]
185 * [`addremove`][]
186 * [`changes`][]
187 * [`clean`][]
188 * [`commit`][]
189 * [`extras`][]
190 * [`merge`][]
191 * [`settings`][]
192 * [`status`][]
193 * [`unset`][]
@@ -211,10 +204,11 @@
204
205 [`add`]: /help?cmd=add
206 [`addremove`]: /help?cmd=addremove
207 [`changes`]: /help?cmd=changes
208 [`clean`]: /help?cmd=clean
209 [`commit`]: /help?cmd=commit
210 [`extras`]: /help?cmd=extras
211 [`merge`]: /help?cmd=merge
212 [`settings`]: /help?cmd=settings
213 [`status`]: /help?cmd=status
214 [`unset`]: /help?cmd=unset
@@ -517,24 +511,21 @@
511 front of the function that implements the command or page in files
512 `src/*.c`. (Fossil's build system creates the tables used to dispatch
513 commands at build time by searching the sources for those comments.) A
514 few starting points:
515
516 :File |:Description
517 --------------------------------------------------------------------------------
518 [`src/glob.c`][] | Implementation of glob pattern list loading, parsing, and matching.
519 [`src/file.c`][] | Implementation of various kinds of canonical names of a file.
520
521 [`src/glob.c`]: https://www.fossil-scm.org/index.html/file/src/glob.c
522 [`src/file.c`]: https://www.fossil-scm.org/index.html/file/src/file.c
 
523
524 The actual pattern matching is implemented in SQL, so the
525 documentation for `GLOB` and the other string matching operators in
526 [SQLite] (https://sqlite.org/lang_expr.html#like) is useful. Of
527 course, the SQLite [source code]
528 (https://www.sqlite.org/src/artifact?name=9d52522cc8ae7f5c&ln=570-768)
529 and [test harnesses]
530 (https://www.sqlite.org/src/artifact?name=66a2c9ac34f74f03&ln=586-673)
531 also make entertaining reading.
 
 
532

Keyboard Shortcuts

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