Fossil SCM

Full-text search for check-in diffs. This works, but it creates a huge index (2x the size of the BLOB table) in spite of being a contentless index. The index is slow to build because of all the diffs that must be computed. Because the index is contentless, the snippet generator runs very slowly on queries - a typical query with a couple hundred hits takes several minutes.

drh 2016-06-25 03:56 UTC trunk
Commit 68194175fb4ccf1b036c8ddc2da912f5dd7e46b5
+6 -5
--- src/diff.c
+++ src/diff.c
@@ -40,10 +40,11 @@
4040
#define DIFF_NOOPT (((u64)0x01)<<32) /* Suppress optimizations (debug) */
4141
#define DIFF_INVERT (((u64)0x02)<<32) /* Invert the diff (debug) */
4242
#define DIFF_CONTEXT_EX (((u64)0x04)<<32) /* Use context even if zero */
4343
#define DIFF_NOTTOOBIG (((u64)0x08)<<32) /* Only display if not too big */
4444
#define DIFF_STRIP_EOLCR (((u64)0x10)<<32) /* Strip trailing CR */
45
+#define DIFF_NO_ERRMSG (((u64)0x20)<<32) /* Do not generate error messages */
4546
4647
/*
4748
** These error messages are shared in multiple locations. They are defined
4849
** here for consistency.
4950
*/
@@ -1804,10 +1805,12 @@
18041805
18051806
/*
18061807
** Append the error message to pOut.
18071808
*/
18081809
void diff_errmsg(Blob *pOut, const char *msg, int diffFlags){
1810
+ if( pOut==0 ) return;
1811
+ if( diffFlags & DIFF_NO_ERRMSG ) return;
18091812
if( diffFlags & DIFF_HTML ){
18101813
blob_appendf(pOut, "<p class=\"generalError\">%s</p>", msg);
18111814
}else{
18121815
blob_append(pOut, msg, -1);
18131816
}
@@ -1858,23 +1861,21 @@
18581861
c.aTo = break_into_lines(blob_str(pB_Blob), blob_size(pB_Blob),
18591862
&c.nTo, diffFlags);
18601863
if( c.aFrom==0 || c.aTo==0 ){
18611864
fossil_free(c.aFrom);
18621865
fossil_free(c.aTo);
1863
- if( pOut ){
1864
- diff_errmsg(pOut, DIFF_CANNOT_COMPUTE_BINARY, diffFlags);
1865
- }
1866
+ diff_errmsg(pOut, DIFF_CANNOT_COMPUTE_BINARY, diffFlags);
18661867
return 0;
18671868
}
18681869
18691870
/* Compute the difference */
18701871
diff_all(&c);
18711872
if( ignoreWs && c.nEdit==6 && c.aEdit[1]==0 && c.aEdit[2]==0 ){
18721873
fossil_free(c.aFrom);
18731874
fossil_free(c.aTo);
18741875
fossil_free(c.aEdit);
1875
- if( pOut ) diff_errmsg(pOut, DIFF_WHITESPACE_ONLY, diffFlags);
1876
+ diff_errmsg(pOut, DIFF_WHITESPACE_ONLY, diffFlags);
18761877
return 0;
18771878
}
18781879
if( (diffFlags & DIFF_NOTTOOBIG)!=0 ){
18791880
int i, m, n;
18801881
int *a = c.aEdit;
@@ -1882,11 +1883,11 @@
18821883
for(i=m=n=0; i<mx; i+=3){ m += a[i]; n += a[i+1]+a[i+2]; }
18831884
if( n>10000 ){
18841885
fossil_free(c.aFrom);
18851886
fossil_free(c.aTo);
18861887
fossil_free(c.aEdit);
1887
- if( pOut ) diff_errmsg(pOut, DIFF_TOO_MANY_CHANGES, diffFlags);
1888
+ diff_errmsg(pOut, DIFF_TOO_MANY_CHANGES, diffFlags);
18881889
return 0;
18891890
}
18901891
}
18911892
if( (diffFlags & DIFF_NOOPT)==0 ){
18921893
diff_optimize(&c);
18931894
--- src/diff.c
+++ src/diff.c
@@ -40,10 +40,11 @@
40 #define DIFF_NOOPT (((u64)0x01)<<32) /* Suppress optimizations (debug) */
41 #define DIFF_INVERT (((u64)0x02)<<32) /* Invert the diff (debug) */
42 #define DIFF_CONTEXT_EX (((u64)0x04)<<32) /* Use context even if zero */
43 #define DIFF_NOTTOOBIG (((u64)0x08)<<32) /* Only display if not too big */
44 #define DIFF_STRIP_EOLCR (((u64)0x10)<<32) /* Strip trailing CR */
 
45
46 /*
47 ** These error messages are shared in multiple locations. They are defined
48 ** here for consistency.
49 */
@@ -1804,10 +1805,12 @@
1804
1805 /*
1806 ** Append the error message to pOut.
1807 */
1808 void diff_errmsg(Blob *pOut, const char *msg, int diffFlags){
 
 
1809 if( diffFlags & DIFF_HTML ){
1810 blob_appendf(pOut, "<p class=\"generalError\">%s</p>", msg);
1811 }else{
1812 blob_append(pOut, msg, -1);
1813 }
@@ -1858,23 +1861,21 @@
1858 c.aTo = break_into_lines(blob_str(pB_Blob), blob_size(pB_Blob),
1859 &c.nTo, diffFlags);
1860 if( c.aFrom==0 || c.aTo==0 ){
1861 fossil_free(c.aFrom);
1862 fossil_free(c.aTo);
1863 if( pOut ){
1864 diff_errmsg(pOut, DIFF_CANNOT_COMPUTE_BINARY, diffFlags);
1865 }
1866 return 0;
1867 }
1868
1869 /* Compute the difference */
1870 diff_all(&c);
1871 if( ignoreWs && c.nEdit==6 && c.aEdit[1]==0 && c.aEdit[2]==0 ){
1872 fossil_free(c.aFrom);
1873 fossil_free(c.aTo);
1874 fossil_free(c.aEdit);
1875 if( pOut ) diff_errmsg(pOut, DIFF_WHITESPACE_ONLY, diffFlags);
1876 return 0;
1877 }
1878 if( (diffFlags & DIFF_NOTTOOBIG)!=0 ){
1879 int i, m, n;
1880 int *a = c.aEdit;
@@ -1882,11 +1883,11 @@
1882 for(i=m=n=0; i<mx; i+=3){ m += a[i]; n += a[i+1]+a[i+2]; }
1883 if( n>10000 ){
1884 fossil_free(c.aFrom);
1885 fossil_free(c.aTo);
1886 fossil_free(c.aEdit);
1887 if( pOut ) diff_errmsg(pOut, DIFF_TOO_MANY_CHANGES, diffFlags);
1888 return 0;
1889 }
1890 }
1891 if( (diffFlags & DIFF_NOOPT)==0 ){
1892 diff_optimize(&c);
1893
--- src/diff.c
+++ src/diff.c
@@ -40,10 +40,11 @@
40 #define DIFF_NOOPT (((u64)0x01)<<32) /* Suppress optimizations (debug) */
41 #define DIFF_INVERT (((u64)0x02)<<32) /* Invert the diff (debug) */
42 #define DIFF_CONTEXT_EX (((u64)0x04)<<32) /* Use context even if zero */
43 #define DIFF_NOTTOOBIG (((u64)0x08)<<32) /* Only display if not too big */
44 #define DIFF_STRIP_EOLCR (((u64)0x10)<<32) /* Strip trailing CR */
45 #define DIFF_NO_ERRMSG (((u64)0x20)<<32) /* Do not generate error messages */
46
47 /*
48 ** These error messages are shared in multiple locations. They are defined
49 ** here for consistency.
50 */
@@ -1804,10 +1805,12 @@
1805
1806 /*
1807 ** Append the error message to pOut.
1808 */
1809 void diff_errmsg(Blob *pOut, const char *msg, int diffFlags){
1810 if( pOut==0 ) return;
1811 if( diffFlags & DIFF_NO_ERRMSG ) return;
1812 if( diffFlags & DIFF_HTML ){
1813 blob_appendf(pOut, "<p class=\"generalError\">%s</p>", msg);
1814 }else{
1815 blob_append(pOut, msg, -1);
1816 }
@@ -1858,23 +1861,21 @@
1861 c.aTo = break_into_lines(blob_str(pB_Blob), blob_size(pB_Blob),
1862 &c.nTo, diffFlags);
1863 if( c.aFrom==0 || c.aTo==0 ){
1864 fossil_free(c.aFrom);
1865 fossil_free(c.aTo);
1866 diff_errmsg(pOut, DIFF_CANNOT_COMPUTE_BINARY, diffFlags);
 
 
1867 return 0;
1868 }
1869
1870 /* Compute the difference */
1871 diff_all(&c);
1872 if( ignoreWs && c.nEdit==6 && c.aEdit[1]==0 && c.aEdit[2]==0 ){
1873 fossil_free(c.aFrom);
1874 fossil_free(c.aTo);
1875 fossil_free(c.aEdit);
1876 diff_errmsg(pOut, DIFF_WHITESPACE_ONLY, diffFlags);
1877 return 0;
1878 }
1879 if( (diffFlags & DIFF_NOTTOOBIG)!=0 ){
1880 int i, m, n;
1881 int *a = c.aEdit;
@@ -1882,11 +1883,11 @@
1883 for(i=m=n=0; i<mx; i+=3){ m += a[i]; n += a[i+1]+a[i+2]; }
1884 if( n>10000 ){
1885 fossil_free(c.aFrom);
1886 fossil_free(c.aTo);
1887 fossil_free(c.aEdit);
1888 diff_errmsg(pOut, DIFF_TOO_MANY_CHANGES, diffFlags);
1889 return 0;
1890 }
1891 }
1892 if( (diffFlags & DIFF_NOOPT)==0 ){
1893 diff_optimize(&c);
1894
--- src/diffcmd.c
+++ src/diffcmd.c
@@ -927,5 +927,82 @@
927927
if( zFrom==0 || zTo==0 ) fossil_redirect_home();
928928
929929
cgi_set_content_type("text/plain");
930930
diff_two_versions(zFrom, zTo, 0, 0, 0, DIFF_VERBOSE, 0);
931931
}
932
+
933
+/*
934
+** Compute a string (into pOut) that is a diff of check-in "rid" and its
935
+** primary parent. The diff has no context lines and is designed to support
936
+** full-text search.
937
+*/
938
+void diff_for_search(int rid, Blob *pOut){
939
+ Manifest *pFrom, *pTo;
940
+ ManifestFile *pFromFile, *pToFile;
941
+ const u64 diffFlags = DIFF_NO_ERRMSG | DIFF_IGNORE_ALLWS | DIFF_CONTEXT_EX;
942
+
943
+ pTo = manifest_get(rid, CFTYPE_MANIFEST, 0);
944
+ if( pTo==0 ) return;
945
+ if( pTo->nParent==0 ){
946
+ manifest_destroy(pTo);
947
+ return;
948
+ }
949
+ pFrom = manifest_get_by_name(pTo->azParent[0], 0);
950
+ manifest_file_rewind(pFrom);
951
+ manifest_file_rewind(pTo);
952
+ pFromFile = manifest_file_next(pFrom,0);
953
+ pToFile = manifest_file_next(pTo,0);
954
+
955
+ while( pFromFile || pToFile ){
956
+ int cmp;
957
+ if( pFromFile==0 ){
958
+ cmp = +1;
959
+ }else if( pToFile==0 ){
960
+ cmp = -1;
961
+ }else{
962
+ cmp = fossil_strcmp(pFromFile->zName, pToFile->zName);
963
+ }
964
+ if( cmp<0 ){
965
+ blob_appendf(pOut, "DELETED %s\n", pFromFile->zName);
966
+ pFromFile = manifest_file_next(pFrom,0);
967
+ }else if( cmp>0 ){
968
+ blob_appendf(pOut, "ADDED %s\n", pToFile->zName);
969
+ pToFile = manifest_file_next(pTo,0);
970
+ }else if( fossil_strcmp(pFromFile->zUuid, pToFile->zUuid)==0 ){
971
+ /* No changes */
972
+ pFromFile = manifest_file_next(pFrom,0);
973
+ pToFile = manifest_file_next(pTo,0);
974
+ }else{
975
+ Blob fileA, fileB;
976
+ blob_appendf(pOut, "CHANGED %s\n", pToFile->zName);
977
+ rid = uuid_to_rid(pFromFile->zUuid, 0);
978
+ content_get(rid, &fileA);
979
+ rid = uuid_to_rid(pToFile->zUuid, 0);
980
+ content_get(rid, &fileB);
981
+ text_diff(&fileA, &fileB, pOut, 0, diffFlags);
982
+ blob_reset(&fileA);
983
+ blob_reset(&fileB);
984
+ pFromFile = manifest_file_next(pFrom,0);
985
+ pToFile = manifest_file_next(pTo,0);
986
+ }
987
+ }
988
+ manifest_destroy(pFrom);
989
+ manifest_destroy(pTo);
990
+}
991
+
992
+/*
993
+** Implement the diff(RID) SQL function that returns a text diff for
994
+** check-in RID.
995
+*/
996
+void diff_sqlfunc(
997
+ sqlite3_context *context,
998
+ int argc,
999
+ sqlite3_value **argv
1000
+){
1001
+ int rid;
1002
+ Blob out;
1003
+ rid = sqlite3_value_int(argv[0]);
1004
+ blob_init(&out, 0, 0);
1005
+ diff_for_search(rid, &out);
1006
+ sqlite3_result_text(context, blob_str(&out), blob_size(&out), SQLITE_TRANSIENT);
1007
+ blob_reset(&out);
1008
+}
9321009
--- src/diffcmd.c
+++ src/diffcmd.c
@@ -927,5 +927,82 @@
927 if( zFrom==0 || zTo==0 ) fossil_redirect_home();
928
929 cgi_set_content_type("text/plain");
930 diff_two_versions(zFrom, zTo, 0, 0, 0, DIFF_VERBOSE, 0);
931 }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
932
--- src/diffcmd.c
+++ src/diffcmd.c
@@ -927,5 +927,82 @@
927 if( zFrom==0 || zTo==0 ) fossil_redirect_home();
928
929 cgi_set_content_type("text/plain");
930 diff_two_versions(zFrom, zTo, 0, 0, 0, DIFF_VERBOSE, 0);
931 }
932
933 /*
934 ** Compute a string (into pOut) that is a diff of check-in "rid" and its
935 ** primary parent. The diff has no context lines and is designed to support
936 ** full-text search.
937 */
938 void diff_for_search(int rid, Blob *pOut){
939 Manifest *pFrom, *pTo;
940 ManifestFile *pFromFile, *pToFile;
941 const u64 diffFlags = DIFF_NO_ERRMSG | DIFF_IGNORE_ALLWS | DIFF_CONTEXT_EX;
942
943 pTo = manifest_get(rid, CFTYPE_MANIFEST, 0);
944 if( pTo==0 ) return;
945 if( pTo->nParent==0 ){
946 manifest_destroy(pTo);
947 return;
948 }
949 pFrom = manifest_get_by_name(pTo->azParent[0], 0);
950 manifest_file_rewind(pFrom);
951 manifest_file_rewind(pTo);
952 pFromFile = manifest_file_next(pFrom,0);
953 pToFile = manifest_file_next(pTo,0);
954
955 while( pFromFile || pToFile ){
956 int cmp;
957 if( pFromFile==0 ){
958 cmp = +1;
959 }else if( pToFile==0 ){
960 cmp = -1;
961 }else{
962 cmp = fossil_strcmp(pFromFile->zName, pToFile->zName);
963 }
964 if( cmp<0 ){
965 blob_appendf(pOut, "DELETED %s\n", pFromFile->zName);
966 pFromFile = manifest_file_next(pFrom,0);
967 }else if( cmp>0 ){
968 blob_appendf(pOut, "ADDED %s\n", pToFile->zName);
969 pToFile = manifest_file_next(pTo,0);
970 }else if( fossil_strcmp(pFromFile->zUuid, pToFile->zUuid)==0 ){
971 /* No changes */
972 pFromFile = manifest_file_next(pFrom,0);
973 pToFile = manifest_file_next(pTo,0);
974 }else{
975 Blob fileA, fileB;
976 blob_appendf(pOut, "CHANGED %s\n", pToFile->zName);
977 rid = uuid_to_rid(pFromFile->zUuid, 0);
978 content_get(rid, &fileA);
979 rid = uuid_to_rid(pToFile->zUuid, 0);
980 content_get(rid, &fileB);
981 text_diff(&fileA, &fileB, pOut, 0, diffFlags);
982 blob_reset(&fileA);
983 blob_reset(&fileB);
984 pFromFile = manifest_file_next(pFrom,0);
985 pToFile = manifest_file_next(pTo,0);
986 }
987 }
988 manifest_destroy(pFrom);
989 manifest_destroy(pTo);
990 }
991
992 /*
993 ** Implement the diff(RID) SQL function that returns a text diff for
994 ** check-in RID.
995 */
996 void diff_sqlfunc(
997 sqlite3_context *context,
998 int argc,
999 sqlite3_value **argv
1000 ){
1001 int rid;
1002 Blob out;
1003 rid = sqlite3_value_int(argv[0]);
1004 blob_init(&out, 0, 0);
1005 diff_for_search(rid, &out);
1006 sqlite3_result_text(context, blob_str(&out), blob_size(&out), SQLITE_TRANSIENT);
1007 blob_reset(&out);
1008 }
1009
+60 -14
--- src/search.c
+++ src/search.c
@@ -510,10 +510,12 @@
510510
search_title_sqlfunc, 0, 0);
511511
sqlite3_create_function(db, "body", 3, SQLITE_UTF8, 0,
512512
search_body_sqlfunc, 0, 0);
513513
sqlite3_create_function(db, "urlencode", 1, SQLITE_UTF8, 0,
514514
search_urlencode_sqlfunc, 0, 0);
515
+ sqlite3_create_function(db, "diff", 1, SQLITE_UTF8, 0,
516
+ diff_sqlfunc, 0, 0);
515517
}
516518
517519
/*
518520
** Testing the search function.
519521
**
@@ -600,11 +602,12 @@
600602
/* What to search for */
601603
#define SRCH_CKIN 0x0001 /* Search over check-in comments */
602604
#define SRCH_DOC 0x0002 /* Search over embedded documents */
603605
#define SRCH_TKT 0x0004 /* Search over tickets */
604606
#define SRCH_WIKI 0x0008 /* Search over wiki */
605
-#define SRCH_ALL 0x000f /* Search over everything */
607
+#define SRCH_DIFF 0x0010 /* Search check-in diffs */
608
+#define SRCH_ALL 0x001f /* Search over everything */
606609
#endif
607610
608611
/*
609612
** Remove bits from srchFlags which are disallowed by either the
610613
** current server configuration or by user permissions.
@@ -615,13 +618,14 @@
615618
static const struct { unsigned m; const char *zKey; } aSetng[] = {
616619
{ SRCH_CKIN, "search-ci" },
617620
{ SRCH_DOC, "search-doc" },
618621
{ SRCH_TKT, "search-tkt" },
619622
{ SRCH_WIKI, "search-wiki" },
623
+ { SRCH_DIFF, "search-diff" },
620624
};
621625
int i;
622
- if( g.perm.Read==0 ) srchFlags &= ~(SRCH_CKIN|SRCH_DOC);
626
+ if( g.perm.Read==0 ) srchFlags &= ~(SRCH_CKIN|SRCH_DOC|SRCH_DIFF);
623627
if( g.perm.RdTkt==0 ) srchFlags &= ~(SRCH_TKT);
624628
if( g.perm.RdWiki==0 ) srchFlags &= ~(SRCH_WIKI);
625629
for(i=0; i<ArraySize(aSetng); i++){
626630
unsigned int m = aSetng[i].m;
627631
if( (srchFlags & m)==0 ) continue;
@@ -841,10 +845,11 @@
841845
static const struct { unsigned m; char c; } aMask[] = {
842846
{ SRCH_CKIN, 'c' },
843847
{ SRCH_DOC, 'd' },
844848
{ SRCH_TKT, 't' },
845849
{ SRCH_WIKI, 'w' },
850
+ { SRCH_DIFF, 'x' },
846851
};
847852
int i;
848853
for(i=0; i<ArraySize(aMask); i++){
849854
if( srchFlags & aMask[i].m ){
850855
blob_appendf(&sql, "%sftsdocs.type='%c'", zSep, aMask[i].c);
@@ -988,10 +993,11 @@
988993
switch( srchFlags ){
989994
case SRCH_CKIN: zType = " Check-ins"; zClass = "Ckin"; break;
990995
case SRCH_DOC: zType = " Docs"; zClass = "Doc"; break;
991996
case SRCH_TKT: zType = " Tickets"; zClass = "Tkt"; break;
992997
case SRCH_WIKI: zType = " Wiki"; zClass = "Wiki"; break;
998
+ case SRCH_DIFF: zType = " Diffs"; zClass = "Diff"; break;
993999
}
9941000
if( srchFlags==0 ){
9951001
zDisable1 = " disabled";
9961002
zDisable2 = " disabled";
9971003
zPattern = "";
@@ -1012,10 +1018,11 @@
10121018
{ "all", "All", SRCH_ALL },
10131019
{ "c", "Check-ins", SRCH_CKIN },
10141020
{ "d", "Docs", SRCH_DOC },
10151021
{ "t", "Tickets", SRCH_TKT },
10161022
{ "w", "Wiki", SRCH_WIKI },
1023
+ { "z", "Diff", SRCH_DIFF },
10171024
};
10181025
const char *zY = PD("y","all");
10191026
unsigned newFlags = srchFlags;
10201027
int i;
10211028
@ <select size='1' name='y'>
@@ -1063,10 +1070,11 @@
10631070
** y=TYPE What to search.
10641071
** c -> check-ins
10651072
** d -> documentation
10661073
** t -> tickets
10671074
** w -> wiki
1075
+** x -> diff
10681076
** all -> everything
10691077
*/
10701078
void search_page(void){
10711079
login_check_credentials();
10721080
style_header("Search");
@@ -1169,10 +1177,11 @@
11691177
**
11701178
** cType: d Embedded documentation
11711179
** w Wiki page
11721180
** c Check-in comment
11731181
** t Ticket text
1182
+** x Check-in diffs
11741183
**
11751184
** rid The RID of an artifact that defines the object
11761185
** being searched.
11771186
**
11781187
** zName Name of the object being searched.
@@ -1182,10 +1191,11 @@
11821191
int rid, /* BLOB.RID or TAG.TAGID value for document */
11831192
const char *zName, /* Auxiliary information */
11841193
Blob *pOut /* OUT: Initialize to the search text */
11851194
){
11861195
blob_init(pOut, 0, 0);
1196
+ /* printf("stext(%c%d)\n", cType, rid); fflush(stdout); */
11871197
switch( cType ){
11881198
case 'd': { /* Documents */
11891199
Blob doc;
11901200
content_get(rid, &doc);
11911201
blob_to_utf8_no_bom(&doc, 0);
@@ -1201,10 +1211,14 @@
12011211
get_stext_by_mimetype(&wiki, wiki_filter_mimetypes(pWiki->zMimetype),
12021212
pOut);
12031213
blob_reset(&wiki);
12041214
manifest_destroy(pWiki);
12051215
break;
1216
+ }
1217
+ case 'x': { /* Check-in diff */
1218
+ diff_for_search(rid, pOut);
1219
+ break;
12061220
}
12071221
case 'c': { /* Check-in Comments */
12081222
static Stmt q;
12091223
static int isPlainText = -1;
12101224
db_static_prepare(&q,
@@ -1411,10 +1425,14 @@
14111425
search_sql_setup(g.db);
14121426
db_multi_exec(
14131427
"INSERT OR IGNORE INTO ftsdocs(type,rid,idxed)"
14141428
" SELECT 'c', objid, 0 FROM event WHERE type='ci';"
14151429
);
1430
+ db_multi_exec(
1431
+ "INSERT OR IGNORE INTO ftsdocs(type,rid,idxed)"
1432
+ " SELECT 'x', objid, 0 FROM event WHERE type='ci';"
1433
+ );
14161434
db_multi_exec(
14171435
"WITH latest_wiki(rid,name,mtime) AS ("
14181436
" SELECT tagxref.rid, substr(tag.tagname,6), max(tagxref.mtime)"
14191437
" FROM tag, tagxref"
14201438
" WHERE tag.tagname GLOB 'wiki-*'"
@@ -1545,10 +1563,32 @@
15451563
" WHERE ftsdocs.type='c' AND NOT ftsdocs.idxed"
15461564
" AND event.objid=ftsdocs.rid"
15471565
" AND blob.rid=ftsdocs.rid"
15481566
);
15491567
}
1568
+
1569
+/*
1570
+** Deal with all of the unindexed 'x' terms in FTSDOCS
1571
+*/
1572
+static void search_update_diff_index(void){
1573
+ db_multi_exec(
1574
+ "INSERT INTO ftsidx(docid,title,body)"
1575
+ " SELECT rowid, '', body('x',rid,NULL) FROM ftsdocs"
1576
+ " WHERE type='x' AND NOT idxed;"
1577
+ );
1578
+ db_multi_exec(
1579
+ "REPLACE INTO ftsdocs(rowid,idxed,type,rid,name,label,url,mtime)"
1580
+ " SELECT ftsdocs.rowid, 1, 'x', ftsdocs.rid, NULL,"
1581
+ " printf('Check-in [%%.16s] on %%s',blob.uuid,datetime(event.mtime)),"
1582
+ " printf('/info/%%.20s',blob.uuid),"
1583
+ " event.mtime"
1584
+ " FROM ftsdocs, event, blob"
1585
+ " WHERE ftsdocs.type='x' AND NOT ftsdocs.idxed"
1586
+ " AND event.objid=ftsdocs.rid"
1587
+ " AND blob.rid=ftsdocs.rid"
1588
+ );
1589
+}
15501590
15511591
/*
15521592
** Deal with all of the unindexed 't' terms in FTSDOCS
15531593
*/
15541594
static void search_update_ticket_index(void){
@@ -1604,10 +1644,13 @@
16041644
search_sql_setup(g.db);
16051645
if( srchFlags & (SRCH_CKIN|SRCH_DOC) ){
16061646
search_update_doc_index();
16071647
search_update_checkin_index();
16081648
}
1649
+ if( srchFlags & SRCH_DIFF ){
1650
+ search_update_diff_index();
1651
+ }
16091652
if( srchFlags & SRCH_TKT ){
16101653
search_update_ticket_index();
16111654
}
16121655
if( srchFlags & SRCH_WIKI ){
16131656
search_update_wiki_index();
@@ -1637,14 +1680,14 @@
16371680
** reindex Rebuild the search index. This is a no-op if
16381681
** index search is disabled
16391682
**
16401683
** index (on|off) Turn the search index on or off
16411684
**
1642
-** enable cdtw Enable various kinds of search. c=Check-ins,
1643
-** d=Documents, t=Tickets, w=Wiki.
1685
+** enable cdtwx Enable various kinds of search. c=Check-ins,
1686
+** d=Documents, t=Tickets, w=Wiki, x=Diffs.
16441687
**
1645
-** disable cdtw Disable various kinds of search
1688
+** disable cdtwx Disable various kinds of search
16461689
**
16471690
** stemmer (on|off) Turn the Porter stemmer on or off for indexed
16481691
** search. (Unindexed search is never stemmed.)
16491692
**
16501693
** The current search settings are displayed after any changes are applied.
@@ -1657,14 +1700,15 @@
16571700
{ 3, "disable" },
16581701
{ 4, "enable" },
16591702
{ 5, "stemmer" },
16601703
};
16611704
static const struct { char *zSetting; char *zName; char *zSw; } aSetng[] = {
1662
- { "search-ckin", "check-in search:", "c" },
1663
- { "search-doc", "document search:", "d" },
1664
- { "search-tkt", "ticket search:", "t" },
1665
- { "search-wiki", "wiki search:", "w" },
1705
+ { "search-ckin", "check-in comment search:", "c" },
1706
+ { "search-diff", "check-in diff search:", "x" },
1707
+ { "search-doc", "document search:", "d" },
1708
+ { "search-tkt", "ticket search:", "t" },
1709
+ { "search-wiki", "wiki search:", "w" },
16661710
};
16671711
char *zSubCmd = 0;
16681712
int i, j, n;
16691713
int iCmd = 0;
16701714
int iAction = 0;
@@ -1683,10 +1727,12 @@
16831727
zSubCmd, blob_str(&all));
16841728
return;
16851729
}
16861730
iCmd = aCmd[i].iCmd;
16871731
}
1732
+ login_set_capabilities("s",0);
1733
+ g.zTop = "";
16881734
if( iCmd==1 ){
16891735
if( search_index_exists() ) iAction = 2;
16901736
}
16911737
if( iCmd==2 ){
16921738
if( g.argc<3 ) usage("index (on|off)");
@@ -1719,19 +1765,19 @@
17191765
search_rebuild_index();
17201766
}
17211767
17221768
/* Always show the status before ending */
17231769
for(i=0; i<ArraySize(aSetng); i++){
1724
- fossil_print("%-16s %s\n", aSetng[i].zName,
1770
+ fossil_print("%-25s %s\n", aSetng[i].zName,
17251771
db_get_boolean(aSetng[i].zSetting,0) ? "on" : "off");
17261772
}
1727
- fossil_print("%-16s %s\n", "Porter stemmer:",
1773
+ fossil_print("%-25s %s\n", "Porter stemmer:",
17281774
db_get_boolean("search-stemmer",0) ? "on" : "off");
17291775
if( search_index_exists() ){
1730
- fossil_print("%-16s enabled\n", "full-text index:");
1731
- fossil_print("%-16s %d\n", "documents:",
1776
+ fossil_print("%-25s enabled\n", "full-text index:");
1777
+ fossil_print("%-25s %d\n", "documents:",
17321778
db_int(0, "SELECT count(*) FROM ftsdocs"));
17331779
}else{
1734
- fossil_print("%-16s disabled\n", "full-text index:");
1780
+ fossil_print("%-25s disabled\n", "full-text index:");
17351781
}
17361782
db_end_transaction(0);
17371783
}
17381784
--- src/search.c
+++ src/search.c
@@ -510,10 +510,12 @@
510 search_title_sqlfunc, 0, 0);
511 sqlite3_create_function(db, "body", 3, SQLITE_UTF8, 0,
512 search_body_sqlfunc, 0, 0);
513 sqlite3_create_function(db, "urlencode", 1, SQLITE_UTF8, 0,
514 search_urlencode_sqlfunc, 0, 0);
 
 
515 }
516
517 /*
518 ** Testing the search function.
519 **
@@ -600,11 +602,12 @@
600 /* What to search for */
601 #define SRCH_CKIN 0x0001 /* Search over check-in comments */
602 #define SRCH_DOC 0x0002 /* Search over embedded documents */
603 #define SRCH_TKT 0x0004 /* Search over tickets */
604 #define SRCH_WIKI 0x0008 /* Search over wiki */
605 #define SRCH_ALL 0x000f /* Search over everything */
 
606 #endif
607
608 /*
609 ** Remove bits from srchFlags which are disallowed by either the
610 ** current server configuration or by user permissions.
@@ -615,13 +618,14 @@
615 static const struct { unsigned m; const char *zKey; } aSetng[] = {
616 { SRCH_CKIN, "search-ci" },
617 { SRCH_DOC, "search-doc" },
618 { SRCH_TKT, "search-tkt" },
619 { SRCH_WIKI, "search-wiki" },
 
620 };
621 int i;
622 if( g.perm.Read==0 ) srchFlags &= ~(SRCH_CKIN|SRCH_DOC);
623 if( g.perm.RdTkt==0 ) srchFlags &= ~(SRCH_TKT);
624 if( g.perm.RdWiki==0 ) srchFlags &= ~(SRCH_WIKI);
625 for(i=0; i<ArraySize(aSetng); i++){
626 unsigned int m = aSetng[i].m;
627 if( (srchFlags & m)==0 ) continue;
@@ -841,10 +845,11 @@
841 static const struct { unsigned m; char c; } aMask[] = {
842 { SRCH_CKIN, 'c' },
843 { SRCH_DOC, 'd' },
844 { SRCH_TKT, 't' },
845 { SRCH_WIKI, 'w' },
 
846 };
847 int i;
848 for(i=0; i<ArraySize(aMask); i++){
849 if( srchFlags & aMask[i].m ){
850 blob_appendf(&sql, "%sftsdocs.type='%c'", zSep, aMask[i].c);
@@ -988,10 +993,11 @@
988 switch( srchFlags ){
989 case SRCH_CKIN: zType = " Check-ins"; zClass = "Ckin"; break;
990 case SRCH_DOC: zType = " Docs"; zClass = "Doc"; break;
991 case SRCH_TKT: zType = " Tickets"; zClass = "Tkt"; break;
992 case SRCH_WIKI: zType = " Wiki"; zClass = "Wiki"; break;
 
993 }
994 if( srchFlags==0 ){
995 zDisable1 = " disabled";
996 zDisable2 = " disabled";
997 zPattern = "";
@@ -1012,10 +1018,11 @@
1012 { "all", "All", SRCH_ALL },
1013 { "c", "Check-ins", SRCH_CKIN },
1014 { "d", "Docs", SRCH_DOC },
1015 { "t", "Tickets", SRCH_TKT },
1016 { "w", "Wiki", SRCH_WIKI },
 
1017 };
1018 const char *zY = PD("y","all");
1019 unsigned newFlags = srchFlags;
1020 int i;
1021 @ <select size='1' name='y'>
@@ -1063,10 +1070,11 @@
1063 ** y=TYPE What to search.
1064 ** c -> check-ins
1065 ** d -> documentation
1066 ** t -> tickets
1067 ** w -> wiki
 
1068 ** all -> everything
1069 */
1070 void search_page(void){
1071 login_check_credentials();
1072 style_header("Search");
@@ -1169,10 +1177,11 @@
1169 **
1170 ** cType: d Embedded documentation
1171 ** w Wiki page
1172 ** c Check-in comment
1173 ** t Ticket text
 
1174 **
1175 ** rid The RID of an artifact that defines the object
1176 ** being searched.
1177 **
1178 ** zName Name of the object being searched.
@@ -1182,10 +1191,11 @@
1182 int rid, /* BLOB.RID or TAG.TAGID value for document */
1183 const char *zName, /* Auxiliary information */
1184 Blob *pOut /* OUT: Initialize to the search text */
1185 ){
1186 blob_init(pOut, 0, 0);
 
1187 switch( cType ){
1188 case 'd': { /* Documents */
1189 Blob doc;
1190 content_get(rid, &doc);
1191 blob_to_utf8_no_bom(&doc, 0);
@@ -1201,10 +1211,14 @@
1201 get_stext_by_mimetype(&wiki, wiki_filter_mimetypes(pWiki->zMimetype),
1202 pOut);
1203 blob_reset(&wiki);
1204 manifest_destroy(pWiki);
1205 break;
 
 
 
 
1206 }
1207 case 'c': { /* Check-in Comments */
1208 static Stmt q;
1209 static int isPlainText = -1;
1210 db_static_prepare(&q,
@@ -1411,10 +1425,14 @@
1411 search_sql_setup(g.db);
1412 db_multi_exec(
1413 "INSERT OR IGNORE INTO ftsdocs(type,rid,idxed)"
1414 " SELECT 'c', objid, 0 FROM event WHERE type='ci';"
1415 );
 
 
 
 
1416 db_multi_exec(
1417 "WITH latest_wiki(rid,name,mtime) AS ("
1418 " SELECT tagxref.rid, substr(tag.tagname,6), max(tagxref.mtime)"
1419 " FROM tag, tagxref"
1420 " WHERE tag.tagname GLOB 'wiki-*'"
@@ -1545,10 +1563,32 @@
1545 " WHERE ftsdocs.type='c' AND NOT ftsdocs.idxed"
1546 " AND event.objid=ftsdocs.rid"
1547 " AND blob.rid=ftsdocs.rid"
1548 );
1549 }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1550
1551 /*
1552 ** Deal with all of the unindexed 't' terms in FTSDOCS
1553 */
1554 static void search_update_ticket_index(void){
@@ -1604,10 +1644,13 @@
1604 search_sql_setup(g.db);
1605 if( srchFlags & (SRCH_CKIN|SRCH_DOC) ){
1606 search_update_doc_index();
1607 search_update_checkin_index();
1608 }
 
 
 
1609 if( srchFlags & SRCH_TKT ){
1610 search_update_ticket_index();
1611 }
1612 if( srchFlags & SRCH_WIKI ){
1613 search_update_wiki_index();
@@ -1637,14 +1680,14 @@
1637 ** reindex Rebuild the search index. This is a no-op if
1638 ** index search is disabled
1639 **
1640 ** index (on|off) Turn the search index on or off
1641 **
1642 ** enable cdtw Enable various kinds of search. c=Check-ins,
1643 ** d=Documents, t=Tickets, w=Wiki.
1644 **
1645 ** disable cdtw Disable various kinds of search
1646 **
1647 ** stemmer (on|off) Turn the Porter stemmer on or off for indexed
1648 ** search. (Unindexed search is never stemmed.)
1649 **
1650 ** The current search settings are displayed after any changes are applied.
@@ -1657,14 +1700,15 @@
1657 { 3, "disable" },
1658 { 4, "enable" },
1659 { 5, "stemmer" },
1660 };
1661 static const struct { char *zSetting; char *zName; char *zSw; } aSetng[] = {
1662 { "search-ckin", "check-in search:", "c" },
1663 { "search-doc", "document search:", "d" },
1664 { "search-tkt", "ticket search:", "t" },
1665 { "search-wiki", "wiki search:", "w" },
 
1666 };
1667 char *zSubCmd = 0;
1668 int i, j, n;
1669 int iCmd = 0;
1670 int iAction = 0;
@@ -1683,10 +1727,12 @@
1683 zSubCmd, blob_str(&all));
1684 return;
1685 }
1686 iCmd = aCmd[i].iCmd;
1687 }
 
 
1688 if( iCmd==1 ){
1689 if( search_index_exists() ) iAction = 2;
1690 }
1691 if( iCmd==2 ){
1692 if( g.argc<3 ) usage("index (on|off)");
@@ -1719,19 +1765,19 @@
1719 search_rebuild_index();
1720 }
1721
1722 /* Always show the status before ending */
1723 for(i=0; i<ArraySize(aSetng); i++){
1724 fossil_print("%-16s %s\n", aSetng[i].zName,
1725 db_get_boolean(aSetng[i].zSetting,0) ? "on" : "off");
1726 }
1727 fossil_print("%-16s %s\n", "Porter stemmer:",
1728 db_get_boolean("search-stemmer",0) ? "on" : "off");
1729 if( search_index_exists() ){
1730 fossil_print("%-16s enabled\n", "full-text index:");
1731 fossil_print("%-16s %d\n", "documents:",
1732 db_int(0, "SELECT count(*) FROM ftsdocs"));
1733 }else{
1734 fossil_print("%-16s disabled\n", "full-text index:");
1735 }
1736 db_end_transaction(0);
1737 }
1738
--- src/search.c
+++ src/search.c
@@ -510,10 +510,12 @@
510 search_title_sqlfunc, 0, 0);
511 sqlite3_create_function(db, "body", 3, SQLITE_UTF8, 0,
512 search_body_sqlfunc, 0, 0);
513 sqlite3_create_function(db, "urlencode", 1, SQLITE_UTF8, 0,
514 search_urlencode_sqlfunc, 0, 0);
515 sqlite3_create_function(db, "diff", 1, SQLITE_UTF8, 0,
516 diff_sqlfunc, 0, 0);
517 }
518
519 /*
520 ** Testing the search function.
521 **
@@ -600,11 +602,12 @@
602 /* What to search for */
603 #define SRCH_CKIN 0x0001 /* Search over check-in comments */
604 #define SRCH_DOC 0x0002 /* Search over embedded documents */
605 #define SRCH_TKT 0x0004 /* Search over tickets */
606 #define SRCH_WIKI 0x0008 /* Search over wiki */
607 #define SRCH_DIFF 0x0010 /* Search check-in diffs */
608 #define SRCH_ALL 0x001f /* Search over everything */
609 #endif
610
611 /*
612 ** Remove bits from srchFlags which are disallowed by either the
613 ** current server configuration or by user permissions.
@@ -615,13 +618,14 @@
618 static const struct { unsigned m; const char *zKey; } aSetng[] = {
619 { SRCH_CKIN, "search-ci" },
620 { SRCH_DOC, "search-doc" },
621 { SRCH_TKT, "search-tkt" },
622 { SRCH_WIKI, "search-wiki" },
623 { SRCH_DIFF, "search-diff" },
624 };
625 int i;
626 if( g.perm.Read==0 ) srchFlags &= ~(SRCH_CKIN|SRCH_DOC|SRCH_DIFF);
627 if( g.perm.RdTkt==0 ) srchFlags &= ~(SRCH_TKT);
628 if( g.perm.RdWiki==0 ) srchFlags &= ~(SRCH_WIKI);
629 for(i=0; i<ArraySize(aSetng); i++){
630 unsigned int m = aSetng[i].m;
631 if( (srchFlags & m)==0 ) continue;
@@ -841,10 +845,11 @@
845 static const struct { unsigned m; char c; } aMask[] = {
846 { SRCH_CKIN, 'c' },
847 { SRCH_DOC, 'd' },
848 { SRCH_TKT, 't' },
849 { SRCH_WIKI, 'w' },
850 { SRCH_DIFF, 'x' },
851 };
852 int i;
853 for(i=0; i<ArraySize(aMask); i++){
854 if( srchFlags & aMask[i].m ){
855 blob_appendf(&sql, "%sftsdocs.type='%c'", zSep, aMask[i].c);
@@ -988,10 +993,11 @@
993 switch( srchFlags ){
994 case SRCH_CKIN: zType = " Check-ins"; zClass = "Ckin"; break;
995 case SRCH_DOC: zType = " Docs"; zClass = "Doc"; break;
996 case SRCH_TKT: zType = " Tickets"; zClass = "Tkt"; break;
997 case SRCH_WIKI: zType = " Wiki"; zClass = "Wiki"; break;
998 case SRCH_DIFF: zType = " Diffs"; zClass = "Diff"; break;
999 }
1000 if( srchFlags==0 ){
1001 zDisable1 = " disabled";
1002 zDisable2 = " disabled";
1003 zPattern = "";
@@ -1012,10 +1018,11 @@
1018 { "all", "All", SRCH_ALL },
1019 { "c", "Check-ins", SRCH_CKIN },
1020 { "d", "Docs", SRCH_DOC },
1021 { "t", "Tickets", SRCH_TKT },
1022 { "w", "Wiki", SRCH_WIKI },
1023 { "z", "Diff", SRCH_DIFF },
1024 };
1025 const char *zY = PD("y","all");
1026 unsigned newFlags = srchFlags;
1027 int i;
1028 @ <select size='1' name='y'>
@@ -1063,10 +1070,11 @@
1070 ** y=TYPE What to search.
1071 ** c -> check-ins
1072 ** d -> documentation
1073 ** t -> tickets
1074 ** w -> wiki
1075 ** x -> diff
1076 ** all -> everything
1077 */
1078 void search_page(void){
1079 login_check_credentials();
1080 style_header("Search");
@@ -1169,10 +1177,11 @@
1177 **
1178 ** cType: d Embedded documentation
1179 ** w Wiki page
1180 ** c Check-in comment
1181 ** t Ticket text
1182 ** x Check-in diffs
1183 **
1184 ** rid The RID of an artifact that defines the object
1185 ** being searched.
1186 **
1187 ** zName Name of the object being searched.
@@ -1182,10 +1191,11 @@
1191 int rid, /* BLOB.RID or TAG.TAGID value for document */
1192 const char *zName, /* Auxiliary information */
1193 Blob *pOut /* OUT: Initialize to the search text */
1194 ){
1195 blob_init(pOut, 0, 0);
1196 /* printf("stext(%c%d)\n", cType, rid); fflush(stdout); */
1197 switch( cType ){
1198 case 'd': { /* Documents */
1199 Blob doc;
1200 content_get(rid, &doc);
1201 blob_to_utf8_no_bom(&doc, 0);
@@ -1201,10 +1211,14 @@
1211 get_stext_by_mimetype(&wiki, wiki_filter_mimetypes(pWiki->zMimetype),
1212 pOut);
1213 blob_reset(&wiki);
1214 manifest_destroy(pWiki);
1215 break;
1216 }
1217 case 'x': { /* Check-in diff */
1218 diff_for_search(rid, pOut);
1219 break;
1220 }
1221 case 'c': { /* Check-in Comments */
1222 static Stmt q;
1223 static int isPlainText = -1;
1224 db_static_prepare(&q,
@@ -1411,10 +1425,14 @@
1425 search_sql_setup(g.db);
1426 db_multi_exec(
1427 "INSERT OR IGNORE INTO ftsdocs(type,rid,idxed)"
1428 " SELECT 'c', objid, 0 FROM event WHERE type='ci';"
1429 );
1430 db_multi_exec(
1431 "INSERT OR IGNORE INTO ftsdocs(type,rid,idxed)"
1432 " SELECT 'x', objid, 0 FROM event WHERE type='ci';"
1433 );
1434 db_multi_exec(
1435 "WITH latest_wiki(rid,name,mtime) AS ("
1436 " SELECT tagxref.rid, substr(tag.tagname,6), max(tagxref.mtime)"
1437 " FROM tag, tagxref"
1438 " WHERE tag.tagname GLOB 'wiki-*'"
@@ -1545,10 +1563,32 @@
1563 " WHERE ftsdocs.type='c' AND NOT ftsdocs.idxed"
1564 " AND event.objid=ftsdocs.rid"
1565 " AND blob.rid=ftsdocs.rid"
1566 );
1567 }
1568
1569 /*
1570 ** Deal with all of the unindexed 'x' terms in FTSDOCS
1571 */
1572 static void search_update_diff_index(void){
1573 db_multi_exec(
1574 "INSERT INTO ftsidx(docid,title,body)"
1575 " SELECT rowid, '', body('x',rid,NULL) FROM ftsdocs"
1576 " WHERE type='x' AND NOT idxed;"
1577 );
1578 db_multi_exec(
1579 "REPLACE INTO ftsdocs(rowid,idxed,type,rid,name,label,url,mtime)"
1580 " SELECT ftsdocs.rowid, 1, 'x', ftsdocs.rid, NULL,"
1581 " printf('Check-in [%%.16s] on %%s',blob.uuid,datetime(event.mtime)),"
1582 " printf('/info/%%.20s',blob.uuid),"
1583 " event.mtime"
1584 " FROM ftsdocs, event, blob"
1585 " WHERE ftsdocs.type='x' AND NOT ftsdocs.idxed"
1586 " AND event.objid=ftsdocs.rid"
1587 " AND blob.rid=ftsdocs.rid"
1588 );
1589 }
1590
1591 /*
1592 ** Deal with all of the unindexed 't' terms in FTSDOCS
1593 */
1594 static void search_update_ticket_index(void){
@@ -1604,10 +1644,13 @@
1644 search_sql_setup(g.db);
1645 if( srchFlags & (SRCH_CKIN|SRCH_DOC) ){
1646 search_update_doc_index();
1647 search_update_checkin_index();
1648 }
1649 if( srchFlags & SRCH_DIFF ){
1650 search_update_diff_index();
1651 }
1652 if( srchFlags & SRCH_TKT ){
1653 search_update_ticket_index();
1654 }
1655 if( srchFlags & SRCH_WIKI ){
1656 search_update_wiki_index();
@@ -1637,14 +1680,14 @@
1680 ** reindex Rebuild the search index. This is a no-op if
1681 ** index search is disabled
1682 **
1683 ** index (on|off) Turn the search index on or off
1684 **
1685 ** enable cdtwx Enable various kinds of search. c=Check-ins,
1686 ** d=Documents, t=Tickets, w=Wiki, x=Diffs.
1687 **
1688 ** disable cdtwx Disable various kinds of search
1689 **
1690 ** stemmer (on|off) Turn the Porter stemmer on or off for indexed
1691 ** search. (Unindexed search is never stemmed.)
1692 **
1693 ** The current search settings are displayed after any changes are applied.
@@ -1657,14 +1700,15 @@
1700 { 3, "disable" },
1701 { 4, "enable" },
1702 { 5, "stemmer" },
1703 };
1704 static const struct { char *zSetting; char *zName; char *zSw; } aSetng[] = {
1705 { "search-ckin", "check-in comment search:", "c" },
1706 { "search-diff", "check-in diff search:", "x" },
1707 { "search-doc", "document search:", "d" },
1708 { "search-tkt", "ticket search:", "t" },
1709 { "search-wiki", "wiki search:", "w" },
1710 };
1711 char *zSubCmd = 0;
1712 int i, j, n;
1713 int iCmd = 0;
1714 int iAction = 0;
@@ -1683,10 +1727,12 @@
1727 zSubCmd, blob_str(&all));
1728 return;
1729 }
1730 iCmd = aCmd[i].iCmd;
1731 }
1732 login_set_capabilities("s",0);
1733 g.zTop = "";
1734 if( iCmd==1 ){
1735 if( search_index_exists() ) iAction = 2;
1736 }
1737 if( iCmd==2 ){
1738 if( g.argc<3 ) usage("index (on|off)");
@@ -1719,19 +1765,19 @@
1765 search_rebuild_index();
1766 }
1767
1768 /* Always show the status before ending */
1769 for(i=0; i<ArraySize(aSetng); i++){
1770 fossil_print("%-25s %s\n", aSetng[i].zName,
1771 db_get_boolean(aSetng[i].zSetting,0) ? "on" : "off");
1772 }
1773 fossil_print("%-25s %s\n", "Porter stemmer:",
1774 db_get_boolean("search-stemmer",0) ? "on" : "off");
1775 if( search_index_exists() ){
1776 fossil_print("%-25s enabled\n", "full-text index:");
1777 fossil_print("%-25s %d\n", "documents:",
1778 db_int(0, "SELECT count(*) FROM ftsdocs"));
1779 }else{
1780 fossil_print("%-25s disabled\n", "full-text index:");
1781 }
1782 db_end_transaction(0);
1783 }
1784
--- src/setup.c
+++ src/setup.c
@@ -2155,10 +2155,12 @@
21552155
@ <p>When searching documents, use the versions of the files found at the
21562156
@ type of the "Document Branch" branch. Recommended value: "trunk".
21572157
@ Document search is disabled if blank.
21582158
@ <hr />
21592159
onoff_attribute("Search Check-in Comments", "search-ci", "sc", 0, 0);
2160
+ @ <br />
2161
+ onoff_attribute("Search Check-in Diffs","search-diff", "sx", 0, 0);
21602162
@ <br />
21612163
onoff_attribute("Search Documents", "search-doc", "sd", 0, 0);
21622164
@ <br />
21632165
onoff_attribute("Search Tickets", "search-tkt", "st", 0, 0);
21642166
@ <br />
21652167
--- src/setup.c
+++ src/setup.c
@@ -2155,10 +2155,12 @@
2155 @ <p>When searching documents, use the versions of the files found at the
2156 @ type of the "Document Branch" branch. Recommended value: "trunk".
2157 @ Document search is disabled if blank.
2158 @ <hr />
2159 onoff_attribute("Search Check-in Comments", "search-ci", "sc", 0, 0);
 
 
2160 @ <br />
2161 onoff_attribute("Search Documents", "search-doc", "sd", 0, 0);
2162 @ <br />
2163 onoff_attribute("Search Tickets", "search-tkt", "st", 0, 0);
2164 @ <br />
2165
--- src/setup.c
+++ src/setup.c
@@ -2155,10 +2155,12 @@
2155 @ <p>When searching documents, use the versions of the files found at the
2156 @ type of the "Document Branch" branch. Recommended value: "trunk".
2157 @ Document search is disabled if blank.
2158 @ <hr />
2159 onoff_attribute("Search Check-in Comments", "search-ci", "sc", 0, 0);
2160 @ <br />
2161 onoff_attribute("Search Check-in Diffs","search-diff", "sx", 0, 0);
2162 @ <br />
2163 onoff_attribute("Search Documents", "search-doc", "sd", 0, 0);
2164 @ <br />
2165 onoff_attribute("Search Tickets", "search-tkt", "st", 0, 0);
2166 @ <br />
2167

Keyboard Shortcuts

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