Fossil SCM

Add the ability to search the built-in help text. Improvements to the "fossil search" command, including colorization of matching terms in the output. Improvements to the "fossil fts-config" interface.

drh 2025-02-26 16:57 trunk merge
Commit 6d9f0f5f308d94938b9620f5d3f3ae93b347fe617df658afb6f656896ee40d67
+9 -5
--- src/dispatch.c
+++ src/dispatch.c
@@ -832,10 +832,13 @@
832832
833833
style_set_current_feature("tkt");
834834
style_header("Help: %s", zCmd);
835835
836836
style_submenu_element("Command-List", "%R/help");
837
+ if( search_restrict(SRCH_HELP,0)!=0 ){
838
+ style_submenu_element("Search","%R/search?y=h");
839
+ }
837840
rc = dispatch_name_search(zCmd, CMDFLAG_ANY|CMDFLAG_PREFIX, &pCmd);
838841
if( *zCmd=='/' ){
839842
/* Some of the webpages require query parameters in order to work.
840843
** @ <h1>The "<a href='%R%s(zCmd)'>%s(zCmd)</a>" page:</h1> */
841844
@ <h1>The "%h(zCmd)" page:</h1>
@@ -873,10 +876,11 @@
873876
int i;
874877
const char *zWidth = "28ex";
875878
unsigned char occHelp[FOSSIL_MX_CMDIDX] = {0}; /* Help str occurrences */
876879
int bktHelp[FOSSIL_MX_CMDIDX][MX_HELP_DUP] = {{0}};/* Help str->commands */
877880
style_header("Help");
881
+ search_screen(SRCH_HELP, 0x02);
878882
879883
@ <a name='commands'></a>
880884
@ <h1>Available commands:</h1>
881885
@ <div class="columns" style="column-width: %s(zWidth);">
882886
@ <ul>
@@ -1270,15 +1274,15 @@
12701274
n = dispatch_approx_match(g.argv[2], 5, az);
12711275
for(i=0; i<n; i++){
12721276
fossil_print(" * %s\n", az[i]);
12731277
}
12741278
fossil_print("Also consider using:\n");
1275
- fossil_print(" fossil help TOPIC ;# show help on TOPIC\n");
1276
- fossil_print(" fossil help -a ;# show all commands\n");
1277
- fossil_print(" fossil help -w ;# show all web-pages\n");
1278
- fossil_print(" fossil help -s ;# show all settings\n");
1279
- fossil_print(" fossil help -o ;# show global options\n");
1279
+ fossil_print(" fossil search -h PATTERN ;# search all help text\n");
1280
+ fossil_print(" fossil help -a ;# show all commands\n");
1281
+ fossil_print(" fossil help -w ;# show all web-pages\n");
1282
+ fossil_print(" fossil help -s ;# show all settings\n");
1283
+ fossil_print(" fossil help -o ;# show global options\n");
12801284
fossil_exit(1);
12811285
}
12821286
z = pCmd->zHelp;
12831287
if( z==0 ){
12841288
fossil_fatal("no help available for the %s %s",
12851289
--- src/dispatch.c
+++ src/dispatch.c
@@ -832,10 +832,13 @@
832
833 style_set_current_feature("tkt");
834 style_header("Help: %s", zCmd);
835
836 style_submenu_element("Command-List", "%R/help");
 
 
 
837 rc = dispatch_name_search(zCmd, CMDFLAG_ANY|CMDFLAG_PREFIX, &pCmd);
838 if( *zCmd=='/' ){
839 /* Some of the webpages require query parameters in order to work.
840 ** @ <h1>The "<a href='%R%s(zCmd)'>%s(zCmd)</a>" page:</h1> */
841 @ <h1>The "%h(zCmd)" page:</h1>
@@ -873,10 +876,11 @@
873 int i;
874 const char *zWidth = "28ex";
875 unsigned char occHelp[FOSSIL_MX_CMDIDX] = {0}; /* Help str occurrences */
876 int bktHelp[FOSSIL_MX_CMDIDX][MX_HELP_DUP] = {{0}};/* Help str->commands */
877 style_header("Help");
 
878
879 @ <a name='commands'></a>
880 @ <h1>Available commands:</h1>
881 @ <div class="columns" style="column-width: %s(zWidth);">
882 @ <ul>
@@ -1270,15 +1274,15 @@
1270 n = dispatch_approx_match(g.argv[2], 5, az);
1271 for(i=0; i<n; i++){
1272 fossil_print(" * %s\n", az[i]);
1273 }
1274 fossil_print("Also consider using:\n");
1275 fossil_print(" fossil help TOPIC ;# show help on TOPIC\n");
1276 fossil_print(" fossil help -a ;# show all commands\n");
1277 fossil_print(" fossil help -w ;# show all web-pages\n");
1278 fossil_print(" fossil help -s ;# show all settings\n");
1279 fossil_print(" fossil help -o ;# show global options\n");
1280 fossil_exit(1);
1281 }
1282 z = pCmd->zHelp;
1283 if( z==0 ){
1284 fossil_fatal("no help available for the %s %s",
1285
--- src/dispatch.c
+++ src/dispatch.c
@@ -832,10 +832,13 @@
832
833 style_set_current_feature("tkt");
834 style_header("Help: %s", zCmd);
835
836 style_submenu_element("Command-List", "%R/help");
837 if( search_restrict(SRCH_HELP,0)!=0 ){
838 style_submenu_element("Search","%R/search?y=h");
839 }
840 rc = dispatch_name_search(zCmd, CMDFLAG_ANY|CMDFLAG_PREFIX, &pCmd);
841 if( *zCmd=='/' ){
842 /* Some of the webpages require query parameters in order to work.
843 ** @ <h1>The "<a href='%R%s(zCmd)'>%s(zCmd)</a>" page:</h1> */
844 @ <h1>The "%h(zCmd)" page:</h1>
@@ -873,10 +876,11 @@
876 int i;
877 const char *zWidth = "28ex";
878 unsigned char occHelp[FOSSIL_MX_CMDIDX] = {0}; /* Help str occurrences */
879 int bktHelp[FOSSIL_MX_CMDIDX][MX_HELP_DUP] = {{0}};/* Help str->commands */
880 style_header("Help");
881 search_screen(SRCH_HELP, 0x02);
882
883 @ <a name='commands'></a>
884 @ <h1>Available commands:</h1>
885 @ <div class="columns" style="column-width: %s(zWidth);">
886 @ <ul>
@@ -1270,15 +1274,15 @@
1274 n = dispatch_approx_match(g.argv[2], 5, az);
1275 for(i=0; i<n; i++){
1276 fossil_print(" * %s\n", az[i]);
1277 }
1278 fossil_print("Also consider using:\n");
1279 fossil_print(" fossil search -h PATTERN ;# search all help text\n");
1280 fossil_print(" fossil help -a ;# show all commands\n");
1281 fossil_print(" fossil help -w ;# show all web-pages\n");
1282 fossil_print(" fossil help -s ;# show all settings\n");
1283 fossil_print(" fossil help -o ;# show global options\n");
1284 fossil_exit(1);
1285 }
1286 z = pCmd->zHelp;
1287 if( z==0 ){
1288 fossil_fatal("no help available for the %s %s",
1289
+1 -1
--- src/forum.c
+++ src/forum.c
@@ -1927,11 +1927,11 @@
19271927
int srchFlags;
19281928
const int isSearch = P("s")!=0;
19291929
char const *zLimit = 0;
19301930
19311931
login_check_credentials();
1932
- srchFlags = search_restrict(SRCH_FORUM);
1932
+ srchFlags = search_restrict(SRCH_FORUM,0);
19331933
if( !g.perm.RdForum ){
19341934
login_needed(g.anon.RdForum);
19351935
return;
19361936
}
19371937
cgi_check_for_malice();
19381938
--- src/forum.c
+++ src/forum.c
@@ -1927,11 +1927,11 @@
1927 int srchFlags;
1928 const int isSearch = P("s")!=0;
1929 char const *zLimit = 0;
1930
1931 login_check_credentials();
1932 srchFlags = search_restrict(SRCH_FORUM);
1933 if( !g.perm.RdForum ){
1934 login_needed(g.anon.RdForum);
1935 return;
1936 }
1937 cgi_check_for_malice();
1938
--- src/forum.c
+++ src/forum.c
@@ -1927,11 +1927,11 @@
1927 int srchFlags;
1928 const int isSearch = P("s")!=0;
1929 char const *zLimit = 0;
1930
1931 login_check_credentials();
1932 srchFlags = search_restrict(SRCH_FORUM,0);
1933 if( !g.perm.RdForum ){
1934 login_needed(g.anon.RdForum);
1935 return;
1936 }
1937 cgi_check_for_malice();
1938
+255 -80
--- src/search.c
+++ src/search.c
@@ -558,96 +558,216 @@
558558
sqlite3_create_function(db, "body", 3, enc, 0,
559559
search_body_sqlfunc, 0, 0);
560560
sqlite3_create_function(db, "urlencode", 1, enc, 0,
561561
search_urlencode_sqlfunc, 0, 0);
562562
}
563
+
564
+/*
565
+** The pSnip input contains snippet text from a search formatted
566
+** as HTML. Attempt to make that text more readable on a TTY.
567
+**
568
+** If nTty is positive, use ANSI escape codes "\e[Nm" where N is nTty
569
+** to highly marked text.
570
+*/
571
+void search_snippet_to_plaintext(Blob *pSnip, int nTty){
572
+ char *zSnip;
573
+ unsigned int j, k;
574
+
575
+ zSnip = pSnip->aData;
576
+ for(j=k=0; j<pSnip->nUsed; j++){
577
+ char c = zSnip[j];
578
+ if( c=='<' ){
579
+ if( memcmp(&zSnip[j],"<mark>",6)==0 ){
580
+ if( nTty ){
581
+ zSnip[k++] = 0x1b;
582
+ zSnip[k++] = '[';
583
+ if( nTty>=10 ) zSnip[k++] = (nTty/10)%10 + '0';
584
+ zSnip[k++] = nTty%10 + '0';
585
+ zSnip[k++] = 'm';
586
+ }
587
+ j += 5;
588
+ }else if( memcmp(&zSnip[j],"</mark>",7)==0 ){
589
+ if( nTty ){
590
+ zSnip[k++] = 0x1b;
591
+ zSnip[k++] = '[';
592
+ zSnip[k++] = '0';
593
+ zSnip[k++] = 'm';
594
+ }
595
+ j += 6;
596
+ }else{
597
+ zSnip[k++] = zSnip[j];
598
+ }
599
+ }else if( fossil_isspace(c) ){
600
+ zSnip[k++] = ' ';
601
+ while( fossil_isspace(zSnip[j+1]) ) j++;
602
+ }else if( c=='&' ){
603
+ if( zSnip[j+1]=='#' && fossil_isdigit(zSnip[j+2]) ){
604
+ int n = 3;
605
+ int x = zSnip[j+2] - '0';
606
+ if( fossil_isdigit(zSnip[j+3]) ){
607
+ x = x*10 + zSnip[j+3] - '0';
608
+ n++;
609
+ if( fossil_isdigit(zSnip[j+4]) ){
610
+ x = x*10 + zSnip[j+4] - '0';
611
+ n++;
612
+ }
613
+ }
614
+ if( zSnip[j+n]==';' ){
615
+ zSnip[k++] = (char)x;
616
+ j += n;
617
+ }else{
618
+ zSnip[k++] = c;
619
+ }
620
+ }else if( memcmp(&zSnip[j],"&lt;",4)==0 ){
621
+ zSnip[k++] = '<';
622
+ j += 3;
623
+ }else if( memcmp(&zSnip[j],"&gt;",4)==0 ){
624
+ zSnip[k++] = '>';
625
+ j += 3;
626
+ }else if( memcmp(&zSnip[j],"&quot;",6)==0 ){
627
+ zSnip[k++] = '<';
628
+ j += 5;
629
+ }else if( memcmp(&zSnip[j],"&amp;",5)==0 ){
630
+ zSnip[k++] = '<';
631
+ j += 4;
632
+ }else{
633
+ zSnip[k++] = c;
634
+ }
635
+ }else{
636
+ zSnip[k++] = c;
637
+ }
638
+ }
639
+ zSnip[k] = 0;
640
+ pSnip->nUsed = k;
641
+}
563642
564643
/*
565644
** Testing the search function.
566645
**
567646
** COMMAND: search*
568647
**
569
-** Usage: %fossil search [-a|-all] [-n|-limit #] [-W|-width #] pattern...
570
-**
571
-** Search for timeline entries matching all words provided on the
572
-** command line. Whole-word matches scope more highly than partial
573
-** matches.
574
-**
575
-** Note: This command only searches the EVENT table. So it will only
576
-** display check-in comments or other comments that appear on an
577
-** unaugmented timeline. It does not search document text or forum
578
-** messages.
579
-**
580
-** Outputs, by default, some top-N fraction of the results. The -all
581
-** option can be used to output all matches, regardless of their search
582
-** score. The -limit option can be used to limit the number of entries
583
-** returned. The -width option can be used to set the output width used
584
-** when printing matches.
648
+** Usage: %fossil search [OPTIONS] PATTERN...
649
+**
650
+** Search the repository database for PATTERN and show matches.
651
+** The following elements of the repository can be searched:
652
+**
653
+** * check-in comments
654
+** * embedded documentation
655
+** * forum posts
656
+** * tickets
657
+** * tech notes
658
+** * wiki pages
659
+** * built-in fossil help text
660
+**
661
+** Use options (listed below) to select the scope of the search. The
662
+** default is check-in comments only.
585663
**
586664
** Options:
587
-** -a|--all Output all matches, not just best matches
588
-** --debug Show additional debug content on --fts search
589
-** --fts Use the full-text search mechanism (testing only)
665
+** -a|--all Search everything
666
+** -c|--checkins Search checkin comments
667
+** --docs Search embedded documentation
668
+** --forum Search forum posts
669
+** -h|--bi-help Search built-in help
590670
** -n|--limit N Limit output to N matches
591
-** --scope SCOPE Scope of search. Valid for --fts only. One or
592
-** more of: all, c, d, e, f, t, w. Defaults to all.
671
+** --technotes Search tech notes
672
+** --tickets Search tickets
593673
** -W|--width WIDTH Set display width to WIDTH columns, 0 for
594
-** unlimited. Defaults the terminal's width.
674
+** unlimited. Defaults to the terminal's width.
675
+** --wiki Search wiki
595676
*/
596677
void search_cmd(void){
597678
Blob pattern;
598679
int i;
599680
Blob sql = empty_blob;
600681
Stmt q;
601682
int iBest;
683
+ int srchFlags = 0;
684
+ int bFts = 1; /* Use FTS search by default now */
602685
char fAll = NULL != find_option("all", "a", 0);
603686
const char *zLimit = find_option("limit","n",1);
687
+ const char *zScope = 0;
604688
const char *zWidth = find_option("width","W",1);
605
- const char *zScope = find_option("scope",0,1);
606
- int bDebug = find_option("debug",0,0)!=0;
689
+ int bDebug = find_option("debug",0,0)!=0; /* Undocumented */
607690
int nLimit = zLimit ? atoi(zLimit) : -1000;
608691
int width;
609
- int bFts = find_option("fts",0,0)!=0;
692
+ int nTty = fossil_isatty(1) ? 91 : 0;
693
+
694
+ /* Undocumented option to change highlight color */
695
+ const char *zHighlight = find_option("highlight",0,1);
696
+ if( zHighlight ) nTty = atoi(zHighlight);
697
+
698
+ /* Undocumented option (legacy) */
699
+ zScope = find_option("scope",0,1);
700
+
701
+ if( find_option("fts",0,0)!=0 ) bFts = 1; /* Undocumented legacy */
702
+ if( find_option("legacy",0,0)!=0 ) bFts = 0; /* Undocumented */
610703
611704
if( zWidth ){
612705
width = atoi(zWidth);
613706
if( (width!=0) && (width<=20) ){
614707
fossil_fatal("-W|--width value must be >20 or 0");
615708
}
616709
}else{
617710
width = -1;
618711
}
712
+ if( zScope ){
713
+ for(i=0; zScope[i]; i++){
714
+ switch( zScope[i] ){
715
+ case 'a': srchFlags = SRCH_ALL; break;
716
+ case 'c': srchFlags |= SRCH_CKIN; break;
717
+ case 'd': srchFlags |= SRCH_DOC; break;
718
+ case 'e': srchFlags |= SRCH_TECHNOTE; break;
719
+ case 'f': srchFlags |= SRCH_FORUM; break;
720
+ case 'h': srchFlags |= SRCH_HELP; break;
721
+ case 't': srchFlags |= SRCH_TKT; break;
722
+ case 'w': srchFlags |= SRCH_WIKI; break;
723
+ }
724
+ }
725
+ bFts = 1;
726
+ }
727
+ if( find_option("all","a",0) ){ srchFlags |= SRCH_ALL; bFts = 1; }
728
+ if( find_option("bi-help","h",0) ){ srchFlags |= SRCH_HELP; bFts = 1; }
729
+ if( find_option("checkins","c",0) ){ srchFlags |= SRCH_CKIN; bFts = 1; }
730
+ if( find_option("docs",0,0) ){ srchFlags |= SRCH_DOC; bFts = 1; }
731
+ if( find_option("forum",0,0) ){ srchFlags |= SRCH_FORUM; bFts = 1; }
732
+ if( find_option("technotes",0,0) ){ srchFlags |= SRCH_TECHNOTE; bFts = 1; }
733
+ if( find_option("tickets",0,0) ){ srchFlags |= SRCH_TKT; bFts = 1; }
734
+ if( find_option("wiki",0,0) ){ srchFlags |= SRCH_WIKI; bFts = 1; }
735
+
736
+ /* If no search objects are specified, default to "check-in comments" */
737
+ if( srchFlags==0 ) srchFlags = SRCH_CKIN;
738
+
619739
620740
db_find_and_open_repository(0, 0);
741
+ verify_all_options();
621742
if( g.argc<3 ) return;
743
+ login_set_capabilities("s", 0);
744
+ if( search_restrict(srchFlags, 1)==0 ){
745
+ const char *zC1 = 0, *zPlural = "s";
746
+ if( srchFlags & SRCH_TECHNOTE ){ zC1 = "technote"; }
747
+ if( srchFlags & SRCH_TKT ){ zC1 = "ticket"; }
748
+ if( srchFlags & SRCH_FORUM ){ zC1 = "forum"; zPlural = ""; }
749
+ if( srchFlags & SRCH_DOC ){ zC1 = "document"; }
750
+ if( srchFlags & SRCH_WIKI ){ zC1 = "wiki"; zPlural = ""; }
751
+ if( srchFlags & SRCH_CKIN ){ zC1 = "check-in"; }
752
+ fossil_print(
753
+ "Search of %s%s is disabled on this repository.\n"
754
+ "Enable using \"fossil fts-config enable %s\".\n",
755
+ zC1, zPlural, zC1
756
+ );
757
+ return;
758
+ }
759
+
622760
blob_init(&pattern, g.argv[2], -1);
623761
for(i=3; i<g.argc; i++){
624762
blob_appendf(&pattern, " %s", g.argv[i]);
625763
}
626764
if( bFts ){
627765
/* Search using FTS */
628766
Blob com;
629767
Blob snip;
630768
const char *zPattern = blob_str(&pattern);
631
- int srchFlags;
632
- unsigned int j;
633
- if( zScope==0 ){
634
- srchFlags = SRCH_ALL;
635
- }else{
636
- srchFlags = 0;
637
- for(i=0; zScope[i]; i++){
638
- switch( zScope[i] ){
639
- case 'a': srchFlags = SRCH_ALL; break;
640
- case 'c': srchFlags |= SRCH_CKIN; break;
641
- case 'd': srchFlags |= SRCH_DOC; break;
642
- case 'e': srchFlags |= SRCH_TECHNOTE; break;
643
- case 'f': srchFlags |= SRCH_FORUM; break;
644
- case 't': srchFlags |= SRCH_TKT; break;
645
- case 'w': srchFlags |= SRCH_WIKI; break;
646
- }
647
- }
648
- }
649769
search_sql_setup(g.db);
650770
add_content_sql_commands(g.db);
651771
db_multi_exec(
652772
"CREATE TEMP TABLE x(label,url,score,id,date,snip);"
653773
);
@@ -654,10 +774,13 @@
654774
if( !search_index_exists() ){
655775
search_fullscan(zPattern, srchFlags); /* Full-scan search */
656776
}else{
657777
search_update_index(srchFlags); /* Update the index */
658778
search_indexed(zPattern, srchFlags); /* Indexed search */
779
+ if( srchFlags & SRCH_HELP ){
780
+ search_fullscan(zPattern, SRCH_HELP);
781
+ }
659782
}
660783
db_prepare(&q, "SELECT snip, label, score, id, date"
661784
" FROM x"
662785
" ORDER BY score DESC, date DESC;");
663786
blob_init(&com, 0, 0);
@@ -668,16 +791,11 @@
668791
const char *zLabel = db_column_text(&q, 1);
669792
const char *zDate = db_column_text(&q, 4);
670793
const char *zScore = db_column_text(&q, 2);
671794
const char *zId = db_column_text(&q, 3);
672795
blob_appendf(&snip, "%s", zSnippet);
673
- for(j=0; j<snip.nUsed; j++){
674
- if( snip.aData[j]=='\n' ){
675
- if( j>0 && snip.aData[j-1]=='\r' ) snip.aData[j-1] = ' ';
676
- snip.aData[j] = ' ';
677
- }
678
- }
796
+ search_snippet_to_plaintext(&snip, nTty);
679797
blob_appendf(&com, "%s\n%s\n%s", zLabel, blob_str(&snip), zDate);
680798
if( bDebug ){
681799
blob_appendf(&com," score: %s id: %s", zScore, zId);
682800
}
683801
comment_print(blob_str(&com), 0, 5, width,
@@ -731,28 +849,33 @@
731849
#define SRCH_DOC 0x0002 /* Search over embedded documents */
732850
#define SRCH_TKT 0x0004 /* Search over tickets */
733851
#define SRCH_WIKI 0x0008 /* Search over wiki */
734852
#define SRCH_TECHNOTE 0x0010 /* Search over tech notes */
735853
#define SRCH_FORUM 0x0020 /* Search over forum messages */
736
-#define SRCH_ALL 0x003f /* Search over everything */
854
+#define SRCH_HELP 0x0040 /* Search built-in help (full-scan only) */
855
+#define SRCH_ALL 0x007f /* Search over everything */
737856
#endif
738857
739858
/*
740859
** Remove bits from srchFlags which are disallowed by either the
741860
** current server configuration or by user permissions. Return
742861
** the revised search flags mask.
862
+**
863
+** If bFlex is true, that means allow through the SRCH_HELP option
864
+** even if it is not explicitly enabled.
743865
*/
744
-unsigned int search_restrict(unsigned int srchFlags){
866
+unsigned int search_restrict(unsigned int srchFlags, int bFlex){
745867
static unsigned int knownGood = 0;
746868
static unsigned int knownBad = 0;
747869
static const struct { unsigned m; const char *zKey; } aSetng[] = {
748
- { SRCH_CKIN, "search-ci" },
749
- { SRCH_DOC, "search-doc" },
750
- { SRCH_TKT, "search-tkt" },
751
- { SRCH_WIKI, "search-wiki" },
870
+ { SRCH_CKIN, "search-ci" },
871
+ { SRCH_DOC, "search-doc" },
872
+ { SRCH_TKT, "search-tkt" },
873
+ { SRCH_WIKI, "search-wiki" },
752874
{ SRCH_TECHNOTE, "search-technote" },
753
- { SRCH_FORUM, "search-forum" },
875
+ { SRCH_FORUM, "search-forum" },
876
+ { SRCH_HELP, "search-help" },
754877
};
755878
int i;
756879
if( g.perm.Read==0 ) srchFlags &= ~(SRCH_CKIN|SRCH_DOC|SRCH_TECHNOTE);
757880
if( g.perm.RdTkt==0 ) srchFlags &= ~(SRCH_TKT);
758881
if( g.perm.RdWiki==0 ) srchFlags &= ~(SRCH_WIKI);
@@ -765,10 +888,11 @@
765888
knownGood |= m;
766889
}else{
767890
knownBad |= m;
768891
}
769892
}
893
+ if( bFlex ) knownBad &= ~SRCH_HELP;
770894
return srchFlags & ~knownBad;
771895
}
772896
773897
/*
774898
** When this routine is called, there already exists a table
@@ -911,10 +1035,23 @@
9111035
" datetime(event.mtime),"
9121036
" search_snippet()"
9131037
" FROM event JOIN blob on event.objid=blob.rid"
9141038
" WHERE search_match('',body('f',rid,NULL));"
9151039
);
1040
+ }
1041
+ if( (srchFlags & SRCH_HELP)!=0 ){
1042
+ helptext_vtab_register(g.db);
1043
+ db_multi_exec(
1044
+ "INSERT INTO x(label,url,score,id,snip)"
1045
+ " SELECT format('Built-in help for the \"%%s\" %%s',name,type),"
1046
+ " '/help?cmd='||name,"
1047
+ " search_score(),"
1048
+ " 'h'||rowid,"
1049
+ " search_snippet()"
1050
+ " FROM helptext"
1051
+ " WHERE search_match('',helptext.helptext);"
1052
+ );
9161053
}
9171054
}
9181055
9191056
/*
9201057
** Number of significant bits in a u32
@@ -1068,10 +1205,11 @@
10681205
{ SRCH_DOC, 'd' },
10691206
{ SRCH_TKT, 't' },
10701207
{ SRCH_WIKI, 'w' },
10711208
{ SRCH_TECHNOTE, 'e' },
10721209
{ SRCH_FORUM, 'f' },
1210
+ { SRCH_HELP, 'h' },
10731211
};
10741212
int i;
10751213
for(i=0; i<count(aMask); i++){
10761214
if( srchFlags & aMask[i].m ){
10771215
blob_appendf(&sql, "%sftsdocs.type='%c'", zSep, aMask[i].c);
@@ -1157,11 +1295,11 @@
11571295
int nLimit = db_get_int("search-limit", 100);
11581296
11591297
if( P("searchlimit")!=0 ){
11601298
nLimit = atoi(P("searchlimit"));
11611299
}
1162
- srchFlags = search_restrict(srchFlags);
1300
+ srchFlags = search_restrict(srchFlags, 1);
11631301
if( srchFlags==0 ) return 0;
11641302
search_sql_setup(g.db);
11651303
add_content_sql_commands(g.db);
11661304
db_multi_exec(
11671305
"CREATE TEMP TABLE x(label,url,score,id,date,snip);"
@@ -1169,10 +1307,13 @@
11691307
if( !search_index_exists() ){
11701308
search_fullscan(zPattern, srchFlags); /* Full-scan search */
11711309
}else{
11721310
search_update_index(srchFlags); /* Update the index, if necessary */
11731311
search_indexed(zPattern, srchFlags); /* Indexed search */
1312
+ if( srchFlags & SRCH_HELP ){
1313
+ search_fullscan(zPattern, SRCH_HELP);
1314
+ }
11741315
}
11751316
db_prepare(&q, "SELECT url, snip, label, score, id, substr(date,1,10)"
11761317
" FROM x"
11771318
" ORDER BY score DESC, date DESC;");
11781319
while( db_step(&q)==SQLITE_ROW ){
@@ -1231,18 +1372,19 @@
12311372
const char *zDisable1;
12321373
const char *zDisable2;
12331374
const char *zPattern;
12341375
int fDebug = PB("debug");
12351376
int haveResult = 0;
1236
- srchFlags = search_restrict(srchFlags);
1377
+ srchFlags = search_restrict(srchFlags, 0);
12371378
switch( srchFlags ){
12381379
case SRCH_CKIN: zType = " Check-ins"; zClass = "Ckin"; break;
12391380
case SRCH_DOC: zType = " Docs"; zClass = "Doc"; break;
12401381
case SRCH_TKT: zType = " Tickets"; zClass = "Tkt"; break;
12411382
case SRCH_WIKI: zType = " Wiki"; zClass = "Wiki"; break;
12421383
case SRCH_TECHNOTE: zType = " Tech Notes"; zClass = "Note"; break;
12431384
case SRCH_FORUM: zType = " Forum"; zClass = "Frm"; break;
1385
+ case SRCH_HELP: zType = " Help"; zClass = "Hlp"; break;
12441386
}
12451387
if( srchFlags==0 ){
12461388
if( mFlags & 0x02 ) return 0;
12471389
zDisable1 = " disabled";
12481390
zDisable2 = " disabled";
@@ -1266,10 +1408,11 @@
12661408
{ "d", "Docs", SRCH_DOC },
12671409
{ "t", "Tickets", SRCH_TKT },
12681410
{ "w", "Wiki", SRCH_WIKI },
12691411
{ "e", "Tech Notes", SRCH_TECHNOTE },
12701412
{ "f", "Forum", SRCH_FORUM },
1413
+ { "h", "Help", SRCH_HELP },
12711414
};
12721415
const char *zY = PD("y","all");
12731416
unsigned newFlags = srchFlags;
12741417
int i;
12751418
@ <select size='1' name='y'>
@@ -1321,10 +1464,11 @@
13211464
** d -> documentation
13221465
** t -> tickets
13231466
** w -> wiki
13241467
** e -> tech notes
13251468
** f -> forum
1469
+** h -> built-in help
13261470
** all -> everything
13271471
*/
13281472
void search_page(void){
13291473
const int isSearch = P("s")!=0;
13301474
login_check_credentials();
@@ -2100,11 +2244,11 @@
21002244
void search_rebuild_index(void){
21012245
fossil_print("rebuilding the search index...");
21022246
fflush(stdout);
21032247
search_create_index();
21042248
search_fill_index();
2105
- search_update_index(search_restrict(SRCH_ALL));
2249
+ search_update_index(search_restrict(SRCH_ALL, 0));
21062250
if( db_table_exists("repository","chat") ){
21072251
chat_rebuild_index(1);
21082252
}
21092253
fossil_print(" done\n");
21102254
}
@@ -2120,15 +2264,15 @@
21202264
** reindex Rebuild the search index. This is a no-op if
21212265
** index search is disabled
21222266
**
21232267
** index (on|off) Turn the search index on or off
21242268
**
2125
-** enable cdtwef Enable various kinds of search. c=Check-ins,
2126
-** d=Documents, t=Tickets, w=Wiki, e=Tech Notes,
2127
-** f=Forum.
2269
+** enable TYPE .. Enable search for TYPE. TYPE is one of:
2270
+** check-in, document, ticket, wiki, technote,
2271
+** forum, help, or all
21282272
**
2129
-** disable cdtwef Disable various kinds of search
2273
+** disable TYPE ... Disable search for TYPE
21302274
**
21312275
** tokenizer VALUE Select a tokenizer for indexed search. VALUE
21322276
** may be one of (porter, on, off, trigram, unicode61),
21332277
** and "on" is equivalent to "porter". Unindexed
21342278
** search never uses tokenization or stemming.
@@ -2150,16 +2294,17 @@
21502294
static const struct {
21512295
const char *zSetting;
21522296
const char *zName;
21532297
const char *zSw;
21542298
} aSetng[] = {
2155
- { "search-ci", "check-in search:", "c" },
2156
- { "search-doc", "document search:", "d" },
2157
- { "search-tkt", "ticket search:", "t" },
2158
- { "search-wiki", "wiki search:", "w" },
2159
- { "search-technote", "tech note search:", "e" },
2160
- { "search-forum", "forum search:", "f" },
2299
+ { "search-ci", "check-in search:", "c" },
2300
+ { "search-doc", "document search:", "d" },
2301
+ { "search-tkt", "ticket search:", "t" },
2302
+ { "search-wiki", "wiki search:", "w" },
2303
+ { "search-technote", "technote search:", "e" },
2304
+ { "search-forum", "forum search:", "f" },
2305
+ { "search-help", "built-in help search:", "h" },
21612306
};
21622307
char *zSubCmd = 0;
21632308
int i, j, n;
21642309
int iCmd = 0;
21652310
int iAction = 0;
@@ -2192,16 +2337,46 @@
21922337
}
21932338
db_begin_transaction();
21942339
21952340
/* Adjust search settings */
21962341
if( iCmd==3 || iCmd==4 ){
2342
+ int k;
21972343
const char *zCtrl;
2198
- if( g.argc<4 ) usage(mprintf("%s STRING",zSubCmd));
2199
- zCtrl = g.argv[3];
2200
- for(j=0; j<count(aSetng); j++){
2201
- if( strchr(zCtrl, aSetng[j].zSw[0])!=0 ){
2202
- db_set_int(aSetng[j].zSetting/*works-like:"x"*/, iCmd-3, 0);
2344
+ for(k=2; k<g.argc; k++){
2345
+ if( k==2 ){
2346
+ if( g.argc<4 ){
2347
+ zCtrl = "all";
2348
+ }else{
2349
+ zCtrl = g.argv[3];
2350
+ k++;
2351
+ }
2352
+ }else{
2353
+ zCtrl = g.argv[k];
2354
+ }
2355
+ if( fossil_strcmp(zCtrl,"all")==0 ){
2356
+ zCtrl = "cdtwefh";
2357
+ }
2358
+ if( strlen(zCtrl)>=4 ){
2359
+ /* If the argument to "enable" or "disable" is a string of at least
2360
+ ** 4 characters which matches part of any aSetng.zName, then use that
2361
+ ** one aSetng value only. */
2362
+ char *zGlob = mprintf("*%s*", zCtrl);
2363
+ for(j=0; j<count(aSetng); j++){
2364
+ if( sqlite3_strglob(zGlob, aSetng[j].zName)==0 ){
2365
+ db_set_int(aSetng[j].zSetting/*works-like:"x"*/, iCmd-3, 0);
2366
+ zCtrl = 0;
2367
+ break;
2368
+ }
2369
+ }
2370
+ fossil_free(zGlob);
2371
+ }
2372
+ if( zCtrl ){
2373
+ for(j=0; j<count(aSetng); j++){
2374
+ if( strchr(zCtrl, aSetng[j].zSw[0])!=0 ){
2375
+ db_set_int(aSetng[j].zSetting/*works-like:"x"*/, iCmd-3, 0);
2376
+ }
2377
+ }
22032378
}
22042379
}
22052380
}else if( iCmd==5 ){
22062381
int iOldTokenizer, iNewTokenizer;
22072382
if( g.argc<4 ) usage("tokenizer porter|on|off|trigram|unicode61");
@@ -2224,30 +2399,30 @@
22242399
search_rebuild_index();
22252400
}
22262401
22272402
/* Always show the status before ending */
22282403
for(i=0; i<count(aSetng); i++){
2229
- fossil_print("%-17s %s\n", aSetng[i].zName,
2404
+ fossil_print("%-21s %s\n", aSetng[i].zName,
22302405
db_get_boolean(aSetng[i].zSetting,0) ? "on" : "off");
22312406
}
2232
- fossil_print("%-17s %s\n", "tokenizer:",
2407
+ fossil_print("%-21s %s\n", "tokenizer:",
22332408
search_tokenizer_for_string(0));
22342409
if( search_index_exists() ){
22352410
int pgsz = db_int64(0, "PRAGMA repository.page_size;");
22362411
i64 nTotal = db_int64(0, "PRAGMA repository.page_count;")*pgsz;
22372412
i64 nFts = db_int64(0, "SELECT count(*) FROM dbstat"
22382413
" WHERE schema='repository'"
22392414
" AND name LIKE 'fts%%'")*pgsz;
22402415
char zSize[50];
2241
- fossil_print("%-17s FTS%d\n", "full-text index:", search_index_type(1));
2242
- fossil_print("%-17s %d\n", "documents:",
2416
+ fossil_print("%-21s FTS%d\n", "full-text index:", search_index_type(1));
2417
+ fossil_print("%-21s %d\n", "documents:",
22432418
db_int(0, "SELECT count(*) FROM ftsdocs"));
22442419
approxSizeName(sizeof(zSize), zSize, nFts);
2245
- fossil_print("%-17s %s (%.1f%% of repository)\n", "space used",
2420
+ fossil_print("%-21s %s (%.1f%% of repository)\n", "space used",
22462421
zSize, 100.0*((double)nFts/(double)nTotal));
22472422
}else{
2248
- fossil_print("%-17s disabled\n", "full-text index:");
2423
+ fossil_print("%-21s disabled\n", "full-text index:");
22492424
}
22502425
db_end_transaction(0);
22512426
}
22522427
22532428
/*
22542429
--- src/search.c
+++ src/search.c
@@ -558,96 +558,216 @@
558 sqlite3_create_function(db, "body", 3, enc, 0,
559 search_body_sqlfunc, 0, 0);
560 sqlite3_create_function(db, "urlencode", 1, enc, 0,
561 search_urlencode_sqlfunc, 0, 0);
562 }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
563
564 /*
565 ** Testing the search function.
566 **
567 ** COMMAND: search*
568 **
569 ** Usage: %fossil search [-a|-all] [-n|-limit #] [-W|-width #] pattern...
570 **
571 ** Search for timeline entries matching all words provided on the
572 ** command line. Whole-word matches scope more highly than partial
573 ** matches.
574 **
575 ** Note: This command only searches the EVENT table. So it will only
576 ** display check-in comments or other comments that appear on an
577 ** unaugmented timeline. It does not search document text or forum
578 ** messages.
579 **
580 ** Outputs, by default, some top-N fraction of the results. The -all
581 ** option can be used to output all matches, regardless of their search
582 ** score. The -limit option can be used to limit the number of entries
583 ** returned. The -width option can be used to set the output width used
584 ** when printing matches.
585 **
586 ** Options:
587 ** -a|--all Output all matches, not just best matches
588 ** --debug Show additional debug content on --fts search
589 ** --fts Use the full-text search mechanism (testing only)
 
 
590 ** -n|--limit N Limit output to N matches
591 ** --scope SCOPE Scope of search. Valid for --fts only. One or
592 ** more of: all, c, d, e, f, t, w. Defaults to all.
593 ** -W|--width WIDTH Set display width to WIDTH columns, 0 for
594 ** unlimited. Defaults the terminal's width.
 
595 */
596 void search_cmd(void){
597 Blob pattern;
598 int i;
599 Blob sql = empty_blob;
600 Stmt q;
601 int iBest;
 
 
602 char fAll = NULL != find_option("all", "a", 0);
603 const char *zLimit = find_option("limit","n",1);
 
604 const char *zWidth = find_option("width","W",1);
605 const char *zScope = find_option("scope",0,1);
606 int bDebug = find_option("debug",0,0)!=0;
607 int nLimit = zLimit ? atoi(zLimit) : -1000;
608 int width;
609 int bFts = find_option("fts",0,0)!=0;
 
 
 
 
 
 
 
 
 
 
610
611 if( zWidth ){
612 width = atoi(zWidth);
613 if( (width!=0) && (width<=20) ){
614 fossil_fatal("-W|--width value must be >20 or 0");
615 }
616 }else{
617 width = -1;
618 }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
619
620 db_find_and_open_repository(0, 0);
 
621 if( g.argc<3 ) return;
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
622 blob_init(&pattern, g.argv[2], -1);
623 for(i=3; i<g.argc; i++){
624 blob_appendf(&pattern, " %s", g.argv[i]);
625 }
626 if( bFts ){
627 /* Search using FTS */
628 Blob com;
629 Blob snip;
630 const char *zPattern = blob_str(&pattern);
631 int srchFlags;
632 unsigned int j;
633 if( zScope==0 ){
634 srchFlags = SRCH_ALL;
635 }else{
636 srchFlags = 0;
637 for(i=0; zScope[i]; i++){
638 switch( zScope[i] ){
639 case 'a': srchFlags = SRCH_ALL; break;
640 case 'c': srchFlags |= SRCH_CKIN; break;
641 case 'd': srchFlags |= SRCH_DOC; break;
642 case 'e': srchFlags |= SRCH_TECHNOTE; break;
643 case 'f': srchFlags |= SRCH_FORUM; break;
644 case 't': srchFlags |= SRCH_TKT; break;
645 case 'w': srchFlags |= SRCH_WIKI; break;
646 }
647 }
648 }
649 search_sql_setup(g.db);
650 add_content_sql_commands(g.db);
651 db_multi_exec(
652 "CREATE TEMP TABLE x(label,url,score,id,date,snip);"
653 );
@@ -654,10 +774,13 @@
654 if( !search_index_exists() ){
655 search_fullscan(zPattern, srchFlags); /* Full-scan search */
656 }else{
657 search_update_index(srchFlags); /* Update the index */
658 search_indexed(zPattern, srchFlags); /* Indexed search */
 
 
 
659 }
660 db_prepare(&q, "SELECT snip, label, score, id, date"
661 " FROM x"
662 " ORDER BY score DESC, date DESC;");
663 blob_init(&com, 0, 0);
@@ -668,16 +791,11 @@
668 const char *zLabel = db_column_text(&q, 1);
669 const char *zDate = db_column_text(&q, 4);
670 const char *zScore = db_column_text(&q, 2);
671 const char *zId = db_column_text(&q, 3);
672 blob_appendf(&snip, "%s", zSnippet);
673 for(j=0; j<snip.nUsed; j++){
674 if( snip.aData[j]=='\n' ){
675 if( j>0 && snip.aData[j-1]=='\r' ) snip.aData[j-1] = ' ';
676 snip.aData[j] = ' ';
677 }
678 }
679 blob_appendf(&com, "%s\n%s\n%s", zLabel, blob_str(&snip), zDate);
680 if( bDebug ){
681 blob_appendf(&com," score: %s id: %s", zScore, zId);
682 }
683 comment_print(blob_str(&com), 0, 5, width,
@@ -731,28 +849,33 @@
731 #define SRCH_DOC 0x0002 /* Search over embedded documents */
732 #define SRCH_TKT 0x0004 /* Search over tickets */
733 #define SRCH_WIKI 0x0008 /* Search over wiki */
734 #define SRCH_TECHNOTE 0x0010 /* Search over tech notes */
735 #define SRCH_FORUM 0x0020 /* Search over forum messages */
736 #define SRCH_ALL 0x003f /* Search over everything */
 
737 #endif
738
739 /*
740 ** Remove bits from srchFlags which are disallowed by either the
741 ** current server configuration or by user permissions. Return
742 ** the revised search flags mask.
 
 
 
743 */
744 unsigned int search_restrict(unsigned int srchFlags){
745 static unsigned int knownGood = 0;
746 static unsigned int knownBad = 0;
747 static const struct { unsigned m; const char *zKey; } aSetng[] = {
748 { SRCH_CKIN, "search-ci" },
749 { SRCH_DOC, "search-doc" },
750 { SRCH_TKT, "search-tkt" },
751 { SRCH_WIKI, "search-wiki" },
752 { SRCH_TECHNOTE, "search-technote" },
753 { SRCH_FORUM, "search-forum" },
 
754 };
755 int i;
756 if( g.perm.Read==0 ) srchFlags &= ~(SRCH_CKIN|SRCH_DOC|SRCH_TECHNOTE);
757 if( g.perm.RdTkt==0 ) srchFlags &= ~(SRCH_TKT);
758 if( g.perm.RdWiki==0 ) srchFlags &= ~(SRCH_WIKI);
@@ -765,10 +888,11 @@
765 knownGood |= m;
766 }else{
767 knownBad |= m;
768 }
769 }
 
770 return srchFlags & ~knownBad;
771 }
772
773 /*
774 ** When this routine is called, there already exists a table
@@ -911,10 +1035,23 @@
911 " datetime(event.mtime),"
912 " search_snippet()"
913 " FROM event JOIN blob on event.objid=blob.rid"
914 " WHERE search_match('',body('f',rid,NULL));"
915 );
 
 
 
 
 
 
 
 
 
 
 
 
 
916 }
917 }
918
919 /*
920 ** Number of significant bits in a u32
@@ -1068,10 +1205,11 @@
1068 { SRCH_DOC, 'd' },
1069 { SRCH_TKT, 't' },
1070 { SRCH_WIKI, 'w' },
1071 { SRCH_TECHNOTE, 'e' },
1072 { SRCH_FORUM, 'f' },
 
1073 };
1074 int i;
1075 for(i=0; i<count(aMask); i++){
1076 if( srchFlags & aMask[i].m ){
1077 blob_appendf(&sql, "%sftsdocs.type='%c'", zSep, aMask[i].c);
@@ -1157,11 +1295,11 @@
1157 int nLimit = db_get_int("search-limit", 100);
1158
1159 if( P("searchlimit")!=0 ){
1160 nLimit = atoi(P("searchlimit"));
1161 }
1162 srchFlags = search_restrict(srchFlags);
1163 if( srchFlags==0 ) return 0;
1164 search_sql_setup(g.db);
1165 add_content_sql_commands(g.db);
1166 db_multi_exec(
1167 "CREATE TEMP TABLE x(label,url,score,id,date,snip);"
@@ -1169,10 +1307,13 @@
1169 if( !search_index_exists() ){
1170 search_fullscan(zPattern, srchFlags); /* Full-scan search */
1171 }else{
1172 search_update_index(srchFlags); /* Update the index, if necessary */
1173 search_indexed(zPattern, srchFlags); /* Indexed search */
 
 
 
1174 }
1175 db_prepare(&q, "SELECT url, snip, label, score, id, substr(date,1,10)"
1176 " FROM x"
1177 " ORDER BY score DESC, date DESC;");
1178 while( db_step(&q)==SQLITE_ROW ){
@@ -1231,18 +1372,19 @@
1231 const char *zDisable1;
1232 const char *zDisable2;
1233 const char *zPattern;
1234 int fDebug = PB("debug");
1235 int haveResult = 0;
1236 srchFlags = search_restrict(srchFlags);
1237 switch( srchFlags ){
1238 case SRCH_CKIN: zType = " Check-ins"; zClass = "Ckin"; break;
1239 case SRCH_DOC: zType = " Docs"; zClass = "Doc"; break;
1240 case SRCH_TKT: zType = " Tickets"; zClass = "Tkt"; break;
1241 case SRCH_WIKI: zType = " Wiki"; zClass = "Wiki"; break;
1242 case SRCH_TECHNOTE: zType = " Tech Notes"; zClass = "Note"; break;
1243 case SRCH_FORUM: zType = " Forum"; zClass = "Frm"; break;
 
1244 }
1245 if( srchFlags==0 ){
1246 if( mFlags & 0x02 ) return 0;
1247 zDisable1 = " disabled";
1248 zDisable2 = " disabled";
@@ -1266,10 +1408,11 @@
1266 { "d", "Docs", SRCH_DOC },
1267 { "t", "Tickets", SRCH_TKT },
1268 { "w", "Wiki", SRCH_WIKI },
1269 { "e", "Tech Notes", SRCH_TECHNOTE },
1270 { "f", "Forum", SRCH_FORUM },
 
1271 };
1272 const char *zY = PD("y","all");
1273 unsigned newFlags = srchFlags;
1274 int i;
1275 @ <select size='1' name='y'>
@@ -1321,10 +1464,11 @@
1321 ** d -> documentation
1322 ** t -> tickets
1323 ** w -> wiki
1324 ** e -> tech notes
1325 ** f -> forum
 
1326 ** all -> everything
1327 */
1328 void search_page(void){
1329 const int isSearch = P("s")!=0;
1330 login_check_credentials();
@@ -2100,11 +2244,11 @@
2100 void search_rebuild_index(void){
2101 fossil_print("rebuilding the search index...");
2102 fflush(stdout);
2103 search_create_index();
2104 search_fill_index();
2105 search_update_index(search_restrict(SRCH_ALL));
2106 if( db_table_exists("repository","chat") ){
2107 chat_rebuild_index(1);
2108 }
2109 fossil_print(" done\n");
2110 }
@@ -2120,15 +2264,15 @@
2120 ** reindex Rebuild the search index. This is a no-op if
2121 ** index search is disabled
2122 **
2123 ** index (on|off) Turn the search index on or off
2124 **
2125 ** enable cdtwef Enable various kinds of search. c=Check-ins,
2126 ** d=Documents, t=Tickets, w=Wiki, e=Tech Notes,
2127 ** f=Forum.
2128 **
2129 ** disable cdtwef Disable various kinds of search
2130 **
2131 ** tokenizer VALUE Select a tokenizer for indexed search. VALUE
2132 ** may be one of (porter, on, off, trigram, unicode61),
2133 ** and "on" is equivalent to "porter". Unindexed
2134 ** search never uses tokenization or stemming.
@@ -2150,16 +2294,17 @@
2150 static const struct {
2151 const char *zSetting;
2152 const char *zName;
2153 const char *zSw;
2154 } aSetng[] = {
2155 { "search-ci", "check-in search:", "c" },
2156 { "search-doc", "document search:", "d" },
2157 { "search-tkt", "ticket search:", "t" },
2158 { "search-wiki", "wiki search:", "w" },
2159 { "search-technote", "tech note search:", "e" },
2160 { "search-forum", "forum search:", "f" },
 
2161 };
2162 char *zSubCmd = 0;
2163 int i, j, n;
2164 int iCmd = 0;
2165 int iAction = 0;
@@ -2192,16 +2337,46 @@
2192 }
2193 db_begin_transaction();
2194
2195 /* Adjust search settings */
2196 if( iCmd==3 || iCmd==4 ){
 
2197 const char *zCtrl;
2198 if( g.argc<4 ) usage(mprintf("%s STRING",zSubCmd));
2199 zCtrl = g.argv[3];
2200 for(j=0; j<count(aSetng); j++){
2201 if( strchr(zCtrl, aSetng[j].zSw[0])!=0 ){
2202 db_set_int(aSetng[j].zSetting/*works-like:"x"*/, iCmd-3, 0);
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
2203 }
2204 }
2205 }else if( iCmd==5 ){
2206 int iOldTokenizer, iNewTokenizer;
2207 if( g.argc<4 ) usage("tokenizer porter|on|off|trigram|unicode61");
@@ -2224,30 +2399,30 @@
2224 search_rebuild_index();
2225 }
2226
2227 /* Always show the status before ending */
2228 for(i=0; i<count(aSetng); i++){
2229 fossil_print("%-17s %s\n", aSetng[i].zName,
2230 db_get_boolean(aSetng[i].zSetting,0) ? "on" : "off");
2231 }
2232 fossil_print("%-17s %s\n", "tokenizer:",
2233 search_tokenizer_for_string(0));
2234 if( search_index_exists() ){
2235 int pgsz = db_int64(0, "PRAGMA repository.page_size;");
2236 i64 nTotal = db_int64(0, "PRAGMA repository.page_count;")*pgsz;
2237 i64 nFts = db_int64(0, "SELECT count(*) FROM dbstat"
2238 " WHERE schema='repository'"
2239 " AND name LIKE 'fts%%'")*pgsz;
2240 char zSize[50];
2241 fossil_print("%-17s FTS%d\n", "full-text index:", search_index_type(1));
2242 fossil_print("%-17s %d\n", "documents:",
2243 db_int(0, "SELECT count(*) FROM ftsdocs"));
2244 approxSizeName(sizeof(zSize), zSize, nFts);
2245 fossil_print("%-17s %s (%.1f%% of repository)\n", "space used",
2246 zSize, 100.0*((double)nFts/(double)nTotal));
2247 }else{
2248 fossil_print("%-17s disabled\n", "full-text index:");
2249 }
2250 db_end_transaction(0);
2251 }
2252
2253 /*
2254
--- src/search.c
+++ src/search.c
@@ -558,96 +558,216 @@
558 sqlite3_create_function(db, "body", 3, enc, 0,
559 search_body_sqlfunc, 0, 0);
560 sqlite3_create_function(db, "urlencode", 1, enc, 0,
561 search_urlencode_sqlfunc, 0, 0);
562 }
563
564 /*
565 ** The pSnip input contains snippet text from a search formatted
566 ** as HTML. Attempt to make that text more readable on a TTY.
567 **
568 ** If nTty is positive, use ANSI escape codes "\e[Nm" where N is nTty
569 ** to highly marked text.
570 */
571 void search_snippet_to_plaintext(Blob *pSnip, int nTty){
572 char *zSnip;
573 unsigned int j, k;
574
575 zSnip = pSnip->aData;
576 for(j=k=0; j<pSnip->nUsed; j++){
577 char c = zSnip[j];
578 if( c=='<' ){
579 if( memcmp(&zSnip[j],"<mark>",6)==0 ){
580 if( nTty ){
581 zSnip[k++] = 0x1b;
582 zSnip[k++] = '[';
583 if( nTty>=10 ) zSnip[k++] = (nTty/10)%10 + '0';
584 zSnip[k++] = nTty%10 + '0';
585 zSnip[k++] = 'm';
586 }
587 j += 5;
588 }else if( memcmp(&zSnip[j],"</mark>",7)==0 ){
589 if( nTty ){
590 zSnip[k++] = 0x1b;
591 zSnip[k++] = '[';
592 zSnip[k++] = '0';
593 zSnip[k++] = 'm';
594 }
595 j += 6;
596 }else{
597 zSnip[k++] = zSnip[j];
598 }
599 }else if( fossil_isspace(c) ){
600 zSnip[k++] = ' ';
601 while( fossil_isspace(zSnip[j+1]) ) j++;
602 }else if( c=='&' ){
603 if( zSnip[j+1]=='#' && fossil_isdigit(zSnip[j+2]) ){
604 int n = 3;
605 int x = zSnip[j+2] - '0';
606 if( fossil_isdigit(zSnip[j+3]) ){
607 x = x*10 + zSnip[j+3] - '0';
608 n++;
609 if( fossil_isdigit(zSnip[j+4]) ){
610 x = x*10 + zSnip[j+4] - '0';
611 n++;
612 }
613 }
614 if( zSnip[j+n]==';' ){
615 zSnip[k++] = (char)x;
616 j += n;
617 }else{
618 zSnip[k++] = c;
619 }
620 }else if( memcmp(&zSnip[j],"&lt;",4)==0 ){
621 zSnip[k++] = '<';
622 j += 3;
623 }else if( memcmp(&zSnip[j],"&gt;",4)==0 ){
624 zSnip[k++] = '>';
625 j += 3;
626 }else if( memcmp(&zSnip[j],"&quot;",6)==0 ){
627 zSnip[k++] = '<';
628 j += 5;
629 }else if( memcmp(&zSnip[j],"&amp;",5)==0 ){
630 zSnip[k++] = '<';
631 j += 4;
632 }else{
633 zSnip[k++] = c;
634 }
635 }else{
636 zSnip[k++] = c;
637 }
638 }
639 zSnip[k] = 0;
640 pSnip->nUsed = k;
641 }
642
643 /*
644 ** Testing the search function.
645 **
646 ** COMMAND: search*
647 **
648 ** Usage: %fossil search [OPTIONS] PATTERN...
649 **
650 ** Search the repository database for PATTERN and show matches.
651 ** The following elements of the repository can be searched:
652 **
653 ** * check-in comments
654 ** * embedded documentation
655 ** * forum posts
656 ** * tickets
657 ** * tech notes
658 ** * wiki pages
659 ** * built-in fossil help text
660 **
661 ** Use options (listed below) to select the scope of the search. The
662 ** default is check-in comments only.
 
663 **
664 ** Options:
665 ** -a|--all Search everything
666 ** -c|--checkins Search checkin comments
667 ** --docs Search embedded documentation
668 ** --forum Search forum posts
669 ** -h|--bi-help Search built-in help
670 ** -n|--limit N Limit output to N matches
671 ** --technotes Search tech notes
672 ** --tickets Search tickets
673 ** -W|--width WIDTH Set display width to WIDTH columns, 0 for
674 ** unlimited. Defaults to the terminal's width.
675 ** --wiki Search wiki
676 */
677 void search_cmd(void){
678 Blob pattern;
679 int i;
680 Blob sql = empty_blob;
681 Stmt q;
682 int iBest;
683 int srchFlags = 0;
684 int bFts = 1; /* Use FTS search by default now */
685 char fAll = NULL != find_option("all", "a", 0);
686 const char *zLimit = find_option("limit","n",1);
687 const char *zScope = 0;
688 const char *zWidth = find_option("width","W",1);
689 int bDebug = find_option("debug",0,0)!=0; /* Undocumented */
 
690 int nLimit = zLimit ? atoi(zLimit) : -1000;
691 int width;
692 int nTty = fossil_isatty(1) ? 91 : 0;
693
694 /* Undocumented option to change highlight color */
695 const char *zHighlight = find_option("highlight",0,1);
696 if( zHighlight ) nTty = atoi(zHighlight);
697
698 /* Undocumented option (legacy) */
699 zScope = find_option("scope",0,1);
700
701 if( find_option("fts",0,0)!=0 ) bFts = 1; /* Undocumented legacy */
702 if( find_option("legacy",0,0)!=0 ) bFts = 0; /* Undocumented */
703
704 if( zWidth ){
705 width = atoi(zWidth);
706 if( (width!=0) && (width<=20) ){
707 fossil_fatal("-W|--width value must be >20 or 0");
708 }
709 }else{
710 width = -1;
711 }
712 if( zScope ){
713 for(i=0; zScope[i]; i++){
714 switch( zScope[i] ){
715 case 'a': srchFlags = SRCH_ALL; break;
716 case 'c': srchFlags |= SRCH_CKIN; break;
717 case 'd': srchFlags |= SRCH_DOC; break;
718 case 'e': srchFlags |= SRCH_TECHNOTE; break;
719 case 'f': srchFlags |= SRCH_FORUM; break;
720 case 'h': srchFlags |= SRCH_HELP; break;
721 case 't': srchFlags |= SRCH_TKT; break;
722 case 'w': srchFlags |= SRCH_WIKI; break;
723 }
724 }
725 bFts = 1;
726 }
727 if( find_option("all","a",0) ){ srchFlags |= SRCH_ALL; bFts = 1; }
728 if( find_option("bi-help","h",0) ){ srchFlags |= SRCH_HELP; bFts = 1; }
729 if( find_option("checkins","c",0) ){ srchFlags |= SRCH_CKIN; bFts = 1; }
730 if( find_option("docs",0,0) ){ srchFlags |= SRCH_DOC; bFts = 1; }
731 if( find_option("forum",0,0) ){ srchFlags |= SRCH_FORUM; bFts = 1; }
732 if( find_option("technotes",0,0) ){ srchFlags |= SRCH_TECHNOTE; bFts = 1; }
733 if( find_option("tickets",0,0) ){ srchFlags |= SRCH_TKT; bFts = 1; }
734 if( find_option("wiki",0,0) ){ srchFlags |= SRCH_WIKI; bFts = 1; }
735
736 /* If no search objects are specified, default to "check-in comments" */
737 if( srchFlags==0 ) srchFlags = SRCH_CKIN;
738
739
740 db_find_and_open_repository(0, 0);
741 verify_all_options();
742 if( g.argc<3 ) return;
743 login_set_capabilities("s", 0);
744 if( search_restrict(srchFlags, 1)==0 ){
745 const char *zC1 = 0, *zPlural = "s";
746 if( srchFlags & SRCH_TECHNOTE ){ zC1 = "technote"; }
747 if( srchFlags & SRCH_TKT ){ zC1 = "ticket"; }
748 if( srchFlags & SRCH_FORUM ){ zC1 = "forum"; zPlural = ""; }
749 if( srchFlags & SRCH_DOC ){ zC1 = "document"; }
750 if( srchFlags & SRCH_WIKI ){ zC1 = "wiki"; zPlural = ""; }
751 if( srchFlags & SRCH_CKIN ){ zC1 = "check-in"; }
752 fossil_print(
753 "Search of %s%s is disabled on this repository.\n"
754 "Enable using \"fossil fts-config enable %s\".\n",
755 zC1, zPlural, zC1
756 );
757 return;
758 }
759
760 blob_init(&pattern, g.argv[2], -1);
761 for(i=3; i<g.argc; i++){
762 blob_appendf(&pattern, " %s", g.argv[i]);
763 }
764 if( bFts ){
765 /* Search using FTS */
766 Blob com;
767 Blob snip;
768 const char *zPattern = blob_str(&pattern);
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
769 search_sql_setup(g.db);
770 add_content_sql_commands(g.db);
771 db_multi_exec(
772 "CREATE TEMP TABLE x(label,url,score,id,date,snip);"
773 );
@@ -654,10 +774,13 @@
774 if( !search_index_exists() ){
775 search_fullscan(zPattern, srchFlags); /* Full-scan search */
776 }else{
777 search_update_index(srchFlags); /* Update the index */
778 search_indexed(zPattern, srchFlags); /* Indexed search */
779 if( srchFlags & SRCH_HELP ){
780 search_fullscan(zPattern, SRCH_HELP);
781 }
782 }
783 db_prepare(&q, "SELECT snip, label, score, id, date"
784 " FROM x"
785 " ORDER BY score DESC, date DESC;");
786 blob_init(&com, 0, 0);
@@ -668,16 +791,11 @@
791 const char *zLabel = db_column_text(&q, 1);
792 const char *zDate = db_column_text(&q, 4);
793 const char *zScore = db_column_text(&q, 2);
794 const char *zId = db_column_text(&q, 3);
795 blob_appendf(&snip, "%s", zSnippet);
796 search_snippet_to_plaintext(&snip, nTty);
 
 
 
 
 
797 blob_appendf(&com, "%s\n%s\n%s", zLabel, blob_str(&snip), zDate);
798 if( bDebug ){
799 blob_appendf(&com," score: %s id: %s", zScore, zId);
800 }
801 comment_print(blob_str(&com), 0, 5, width,
@@ -731,28 +849,33 @@
849 #define SRCH_DOC 0x0002 /* Search over embedded documents */
850 #define SRCH_TKT 0x0004 /* Search over tickets */
851 #define SRCH_WIKI 0x0008 /* Search over wiki */
852 #define SRCH_TECHNOTE 0x0010 /* Search over tech notes */
853 #define SRCH_FORUM 0x0020 /* Search over forum messages */
854 #define SRCH_HELP 0x0040 /* Search built-in help (full-scan only) */
855 #define SRCH_ALL 0x007f /* Search over everything */
856 #endif
857
858 /*
859 ** Remove bits from srchFlags which are disallowed by either the
860 ** current server configuration or by user permissions. Return
861 ** the revised search flags mask.
862 **
863 ** If bFlex is true, that means allow through the SRCH_HELP option
864 ** even if it is not explicitly enabled.
865 */
866 unsigned int search_restrict(unsigned int srchFlags, int bFlex){
867 static unsigned int knownGood = 0;
868 static unsigned int knownBad = 0;
869 static const struct { unsigned m; const char *zKey; } aSetng[] = {
870 { SRCH_CKIN, "search-ci" },
871 { SRCH_DOC, "search-doc" },
872 { SRCH_TKT, "search-tkt" },
873 { SRCH_WIKI, "search-wiki" },
874 { SRCH_TECHNOTE, "search-technote" },
875 { SRCH_FORUM, "search-forum" },
876 { SRCH_HELP, "search-help" },
877 };
878 int i;
879 if( g.perm.Read==0 ) srchFlags &= ~(SRCH_CKIN|SRCH_DOC|SRCH_TECHNOTE);
880 if( g.perm.RdTkt==0 ) srchFlags &= ~(SRCH_TKT);
881 if( g.perm.RdWiki==0 ) srchFlags &= ~(SRCH_WIKI);
@@ -765,10 +888,11 @@
888 knownGood |= m;
889 }else{
890 knownBad |= m;
891 }
892 }
893 if( bFlex ) knownBad &= ~SRCH_HELP;
894 return srchFlags & ~knownBad;
895 }
896
897 /*
898 ** When this routine is called, there already exists a table
@@ -911,10 +1035,23 @@
1035 " datetime(event.mtime),"
1036 " search_snippet()"
1037 " FROM event JOIN blob on event.objid=blob.rid"
1038 " WHERE search_match('',body('f',rid,NULL));"
1039 );
1040 }
1041 if( (srchFlags & SRCH_HELP)!=0 ){
1042 helptext_vtab_register(g.db);
1043 db_multi_exec(
1044 "INSERT INTO x(label,url,score,id,snip)"
1045 " SELECT format('Built-in help for the \"%%s\" %%s',name,type),"
1046 " '/help?cmd='||name,"
1047 " search_score(),"
1048 " 'h'||rowid,"
1049 " search_snippet()"
1050 " FROM helptext"
1051 " WHERE search_match('',helptext.helptext);"
1052 );
1053 }
1054 }
1055
1056 /*
1057 ** Number of significant bits in a u32
@@ -1068,10 +1205,11 @@
1205 { SRCH_DOC, 'd' },
1206 { SRCH_TKT, 't' },
1207 { SRCH_WIKI, 'w' },
1208 { SRCH_TECHNOTE, 'e' },
1209 { SRCH_FORUM, 'f' },
1210 { SRCH_HELP, 'h' },
1211 };
1212 int i;
1213 for(i=0; i<count(aMask); i++){
1214 if( srchFlags & aMask[i].m ){
1215 blob_appendf(&sql, "%sftsdocs.type='%c'", zSep, aMask[i].c);
@@ -1157,11 +1295,11 @@
1295 int nLimit = db_get_int("search-limit", 100);
1296
1297 if( P("searchlimit")!=0 ){
1298 nLimit = atoi(P("searchlimit"));
1299 }
1300 srchFlags = search_restrict(srchFlags, 1);
1301 if( srchFlags==0 ) return 0;
1302 search_sql_setup(g.db);
1303 add_content_sql_commands(g.db);
1304 db_multi_exec(
1305 "CREATE TEMP TABLE x(label,url,score,id,date,snip);"
@@ -1169,10 +1307,13 @@
1307 if( !search_index_exists() ){
1308 search_fullscan(zPattern, srchFlags); /* Full-scan search */
1309 }else{
1310 search_update_index(srchFlags); /* Update the index, if necessary */
1311 search_indexed(zPattern, srchFlags); /* Indexed search */
1312 if( srchFlags & SRCH_HELP ){
1313 search_fullscan(zPattern, SRCH_HELP);
1314 }
1315 }
1316 db_prepare(&q, "SELECT url, snip, label, score, id, substr(date,1,10)"
1317 " FROM x"
1318 " ORDER BY score DESC, date DESC;");
1319 while( db_step(&q)==SQLITE_ROW ){
@@ -1231,18 +1372,19 @@
1372 const char *zDisable1;
1373 const char *zDisable2;
1374 const char *zPattern;
1375 int fDebug = PB("debug");
1376 int haveResult = 0;
1377 srchFlags = search_restrict(srchFlags, 0);
1378 switch( srchFlags ){
1379 case SRCH_CKIN: zType = " Check-ins"; zClass = "Ckin"; break;
1380 case SRCH_DOC: zType = " Docs"; zClass = "Doc"; break;
1381 case SRCH_TKT: zType = " Tickets"; zClass = "Tkt"; break;
1382 case SRCH_WIKI: zType = " Wiki"; zClass = "Wiki"; break;
1383 case SRCH_TECHNOTE: zType = " Tech Notes"; zClass = "Note"; break;
1384 case SRCH_FORUM: zType = " Forum"; zClass = "Frm"; break;
1385 case SRCH_HELP: zType = " Help"; zClass = "Hlp"; break;
1386 }
1387 if( srchFlags==0 ){
1388 if( mFlags & 0x02 ) return 0;
1389 zDisable1 = " disabled";
1390 zDisable2 = " disabled";
@@ -1266,10 +1408,11 @@
1408 { "d", "Docs", SRCH_DOC },
1409 { "t", "Tickets", SRCH_TKT },
1410 { "w", "Wiki", SRCH_WIKI },
1411 { "e", "Tech Notes", SRCH_TECHNOTE },
1412 { "f", "Forum", SRCH_FORUM },
1413 { "h", "Help", SRCH_HELP },
1414 };
1415 const char *zY = PD("y","all");
1416 unsigned newFlags = srchFlags;
1417 int i;
1418 @ <select size='1' name='y'>
@@ -1321,10 +1464,11 @@
1464 ** d -> documentation
1465 ** t -> tickets
1466 ** w -> wiki
1467 ** e -> tech notes
1468 ** f -> forum
1469 ** h -> built-in help
1470 ** all -> everything
1471 */
1472 void search_page(void){
1473 const int isSearch = P("s")!=0;
1474 login_check_credentials();
@@ -2100,11 +2244,11 @@
2244 void search_rebuild_index(void){
2245 fossil_print("rebuilding the search index...");
2246 fflush(stdout);
2247 search_create_index();
2248 search_fill_index();
2249 search_update_index(search_restrict(SRCH_ALL, 0));
2250 if( db_table_exists("repository","chat") ){
2251 chat_rebuild_index(1);
2252 }
2253 fossil_print(" done\n");
2254 }
@@ -2120,15 +2264,15 @@
2264 ** reindex Rebuild the search index. This is a no-op if
2265 ** index search is disabled
2266 **
2267 ** index (on|off) Turn the search index on or off
2268 **
2269 ** enable TYPE .. Enable search for TYPE. TYPE is one of:
2270 ** check-in, document, ticket, wiki, technote,
2271 ** forum, help, or all
2272 **
2273 ** disable TYPE ... Disable search for TYPE
2274 **
2275 ** tokenizer VALUE Select a tokenizer for indexed search. VALUE
2276 ** may be one of (porter, on, off, trigram, unicode61),
2277 ** and "on" is equivalent to "porter". Unindexed
2278 ** search never uses tokenization or stemming.
@@ -2150,16 +2294,17 @@
2294 static const struct {
2295 const char *zSetting;
2296 const char *zName;
2297 const char *zSw;
2298 } aSetng[] = {
2299 { "search-ci", "check-in search:", "c" },
2300 { "search-doc", "document search:", "d" },
2301 { "search-tkt", "ticket search:", "t" },
2302 { "search-wiki", "wiki search:", "w" },
2303 { "search-technote", "technote search:", "e" },
2304 { "search-forum", "forum search:", "f" },
2305 { "search-help", "built-in help search:", "h" },
2306 };
2307 char *zSubCmd = 0;
2308 int i, j, n;
2309 int iCmd = 0;
2310 int iAction = 0;
@@ -2192,16 +2337,46 @@
2337 }
2338 db_begin_transaction();
2339
2340 /* Adjust search settings */
2341 if( iCmd==3 || iCmd==4 ){
2342 int k;
2343 const char *zCtrl;
2344 for(k=2; k<g.argc; k++){
2345 if( k==2 ){
2346 if( g.argc<4 ){
2347 zCtrl = "all";
2348 }else{
2349 zCtrl = g.argv[3];
2350 k++;
2351 }
2352 }else{
2353 zCtrl = g.argv[k];
2354 }
2355 if( fossil_strcmp(zCtrl,"all")==0 ){
2356 zCtrl = "cdtwefh";
2357 }
2358 if( strlen(zCtrl)>=4 ){
2359 /* If the argument to "enable" or "disable" is a string of at least
2360 ** 4 characters which matches part of any aSetng.zName, then use that
2361 ** one aSetng value only. */
2362 char *zGlob = mprintf("*%s*", zCtrl);
2363 for(j=0; j<count(aSetng); j++){
2364 if( sqlite3_strglob(zGlob, aSetng[j].zName)==0 ){
2365 db_set_int(aSetng[j].zSetting/*works-like:"x"*/, iCmd-3, 0);
2366 zCtrl = 0;
2367 break;
2368 }
2369 }
2370 fossil_free(zGlob);
2371 }
2372 if( zCtrl ){
2373 for(j=0; j<count(aSetng); j++){
2374 if( strchr(zCtrl, aSetng[j].zSw[0])!=0 ){
2375 db_set_int(aSetng[j].zSetting/*works-like:"x"*/, iCmd-3, 0);
2376 }
2377 }
2378 }
2379 }
2380 }else if( iCmd==5 ){
2381 int iOldTokenizer, iNewTokenizer;
2382 if( g.argc<4 ) usage("tokenizer porter|on|off|trigram|unicode61");
@@ -2224,30 +2399,30 @@
2399 search_rebuild_index();
2400 }
2401
2402 /* Always show the status before ending */
2403 for(i=0; i<count(aSetng); i++){
2404 fossil_print("%-21s %s\n", aSetng[i].zName,
2405 db_get_boolean(aSetng[i].zSetting,0) ? "on" : "off");
2406 }
2407 fossil_print("%-21s %s\n", "tokenizer:",
2408 search_tokenizer_for_string(0));
2409 if( search_index_exists() ){
2410 int pgsz = db_int64(0, "PRAGMA repository.page_size;");
2411 i64 nTotal = db_int64(0, "PRAGMA repository.page_count;")*pgsz;
2412 i64 nFts = db_int64(0, "SELECT count(*) FROM dbstat"
2413 " WHERE schema='repository'"
2414 " AND name LIKE 'fts%%'")*pgsz;
2415 char zSize[50];
2416 fossil_print("%-21s FTS%d\n", "full-text index:", search_index_type(1));
2417 fossil_print("%-21s %d\n", "documents:",
2418 db_int(0, "SELECT count(*) FROM ftsdocs"));
2419 approxSizeName(sizeof(zSize), zSize, nFts);
2420 fossil_print("%-21s %s (%.1f%% of repository)\n", "space used",
2421 zSize, 100.0*((double)nFts/(double)nTotal));
2422 }else{
2423 fossil_print("%-21s disabled\n", "full-text index:");
2424 }
2425 db_end_transaction(0);
2426 }
2427
2428 /*
2429
+3 -1
--- src/setup.c
+++ src/setup.c
@@ -2251,10 +2251,12 @@
22512251
onoff_attribute("Search Wiki", "search-wiki", "sw", 0, 0);
22522252
@ <br>
22532253
onoff_attribute("Search Tech Notes", "search-technote", "se", 0, 0);
22542254
@ <br>
22552255
onoff_attribute("Search Forum", "search-forum", "sf", 0, 0);
2256
+ @ <br>
2257
+ onoff_attribute("Search Built-in Help Text", "search-help", "sh", 0, 0);
22562258
@ <hr>
22572259
@ <p><input type="submit" name="submit" value="Apply Changes"></p>
22582260
@ <hr>
22592261
if( P("fts0") ){
22602262
search_drop_index();
@@ -2262,11 +2264,11 @@
22622264
const char *zTokenizer = PD("ftstok","off");
22632265
search_set_tokenizer(zTokenizer);
22642266
search_drop_index();
22652267
search_create_index();
22662268
search_fill_index();
2267
- search_update_index(search_restrict(SRCH_ALL));
2269
+ search_update_index(search_restrict(SRCH_ALL,0));
22682270
}
22692271
if( search_index_exists() ){
22702272
int pgsz = db_int64(0, "PRAGMA repository.page_size;");
22712273
i64 nTotal = db_int64(0, "PRAGMA repository.page_count;")*pgsz;
22722274
i64 nFts = db_int64(0, "SELECT count(*) FROM dbstat"
22732275
--- src/setup.c
+++ src/setup.c
@@ -2251,10 +2251,12 @@
2251 onoff_attribute("Search Wiki", "search-wiki", "sw", 0, 0);
2252 @ <br>
2253 onoff_attribute("Search Tech Notes", "search-technote", "se", 0, 0);
2254 @ <br>
2255 onoff_attribute("Search Forum", "search-forum", "sf", 0, 0);
 
 
2256 @ <hr>
2257 @ <p><input type="submit" name="submit" value="Apply Changes"></p>
2258 @ <hr>
2259 if( P("fts0") ){
2260 search_drop_index();
@@ -2262,11 +2264,11 @@
2262 const char *zTokenizer = PD("ftstok","off");
2263 search_set_tokenizer(zTokenizer);
2264 search_drop_index();
2265 search_create_index();
2266 search_fill_index();
2267 search_update_index(search_restrict(SRCH_ALL));
2268 }
2269 if( search_index_exists() ){
2270 int pgsz = db_int64(0, "PRAGMA repository.page_size;");
2271 i64 nTotal = db_int64(0, "PRAGMA repository.page_count;")*pgsz;
2272 i64 nFts = db_int64(0, "SELECT count(*) FROM dbstat"
2273
--- src/setup.c
+++ src/setup.c
@@ -2251,10 +2251,12 @@
2251 onoff_attribute("Search Wiki", "search-wiki", "sw", 0, 0);
2252 @ <br>
2253 onoff_attribute("Search Tech Notes", "search-technote", "se", 0, 0);
2254 @ <br>
2255 onoff_attribute("Search Forum", "search-forum", "sf", 0, 0);
2256 @ <br>
2257 onoff_attribute("Search Built-in Help Text", "search-help", "sh", 0, 0);
2258 @ <hr>
2259 @ <p><input type="submit" name="submit" value="Apply Changes"></p>
2260 @ <hr>
2261 if( P("fts0") ){
2262 search_drop_index();
@@ -2262,11 +2264,11 @@
2264 const char *zTokenizer = PD("ftstok","off");
2265 search_set_tokenizer(zTokenizer);
2266 search_drop_index();
2267 search_create_index();
2268 search_fill_index();
2269 search_update_index(search_restrict(SRCH_ALL,0));
2270 }
2271 if( search_index_exists() ){
2272 int pgsz = db_int64(0, "PRAGMA repository.page_size;");
2273 i64 nTotal = db_int64(0, "PRAGMA repository.page_count;")*pgsz;
2274 i64 nFts = db_int64(0, "SELECT count(*) FROM dbstat"
2275
+1 -1
--- src/sitemap.c
+++ src/sitemap.c
@@ -64,11 +64,11 @@
6464
** then disable anti-robot defenses */
6565
isPopup = 1;
6666
g.perm.Hyperlink = 1;
6767
g.jsHref = 0;
6868
}
69
- srchFlags = search_restrict(SRCH_ALL);
69
+ srchFlags = search_restrict(SRCH_ALL,0);
7070
if( !isPopup ){
7171
style_header("Site Map");
7272
style_adunit_config(ADUNIT_RIGHT_OK);
7373
}
7474
7575
--- src/sitemap.c
+++ src/sitemap.c
@@ -64,11 +64,11 @@
64 ** then disable anti-robot defenses */
65 isPopup = 1;
66 g.perm.Hyperlink = 1;
67 g.jsHref = 0;
68 }
69 srchFlags = search_restrict(SRCH_ALL);
70 if( !isPopup ){
71 style_header("Site Map");
72 style_adunit_config(ADUNIT_RIGHT_OK);
73 }
74
75
--- src/sitemap.c
+++ src/sitemap.c
@@ -64,11 +64,11 @@
64 ** then disable anti-robot defenses */
65 isPopup = 1;
66 g.perm.Hyperlink = 1;
67 g.jsHref = 0;
68 }
69 srchFlags = search_restrict(SRCH_ALL,0);
70 if( !isPopup ){
71 style_header("Site Map");
72 style_adunit_config(ADUNIT_RIGHT_OK);
73 }
74
75
+1 -1
--- src/th_main.c
+++ src/th_main.c
@@ -894,11 +894,11 @@
894894
int argc,
895895
const char **argv,
896896
int *argl
897897
){
898898
int rc = 1, i, j;
899
- unsigned int searchCap = search_restrict(SRCH_ALL);
899
+ unsigned int searchCap = search_restrict(SRCH_ALL, 0);
900900
if( argc<2 ){
901901
return Th_WrongNumArgs(interp, "hascap STRING ...");
902902
}
903903
for(i=1; i<argc && rc; i++){
904904
int match = 0;
905905
--- src/th_main.c
+++ src/th_main.c
@@ -894,11 +894,11 @@
894 int argc,
895 const char **argv,
896 int *argl
897 ){
898 int rc = 1, i, j;
899 unsigned int searchCap = search_restrict(SRCH_ALL);
900 if( argc<2 ){
901 return Th_WrongNumArgs(interp, "hascap STRING ...");
902 }
903 for(i=1; i<argc && rc; i++){
904 int match = 0;
905
--- src/th_main.c
+++ src/th_main.c
@@ -894,11 +894,11 @@
894 int argc,
895 const char **argv,
896 int *argl
897 ){
898 int rc = 1, i, j;
899 unsigned int searchCap = search_restrict(SRCH_ALL, 0);
900 if( argc<2 ){
901 return Th_WrongNumArgs(interp, "hascap STRING ...");
902 }
903 for(i=1; i<argc && rc; i++){
904 int match = 0;
905
+1 -1
--- src/timeline.c
+++ src/timeline.c
@@ -3005,11 +3005,11 @@
30053005
if( showSql ){
30063006
db_append_dml_to_blob(0);
30073007
@ <pre>%h(blob_str(&allSql))</pre>
30083008
blob_reset(&allSql);
30093009
}
3010
- if( search_restrict(SRCH_CKIN)!=0 ){
3010
+ if( search_restrict(SRCH_CKIN, 0)!=0 ){
30113011
style_submenu_element("Search", "%R/search?y=c");
30123012
}
30133013
if( advancedMenu ){
30143014
style_submenu_element("Basic", "%s",
30153015
url_render(&url, "advm", "0", "udc", "1"));
30163016
--- src/timeline.c
+++ src/timeline.c
@@ -3005,11 +3005,11 @@
3005 if( showSql ){
3006 db_append_dml_to_blob(0);
3007 @ <pre>%h(blob_str(&allSql))</pre>
3008 blob_reset(&allSql);
3009 }
3010 if( search_restrict(SRCH_CKIN)!=0 ){
3011 style_submenu_element("Search", "%R/search?y=c");
3012 }
3013 if( advancedMenu ){
3014 style_submenu_element("Basic", "%s",
3015 url_render(&url, "advm", "0", "udc", "1"));
3016
--- src/timeline.c
+++ src/timeline.c
@@ -3005,11 +3005,11 @@
3005 if( showSql ){
3006 db_append_dml_to_blob(0);
3007 @ <pre>%h(blob_str(&allSql))</pre>
3008 blob_reset(&allSql);
3009 }
3010 if( search_restrict(SRCH_CKIN, 0)!=0 ){
3011 style_submenu_element("Search", "%R/search?y=c");
3012 }
3013 if( advancedMenu ){
3014 style_submenu_element("Basic", "%s",
3015 url_render(&url, "advm", "0", "udc", "1"));
3016
+2 -2
--- src/tkt.c
+++ src/tkt.c
@@ -1855,11 +1855,11 @@
18551855
18561856
/*
18571857
** Add some standard submenu elements for ticket screens.
18581858
*/
18591859
void ticket_standard_submenu(unsigned int ok){
1860
- if( (ok & T_SRCH)!=0 && search_restrict(SRCH_TKT)!=0 ){
1860
+ if( (ok & T_SRCH)!=0 && search_restrict(SRCH_TKT, 0)!=0 ){
18611861
style_submenu_element("Search", "%R/tktsrch");
18621862
}
18631863
if( (ok & T_REPLIST)!=0 ){
18641864
style_submenu_element("Reports", "%R/reportlist");
18651865
}
@@ -1875,11 +1875,11 @@
18751875
** either ticket-search (if search is enabled) or as the
18761876
** /reportlist page (if ticket search is disabled).
18771877
*/
18781878
void tkt_home_page(void){
18791879
login_check_credentials();
1880
- if( search_restrict(SRCH_TKT)!=0 ){
1880
+ if( search_restrict(SRCH_TKT, 0)!=0 ){
18811881
tkt_srchpage();
18821882
}else{
18831883
view_list();
18841884
}
18851885
}
18861886
--- src/tkt.c
+++ src/tkt.c
@@ -1855,11 +1855,11 @@
1855
1856 /*
1857 ** Add some standard submenu elements for ticket screens.
1858 */
1859 void ticket_standard_submenu(unsigned int ok){
1860 if( (ok & T_SRCH)!=0 && search_restrict(SRCH_TKT)!=0 ){
1861 style_submenu_element("Search", "%R/tktsrch");
1862 }
1863 if( (ok & T_REPLIST)!=0 ){
1864 style_submenu_element("Reports", "%R/reportlist");
1865 }
@@ -1875,11 +1875,11 @@
1875 ** either ticket-search (if search is enabled) or as the
1876 ** /reportlist page (if ticket search is disabled).
1877 */
1878 void tkt_home_page(void){
1879 login_check_credentials();
1880 if( search_restrict(SRCH_TKT)!=0 ){
1881 tkt_srchpage();
1882 }else{
1883 view_list();
1884 }
1885 }
1886
--- src/tkt.c
+++ src/tkt.c
@@ -1855,11 +1855,11 @@
1855
1856 /*
1857 ** Add some standard submenu elements for ticket screens.
1858 */
1859 void ticket_standard_submenu(unsigned int ok){
1860 if( (ok & T_SRCH)!=0 && search_restrict(SRCH_TKT, 0)!=0 ){
1861 style_submenu_element("Search", "%R/tktsrch");
1862 }
1863 if( (ok & T_REPLIST)!=0 ){
1864 style_submenu_element("Reports", "%R/reportlist");
1865 }
@@ -1875,11 +1875,11 @@
1875 ** either ticket-search (if search is enabled) or as the
1876 ** /reportlist page (if ticket search is disabled).
1877 */
1878 void tkt_home_page(void){
1879 login_check_credentials();
1880 if( search_restrict(SRCH_TKT, 0)!=0 ){
1881 tkt_srchpage();
1882 }else{
1883 view_list();
1884 }
1885 }
1886
+3 -3
--- src/wiki.c
+++ src/wiki.c
@@ -332,11 +332,11 @@
332332
333333
/*
334334
** Add some standard submenu elements for wiki screens.
335335
*/
336336
static void wiki_standard_submenu(unsigned int ok){
337
- if( (ok & W_SRCH)!=0 && search_restrict(SRCH_WIKI)!=0 ){
337
+ if( (ok & W_SRCH)!=0 && search_restrict(SRCH_WIKI,0)!=0 ){
338338
style_submenu_element("Search", "%R/wikisrch");
339339
}
340340
if( (ok & W_LIST)!=0 ){
341341
style_submenu_element("List", "%R/wcontent");
342342
}
@@ -379,11 +379,11 @@
379379
@ <li> %z(href("%R/timeline?y=e"))List of All Tech-notes</a>
380380
@ available on this server.</li>
381381
if( g.perm.ModWiki ){
382382
@ <li> %z(href("%R/modreq"))Tend to pending moderation requests</a></li>
383383
}
384
- if( search_restrict(SRCH_WIKI)!=0 ){
384
+ if( search_restrict(SRCH_WIKI,0)!=0 ){
385385
@ <li> %z(href("%R/wikisrch"))Search</a> for wiki pages containing key
386386
@ words</li>
387387
}
388388
@ </ul>
389389
style_finish_page();
@@ -561,11 +561,11 @@
561561
if( !g.perm.RdWiki ){ login_needed(g.anon.RdWiki); return; }
562562
zPageName = P("name");
563563
(void)P("s")/*for cgi_check_for_malice(). "s" == search stringy*/;
564564
cgi_check_for_malice();
565565
if( zPageName==0 ){
566
- if( search_restrict(SRCH_WIKI)!=0 ){
566
+ if( search_restrict(SRCH_WIKI,0)!=0 ){
567567
wiki_srchpage();
568568
}else{
569569
wiki_helppage();
570570
}
571571
return;
572572
--- src/wiki.c
+++ src/wiki.c
@@ -332,11 +332,11 @@
332
333 /*
334 ** Add some standard submenu elements for wiki screens.
335 */
336 static void wiki_standard_submenu(unsigned int ok){
337 if( (ok & W_SRCH)!=0 && search_restrict(SRCH_WIKI)!=0 ){
338 style_submenu_element("Search", "%R/wikisrch");
339 }
340 if( (ok & W_LIST)!=0 ){
341 style_submenu_element("List", "%R/wcontent");
342 }
@@ -379,11 +379,11 @@
379 @ <li> %z(href("%R/timeline?y=e"))List of All Tech-notes</a>
380 @ available on this server.</li>
381 if( g.perm.ModWiki ){
382 @ <li> %z(href("%R/modreq"))Tend to pending moderation requests</a></li>
383 }
384 if( search_restrict(SRCH_WIKI)!=0 ){
385 @ <li> %z(href("%R/wikisrch"))Search</a> for wiki pages containing key
386 @ words</li>
387 }
388 @ </ul>
389 style_finish_page();
@@ -561,11 +561,11 @@
561 if( !g.perm.RdWiki ){ login_needed(g.anon.RdWiki); return; }
562 zPageName = P("name");
563 (void)P("s")/*for cgi_check_for_malice(). "s" == search stringy*/;
564 cgi_check_for_malice();
565 if( zPageName==0 ){
566 if( search_restrict(SRCH_WIKI)!=0 ){
567 wiki_srchpage();
568 }else{
569 wiki_helppage();
570 }
571 return;
572
--- src/wiki.c
+++ src/wiki.c
@@ -332,11 +332,11 @@
332
333 /*
334 ** Add some standard submenu elements for wiki screens.
335 */
336 static void wiki_standard_submenu(unsigned int ok){
337 if( (ok & W_SRCH)!=0 && search_restrict(SRCH_WIKI,0)!=0 ){
338 style_submenu_element("Search", "%R/wikisrch");
339 }
340 if( (ok & W_LIST)!=0 ){
341 style_submenu_element("List", "%R/wcontent");
342 }
@@ -379,11 +379,11 @@
379 @ <li> %z(href("%R/timeline?y=e"))List of All Tech-notes</a>
380 @ available on this server.</li>
381 if( g.perm.ModWiki ){
382 @ <li> %z(href("%R/modreq"))Tend to pending moderation requests</a></li>
383 }
384 if( search_restrict(SRCH_WIKI,0)!=0 ){
385 @ <li> %z(href("%R/wikisrch"))Search</a> for wiki pages containing key
386 @ words</li>
387 }
388 @ </ul>
389 style_finish_page();
@@ -561,11 +561,11 @@
561 if( !g.perm.RdWiki ){ login_needed(g.anon.RdWiki); return; }
562 zPageName = P("name");
563 (void)P("s")/*for cgi_check_for_malice(). "s" == search stringy*/;
564 cgi_check_for_malice();
565 if( zPageName==0 ){
566 if( search_restrict(SRCH_WIKI,0)!=0 ){
567 wiki_srchpage();
568 }else{
569 wiki_helppage();
570 }
571 return;
572

Keyboard Shortcuts

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