Fossil SCM

Added the /srchsetup page for configuring the /search screen.

drh 2015-02-02 00:17 trunk
Commit ca833ff86f0a6a7e00477cf88fb88176f75c6fdb
2 files changed +67 -57 +55 -1
+67 -57
--- src/search.c
+++ src/search.c
@@ -424,13 +424,13 @@
424424
int argc,
425425
sqlite3_value **argv
426426
){
427427
Blob txt;
428428
const char *zType = (const char*)sqlite3_value_text(argv[0]);
429
- const char *zArg1 = (const char*)sqlite3_value_text(argv[1]);
430
- const char *zArg2 = (const char*)sqlite3_value_text(argv[2]);
431
- search_stext(zType[0], zArg1, zArg2, &txt);
429
+ int rid = sqlite3_value_int(argv[1]);
430
+ const char *zName = (const char*)sqlite3_value_text(argv[2]);
431
+ search_stext(zType[0], rid, zName, &txt);
432432
sqlite3_result_text(context, blob_materialize(&txt), -1, fossil_free);
433433
}
434434
435435
/*
436436
** Encode a string for use as a query parameter in a URL
@@ -556,18 +556,32 @@
556556
** * Search wiki
557557
*/
558558
void search_page(void){
559559
const char *zPattern = PD("s","");
560560
Stmt q;
561
- const char *zSrchEnable = "dwc";
561
+ int okCheckin;
562
+ int okDoc;
563
+ int okTicket;
564
+ int okWiki;
565
+ int allOff;
566
+ const char *zDisable;
562567
563568
login_check_credentials();
564
- if( !g.perm.Read ){ login_needed(); return; }
569
+ okCheckin = g.perm.Read && db_get_boolean("search-ci",0);
570
+ okDoc = g.perm.Read && db_get_boolean("search-doc",0);
571
+ okTicket = g.perm.RdTkt && db_get_boolean("search-tkt",0);
572
+ okWiki = g.perm.RdWiki && db_get_boolean("search-wiki",0);
573
+ allOff = (okCheckin + okDoc + okTicket + okWiki == 0);
574
+ zDisable = allOff ? " disabled" : "";
575
+ zPattern = allOff ? "" : PD("s","");
565576
style_header("Search");
566577
@ <form method="GET" action="search"><center>
567
- @ <input type="text" name="s" size="40" value="%h(zPattern)">
568
- @ <input type="submit" value="Search">
578
+ @ <input type="text" name="s" size="40" value="%h(zPattern)"%s(zDisable)>
579
+ @ <input type="submit" value="Search"%s(zDisable)>
580
+ if( allOff ){
581
+ @ <p class="generalError">Search is disabled</p>
582
+ }
569583
@ </center></form>
570584
while( fossil_isspace(zPattern[0]) ) zPattern++;
571585
if( zPattern[0] ){
572586
search_sql_setup(g.db);
573587
add_content_sql_commands(g.db);
@@ -575,28 +589,30 @@
575589
SRCHFLG_STATIC|SRCHFLG_HTML|SRCHFLG_SCORE);
576590
db_multi_exec(
577591
"CREATE VIRTUAL TABLE IF NOT EXISTS temp.foci USING files_of_checkin;"
578592
"CREATE TEMP TABLE x(label TEXT,url TEXT,date TEXT,snip TEXT);"
579593
);
580
- if( strchr(zSrchEnable, 'd') ){
581
- db_multi_exec(
582
- "INSERT INTO x(label,url,date,snip)"
583
- " SELECT printf('Document: %%s',foci.filename),"
584
- " printf('%R/doc/trunk/%%s',foci.filename),"
585
- " (SELECT datetime(event.mtime) FROM event"
586
- " WHERE objid=symbolic_name_to_rid('trunk')),"
587
- " snippet(stext('d',blob.rid,foci.filename))"
588
- " FROM foci CROSS JOIN blob"
589
- " WHERE checkinID=symbolic_name_to_rid('trunk')"
590
- " AND blob.uuid=foci.uuid"
591
- " AND (filename GLOB '*.wiki' OR"
592
- " filename GLOB '*.md' OR"
593
- " filename GLOB '*.txt' OR"
594
- " filename GLOB '*.html');"
595
- );
596
- }
597
- if( strchr(zSrchEnable, 'w') ){
594
+ if( okDoc ){
595
+ char *zDocGlob = db_get("doc-glob","");
596
+ char *zDocBr = db_get("doc-branch","trunk");
597
+ if( zDocGlob && zDocGlob[0] && zDocBr && zDocBr[0] ){
598
+ db_multi_exec(
599
+ "INSERT INTO x(label,url,date,snip)"
600
+ " SELECT printf('Document: %%s',foci.filename),"
601
+ " printf('%R/doc/%T/%%s',foci.filename),"
602
+ " (SELECT datetime(event.mtime) FROM event"
603
+ " WHERE objid=symbolic_name_to_rid('trunk')),"
604
+ " snippet(stext('d',blob.rid,foci.filename))"
605
+ " FROM foci CROSS JOIN blob"
606
+ " WHERE checkinID=symbolic_name_to_rid('trunk')"
607
+ " AND blob.uuid=foci.uuid"
608
+ " AND %z",
609
+ zDocBr, glob_expr("foci.filename", zDocGlob)
610
+ );
611
+ }
612
+ }
613
+ if( okWiki ){
598614
db_multi_exec(
599615
"WITH wiki(name,rid,mtime) AS ("
600616
" SELECT substr(tagname,6), tagxref.rid, max(tagxref.mtime)"
601617
" FROM tag, tagxref"
602618
" WHERE tag.tagname GLOB 'wiki-*'"
@@ -609,11 +625,11 @@
609625
" datetime(mtime),"
610626
" snippet(stext('w',rid,name))"
611627
" FROM wiki;"
612628
);
613629
}
614
- if( strchr(zSrchEnable, 'c') ){
630
+ if( okCheckin ){
615631
db_multi_exec(
616632
"WITH ckin(uuid,rid,mtime) AS ("
617633
" SELECT blob.uuid, event.objid, event.mtime"
618634
" FROM event, blob"
619635
" WHERE event.type='ci'"
@@ -627,11 +643,11 @@
627643
" FROM ckin;"
628644
);
629645
}
630646
db_prepare(&q, "SELECT url, substr(snip,9), label"
631647
" FROM x WHERE snip IS NOT NULL"
632
- " ORDER BY substr(snip,1,9) DESC, date DESC;");
648
+ " ORDER BY substr(snip,1,8) DESC, date DESC;");
633649
@ <ol>
634650
while( db_step(&q)==SQLITE_ROW ){
635651
const char *zUrl = db_column_text(&q, 0);
636652
const char *zSnippet = db_column_text(&q, 1);
637653
const char *zLabel = db_column_text(&q, 2);
@@ -676,40 +692,36 @@
676692
/*
677693
** Return "search text" - a reduced version of a document appropriate for
678694
** full text search and/or for constructing a search result snippet.
679695
**
680696
** cType: d Embedded documentation
681
-** s Source code listing
682697
** w Wiki page
683698
** c Check-in comment
684699
** t Ticket text
685
-** e Event/Blog text
686
-** k Diff of a wiki
687
-** f Diff of a checkin
700
+**
701
+** rid The RID of an artifact that defines the object
702
+** being searched.
688703
**
689
-** zArg1, zArg2: Description of the document, depending on cType.
704
+** zName Name of the object being searched.
690705
*/
691706
void search_stext(
692707
char cType, /* Type of document */
693
- const char *zArg1, /* First parameter */
694
- const char *zArg2, /* Second parameter */
708
+ int rid, /* BLOB.RID or TAG.TAGID value for document */
709
+ const char *zName, /* Name of the document */
695710
Blob *pOut /* OUT: Initialize to the search text */
696711
){
697712
blob_init(pOut, 0, 0);
698713
switch( cType ){
699
- case 'd': /* Doc. zArg1: RID of the file. zArg2: Filename */
700
- case 's': { /* Source. zArg1: RID of the file. zArg2: Filename */
701
- int rid = atoi(zArg1);
714
+ case 'd': { /* Documents */
702715
Blob doc;
703716
content_get(rid, &doc);
704717
blob_to_utf8_no_bom(&doc, 0);
705
- get_stext_by_mimetype(&doc, mimetype_from_name(zArg2), pOut);
718
+ get_stext_by_mimetype(&doc, mimetype_from_name(zName), pOut);
706719
blob_reset(&doc);
707720
break;
708721
}
709
- case 'w': { /* Wiki. zArg1: RID of the page. zArg2: Page name */
710
- int rid = atoi(zArg1);
722
+ case 'w': { /* Wiki */
711723
Manifest *pWiki = manifest_get(rid, CFTYPE_WIKI,0);
712724
Blob wiki;
713725
if( pWiki==0 ) break;
714726
blob_init(&wiki, pWiki->zWiki, -1);
715727
get_stext_by_mimetype(&wiki, wiki_filter_mimetypes(pWiki->zMimetype),
@@ -716,12 +728,11 @@
716728
pOut);
717729
blob_reset(&wiki);
718730
manifest_destroy(pWiki);
719731
break;
720732
}
721
- case 'c': { /* Ckeckin: zArg1: RID of the checkin. zArg2: Not used */
722
- int rid = atoi(zArg1);
733
+ case 'c': { /* Ckeck-in Comments */
723734
static Stmt q;
724735
db_static_prepare(&q,
725736
"SELECT coalesce(ecomment,comment)"
726737
" ||' (user: '||coalesce(euser,user,'?')"
727738
" ||', tags: '||"
@@ -741,46 +752,45 @@
741752
}
742753
}
743754
}
744755
745756
/*
746
-** The arguments cType,zArg1,zArg2 define an object that can be searched
757
+** The arguments cType,rid,zName define an object that can be searched
747758
** for. Return a URL (relative to the root of the Fossil project) that
748759
** will jump to that document.
749760
**
750761
** Space to hold the returned string is obtained from mprintf() and should
751762
** be freed by the caller using fossil_free() or the equivalent.
752763
*/
753764
char *search_url(
754765
char cType, /* Type of document */
755
- const char *zArg1, /* First parameter */
756
- const char *zArg2 /* Second parameter */
766
+ int rid, /* BLOB.RID or TAG.TAGID for the object */
767
+ const char *zName /* Name of the object */
757768
){
758769
char *zUrl = 0;
759770
switch( cType ){
760
- case 'd': { /* Doc. zArg1: RID of the file. zArg2: Filename */
761
- case 's': /* Source. zArg1: RID of the file. zArg2: Filename */
771
+ case 'd': { /* Documents */
762772
zUrl = db_text(0,
763773
"SELECT printf('/doc/%%s%%s', substr(blob.uuid,20), %Q)"
764774
" FROM mlink, blob"
765775
" WHERE mlink.fid=%d AND mlink.mid=blob.rid",
766
- zArg2, atoi(zArg1));
776
+ zName, rid);
767777
break;
768778
}
769
- case 'w': { /* Wiki. zArg1: RID of the page. zArg2: Page name */
770
- char *zId = db_text(0, "SELECT uuid FROM blob WHERE rid=%d",atoi(zArg1));
771
- zUrl = mprintf("/wiki?id=%z&name=%t", zId, zArg2);
779
+ case 'w': { /* Wiki */
780
+ char *zId = db_text(0, "SELECT uuid FROM blob WHERE rid=%d", rid);
781
+ zUrl = mprintf("/wiki?id=%z&name=%t", zId, zName);
772782
break;
773783
}
774
- case 'c': { /* Ckeckin: zArg1: RID of the checkin. zArg2: Not used */
775
- char *zId = db_text(0, "SELECT uuid FROM blob WHERE rid=%d",atoi(zArg1));
784
+ case 'c': { /* Ckeck-in Comment */
785
+ char *zId = db_text(0, "SELECT uuid FROM blob WHERE rid=%d", rid);
776786
zUrl = mprintf("/info/%z", zId);
777787
break;
778788
}
779789
}
780790
return zUrl;
781
-}
791
+}
782792
783793
/*
784794
** COMMAND: test-search-stext
785795
**
786796
** Usage: fossil test-search-stext TYPE ARG1 ARG2
@@ -787,11 +797,11 @@
787797
*/
788798
void test_search_stext(void){
789799
Blob out;
790800
char *zUrl;
791801
db_find_and_open_repository(0,0);
792
- if( g.argc!=5 ) usage("TYPE ARG1 ARG2");
793
- search_stext(g.argv[2][0], g.argv[3], g.argv[4], &out);
794
- zUrl = search_url(g.argv[2][0], g.argv[3], g.argv[4]);
802
+ if( g.argc!=5 ) usage("TYPE RID NAME");
803
+ search_stext(g.argv[2][0], atoi(g.argv[3]), g.argv[4], &out);
804
+ zUrl = search_url(g.argv[2][0], atoi(g.argv[3]), g.argv[4]);
795805
fossil_print("%s\n%z\n",blob_str(&out),zUrl);
796806
blob_reset(&out);
797807
}
798808
--- src/search.c
+++ src/search.c
@@ -424,13 +424,13 @@
424 int argc,
425 sqlite3_value **argv
426 ){
427 Blob txt;
428 const char *zType = (const char*)sqlite3_value_text(argv[0]);
429 const char *zArg1 = (const char*)sqlite3_value_text(argv[1]);
430 const char *zArg2 = (const char*)sqlite3_value_text(argv[2]);
431 search_stext(zType[0], zArg1, zArg2, &txt);
432 sqlite3_result_text(context, blob_materialize(&txt), -1, fossil_free);
433 }
434
435 /*
436 ** Encode a string for use as a query parameter in a URL
@@ -556,18 +556,32 @@
556 ** * Search wiki
557 */
558 void search_page(void){
559 const char *zPattern = PD("s","");
560 Stmt q;
561 const char *zSrchEnable = "dwc";
 
 
 
 
 
562
563 login_check_credentials();
564 if( !g.perm.Read ){ login_needed(); return; }
 
 
 
 
 
 
565 style_header("Search");
566 @ <form method="GET" action="search"><center>
567 @ <input type="text" name="s" size="40" value="%h(zPattern)">
568 @ <input type="submit" value="Search">
 
 
 
569 @ </center></form>
570 while( fossil_isspace(zPattern[0]) ) zPattern++;
571 if( zPattern[0] ){
572 search_sql_setup(g.db);
573 add_content_sql_commands(g.db);
@@ -575,28 +589,30 @@
575 SRCHFLG_STATIC|SRCHFLG_HTML|SRCHFLG_SCORE);
576 db_multi_exec(
577 "CREATE VIRTUAL TABLE IF NOT EXISTS temp.foci USING files_of_checkin;"
578 "CREATE TEMP TABLE x(label TEXT,url TEXT,date TEXT,snip TEXT);"
579 );
580 if( strchr(zSrchEnable, 'd') ){
581 db_multi_exec(
582 "INSERT INTO x(label,url,date,snip)"
583 " SELECT printf('Document: %%s',foci.filename),"
584 " printf('%R/doc/trunk/%%s',foci.filename),"
585 " (SELECT datetime(event.mtime) FROM event"
586 " WHERE objid=symbolic_name_to_rid('trunk')),"
587 " snippet(stext('d',blob.rid,foci.filename))"
588 " FROM foci CROSS JOIN blob"
589 " WHERE checkinID=symbolic_name_to_rid('trunk')"
590 " AND blob.uuid=foci.uuid"
591 " AND (filename GLOB '*.wiki' OR"
592 " filename GLOB '*.md' OR"
593 " filename GLOB '*.txt' OR"
594 " filename GLOB '*.html');"
595 );
596 }
597 if( strchr(zSrchEnable, 'w') ){
 
 
598 db_multi_exec(
599 "WITH wiki(name,rid,mtime) AS ("
600 " SELECT substr(tagname,6), tagxref.rid, max(tagxref.mtime)"
601 " FROM tag, tagxref"
602 " WHERE tag.tagname GLOB 'wiki-*'"
@@ -609,11 +625,11 @@
609 " datetime(mtime),"
610 " snippet(stext('w',rid,name))"
611 " FROM wiki;"
612 );
613 }
614 if( strchr(zSrchEnable, 'c') ){
615 db_multi_exec(
616 "WITH ckin(uuid,rid,mtime) AS ("
617 " SELECT blob.uuid, event.objid, event.mtime"
618 " FROM event, blob"
619 " WHERE event.type='ci'"
@@ -627,11 +643,11 @@
627 " FROM ckin;"
628 );
629 }
630 db_prepare(&q, "SELECT url, substr(snip,9), label"
631 " FROM x WHERE snip IS NOT NULL"
632 " ORDER BY substr(snip,1,9) DESC, date DESC;");
633 @ <ol>
634 while( db_step(&q)==SQLITE_ROW ){
635 const char *zUrl = db_column_text(&q, 0);
636 const char *zSnippet = db_column_text(&q, 1);
637 const char *zLabel = db_column_text(&q, 2);
@@ -676,40 +692,36 @@
676 /*
677 ** Return "search text" - a reduced version of a document appropriate for
678 ** full text search and/or for constructing a search result snippet.
679 **
680 ** cType: d Embedded documentation
681 ** s Source code listing
682 ** w Wiki page
683 ** c Check-in comment
684 ** t Ticket text
685 ** e Event/Blog text
686 ** k Diff of a wiki
687 ** f Diff of a checkin
688 **
689 ** zArg1, zArg2: Description of the document, depending on cType.
690 */
691 void search_stext(
692 char cType, /* Type of document */
693 const char *zArg1, /* First parameter */
694 const char *zArg2, /* Second parameter */
695 Blob *pOut /* OUT: Initialize to the search text */
696 ){
697 blob_init(pOut, 0, 0);
698 switch( cType ){
699 case 'd': /* Doc. zArg1: RID of the file. zArg2: Filename */
700 case 's': { /* Source. zArg1: RID of the file. zArg2: Filename */
701 int rid = atoi(zArg1);
702 Blob doc;
703 content_get(rid, &doc);
704 blob_to_utf8_no_bom(&doc, 0);
705 get_stext_by_mimetype(&doc, mimetype_from_name(zArg2), pOut);
706 blob_reset(&doc);
707 break;
708 }
709 case 'w': { /* Wiki. zArg1: RID of the page. zArg2: Page name */
710 int rid = atoi(zArg1);
711 Manifest *pWiki = manifest_get(rid, CFTYPE_WIKI,0);
712 Blob wiki;
713 if( pWiki==0 ) break;
714 blob_init(&wiki, pWiki->zWiki, -1);
715 get_stext_by_mimetype(&wiki, wiki_filter_mimetypes(pWiki->zMimetype),
@@ -716,12 +728,11 @@
716 pOut);
717 blob_reset(&wiki);
718 manifest_destroy(pWiki);
719 break;
720 }
721 case 'c': { /* Ckeckin: zArg1: RID of the checkin. zArg2: Not used */
722 int rid = atoi(zArg1);
723 static Stmt q;
724 db_static_prepare(&q,
725 "SELECT coalesce(ecomment,comment)"
726 " ||' (user: '||coalesce(euser,user,'?')"
727 " ||', tags: '||"
@@ -741,46 +752,45 @@
741 }
742 }
743 }
744
745 /*
746 ** The arguments cType,zArg1,zArg2 define an object that can be searched
747 ** for. Return a URL (relative to the root of the Fossil project) that
748 ** will jump to that document.
749 **
750 ** Space to hold the returned string is obtained from mprintf() and should
751 ** be freed by the caller using fossil_free() or the equivalent.
752 */
753 char *search_url(
754 char cType, /* Type of document */
755 const char *zArg1, /* First parameter */
756 const char *zArg2 /* Second parameter */
757 ){
758 char *zUrl = 0;
759 switch( cType ){
760 case 'd': { /* Doc. zArg1: RID of the file. zArg2: Filename */
761 case 's': /* Source. zArg1: RID of the file. zArg2: Filename */
762 zUrl = db_text(0,
763 "SELECT printf('/doc/%%s%%s', substr(blob.uuid,20), %Q)"
764 " FROM mlink, blob"
765 " WHERE mlink.fid=%d AND mlink.mid=blob.rid",
766 zArg2, atoi(zArg1));
767 break;
768 }
769 case 'w': { /* Wiki. zArg1: RID of the page. zArg2: Page name */
770 char *zId = db_text(0, "SELECT uuid FROM blob WHERE rid=%d",atoi(zArg1));
771 zUrl = mprintf("/wiki?id=%z&name=%t", zId, zArg2);
772 break;
773 }
774 case 'c': { /* Ckeckin: zArg1: RID of the checkin. zArg2: Not used */
775 char *zId = db_text(0, "SELECT uuid FROM blob WHERE rid=%d",atoi(zArg1));
776 zUrl = mprintf("/info/%z", zId);
777 break;
778 }
779 }
780 return zUrl;
781 }
782
783 /*
784 ** COMMAND: test-search-stext
785 **
786 ** Usage: fossil test-search-stext TYPE ARG1 ARG2
@@ -787,11 +797,11 @@
787 */
788 void test_search_stext(void){
789 Blob out;
790 char *zUrl;
791 db_find_and_open_repository(0,0);
792 if( g.argc!=5 ) usage("TYPE ARG1 ARG2");
793 search_stext(g.argv[2][0], g.argv[3], g.argv[4], &out);
794 zUrl = search_url(g.argv[2][0], g.argv[3], g.argv[4]);
795 fossil_print("%s\n%z\n",blob_str(&out),zUrl);
796 blob_reset(&out);
797 }
798
--- src/search.c
+++ src/search.c
@@ -424,13 +424,13 @@
424 int argc,
425 sqlite3_value **argv
426 ){
427 Blob txt;
428 const char *zType = (const char*)sqlite3_value_text(argv[0]);
429 int rid = sqlite3_value_int(argv[1]);
430 const char *zName = (const char*)sqlite3_value_text(argv[2]);
431 search_stext(zType[0], rid, zName, &txt);
432 sqlite3_result_text(context, blob_materialize(&txt), -1, fossil_free);
433 }
434
435 /*
436 ** Encode a string for use as a query parameter in a URL
@@ -556,18 +556,32 @@
556 ** * Search wiki
557 */
558 void search_page(void){
559 const char *zPattern = PD("s","");
560 Stmt q;
561 int okCheckin;
562 int okDoc;
563 int okTicket;
564 int okWiki;
565 int allOff;
566 const char *zDisable;
567
568 login_check_credentials();
569 okCheckin = g.perm.Read && db_get_boolean("search-ci",0);
570 okDoc = g.perm.Read && db_get_boolean("search-doc",0);
571 okTicket = g.perm.RdTkt && db_get_boolean("search-tkt",0);
572 okWiki = g.perm.RdWiki && db_get_boolean("search-wiki",0);
573 allOff = (okCheckin + okDoc + okTicket + okWiki == 0);
574 zDisable = allOff ? " disabled" : "";
575 zPattern = allOff ? "" : PD("s","");
576 style_header("Search");
577 @ <form method="GET" action="search"><center>
578 @ <input type="text" name="s" size="40" value="%h(zPattern)"%s(zDisable)>
579 @ <input type="submit" value="Search"%s(zDisable)>
580 if( allOff ){
581 @ <p class="generalError">Search is disabled</p>
582 }
583 @ </center></form>
584 while( fossil_isspace(zPattern[0]) ) zPattern++;
585 if( zPattern[0] ){
586 search_sql_setup(g.db);
587 add_content_sql_commands(g.db);
@@ -575,28 +589,30 @@
589 SRCHFLG_STATIC|SRCHFLG_HTML|SRCHFLG_SCORE);
590 db_multi_exec(
591 "CREATE VIRTUAL TABLE IF NOT EXISTS temp.foci USING files_of_checkin;"
592 "CREATE TEMP TABLE x(label TEXT,url TEXT,date TEXT,snip TEXT);"
593 );
594 if( okDoc ){
595 char *zDocGlob = db_get("doc-glob","");
596 char *zDocBr = db_get("doc-branch","trunk");
597 if( zDocGlob && zDocGlob[0] && zDocBr && zDocBr[0] ){
598 db_multi_exec(
599 "INSERT INTO x(label,url,date,snip)"
600 " SELECT printf('Document: %%s',foci.filename),"
601 " printf('%R/doc/%T/%%s',foci.filename),"
602 " (SELECT datetime(event.mtime) FROM event"
603 " WHERE objid=symbolic_name_to_rid('trunk')),"
604 " snippet(stext('d',blob.rid,foci.filename))"
605 " FROM foci CROSS JOIN blob"
606 " WHERE checkinID=symbolic_name_to_rid('trunk')"
607 " AND blob.uuid=foci.uuid"
608 " AND %z",
609 zDocBr, glob_expr("foci.filename", zDocGlob)
610 );
611 }
612 }
613 if( okWiki ){
614 db_multi_exec(
615 "WITH wiki(name,rid,mtime) AS ("
616 " SELECT substr(tagname,6), tagxref.rid, max(tagxref.mtime)"
617 " FROM tag, tagxref"
618 " WHERE tag.tagname GLOB 'wiki-*'"
@@ -609,11 +625,11 @@
625 " datetime(mtime),"
626 " snippet(stext('w',rid,name))"
627 " FROM wiki;"
628 );
629 }
630 if( okCheckin ){
631 db_multi_exec(
632 "WITH ckin(uuid,rid,mtime) AS ("
633 " SELECT blob.uuid, event.objid, event.mtime"
634 " FROM event, blob"
635 " WHERE event.type='ci'"
@@ -627,11 +643,11 @@
643 " FROM ckin;"
644 );
645 }
646 db_prepare(&q, "SELECT url, substr(snip,9), label"
647 " FROM x WHERE snip IS NOT NULL"
648 " ORDER BY substr(snip,1,8) DESC, date DESC;");
649 @ <ol>
650 while( db_step(&q)==SQLITE_ROW ){
651 const char *zUrl = db_column_text(&q, 0);
652 const char *zSnippet = db_column_text(&q, 1);
653 const char *zLabel = db_column_text(&q, 2);
@@ -676,40 +692,36 @@
692 /*
693 ** Return "search text" - a reduced version of a document appropriate for
694 ** full text search and/or for constructing a search result snippet.
695 **
696 ** cType: d Embedded documentation
 
697 ** w Wiki page
698 ** c Check-in comment
699 ** t Ticket text
700 **
701 ** rid The RID of an artifact that defines the object
702 ** being searched.
703 **
704 ** zName Name of the object being searched.
705 */
706 void search_stext(
707 char cType, /* Type of document */
708 int rid, /* BLOB.RID or TAG.TAGID value for document */
709 const char *zName, /* Name of the document */
710 Blob *pOut /* OUT: Initialize to the search text */
711 ){
712 blob_init(pOut, 0, 0);
713 switch( cType ){
714 case 'd': { /* Documents */
 
 
715 Blob doc;
716 content_get(rid, &doc);
717 blob_to_utf8_no_bom(&doc, 0);
718 get_stext_by_mimetype(&doc, mimetype_from_name(zName), pOut);
719 blob_reset(&doc);
720 break;
721 }
722 case 'w': { /* Wiki */
 
723 Manifest *pWiki = manifest_get(rid, CFTYPE_WIKI,0);
724 Blob wiki;
725 if( pWiki==0 ) break;
726 blob_init(&wiki, pWiki->zWiki, -1);
727 get_stext_by_mimetype(&wiki, wiki_filter_mimetypes(pWiki->zMimetype),
@@ -716,12 +728,11 @@
728 pOut);
729 blob_reset(&wiki);
730 manifest_destroy(pWiki);
731 break;
732 }
733 case 'c': { /* Ckeck-in Comments */
 
734 static Stmt q;
735 db_static_prepare(&q,
736 "SELECT coalesce(ecomment,comment)"
737 " ||' (user: '||coalesce(euser,user,'?')"
738 " ||', tags: '||"
@@ -741,46 +752,45 @@
752 }
753 }
754 }
755
756 /*
757 ** The arguments cType,rid,zName define an object that can be searched
758 ** for. Return a URL (relative to the root of the Fossil project) that
759 ** will jump to that document.
760 **
761 ** Space to hold the returned string is obtained from mprintf() and should
762 ** be freed by the caller using fossil_free() or the equivalent.
763 */
764 char *search_url(
765 char cType, /* Type of document */
766 int rid, /* BLOB.RID or TAG.TAGID for the object */
767 const char *zName /* Name of the object */
768 ){
769 char *zUrl = 0;
770 switch( cType ){
771 case 'd': { /* Documents */
 
772 zUrl = db_text(0,
773 "SELECT printf('/doc/%%s%%s', substr(blob.uuid,20), %Q)"
774 " FROM mlink, blob"
775 " WHERE mlink.fid=%d AND mlink.mid=blob.rid",
776 zName, rid);
777 break;
778 }
779 case 'w': { /* Wiki */
780 char *zId = db_text(0, "SELECT uuid FROM blob WHERE rid=%d", rid);
781 zUrl = mprintf("/wiki?id=%z&name=%t", zId, zName);
782 break;
783 }
784 case 'c': { /* Ckeck-in Comment */
785 char *zId = db_text(0, "SELECT uuid FROM blob WHERE rid=%d", rid);
786 zUrl = mprintf("/info/%z", zId);
787 break;
788 }
789 }
790 return zUrl;
791 }
792
793 /*
794 ** COMMAND: test-search-stext
795 **
796 ** Usage: fossil test-search-stext TYPE ARG1 ARG2
@@ -787,11 +797,11 @@
797 */
798 void test_search_stext(void){
799 Blob out;
800 char *zUrl;
801 db_find_and_open_repository(0,0);
802 if( g.argc!=5 ) usage("TYPE RID NAME");
803 search_stext(g.argv[2][0], atoi(g.argv[3]), g.argv[4], &out);
804 zUrl = search_url(g.argv[2][0], atoi(g.argv[3]), g.argv[4]);
805 fossil_print("%s\n%z\n",blob_str(&out),zUrl);
806 blob_reset(&out);
807 }
808
+55 -1
--- src/setup.c
+++ src/setup.c
@@ -70,11 +70,11 @@
7070
@ <p class="generalError"><b>Configuration Error:</b> Please add
7171
@ <tt>&lt;base href="$secureurl/$current_page"&gt;</tt> after
7272
@ <tt>&lt;head&gt;</tt> in the <a href="setup_header">HTML header</a>!</p>
7373
}
7474
75
- @ <table border="0" cellspacing="7">
75
+ @ <table border="0" cellspacing="3">
7676
setup_menu_entry("Users", "setup_ulist",
7777
"Grant privileges to individual users.");
7878
setup_menu_entry("Access", "setup_access",
7979
"Control access settings.");
8080
setup_menu_entry("Configuration", "setup_config",
@@ -86,10 +86,12 @@
8686
setup_menu_entry("Login-Group", "setup_login_group",
8787
"Manage single sign-on between this repository and others"
8888
" on the same server");
8989
setup_menu_entry("Tickets", "tktsetup",
9090
"Configure the trouble-ticketing system for this repository");
91
+ setup_menu_entry("Search","srchsetup",
92
+ "Configure the built-in search engine");
9193
setup_menu_entry("Transfers", "xfersetup",
9294
"Configure the transfer system for this repository");
9395
setup_menu_entry("Skins", "setup_skin",
9496
"Select from a menu of prepackaged \"skins\" for the web interface");
9597
setup_menu_entry("CSS", "setup_editcss",
@@ -2155,5 +2157,57 @@
21552157
if(limit>0 && counter<limit){
21562158
@ <div>%d(counter) entries shown.</div>
21572159
}
21582160
style_footer();
21592161
}
2162
+
2163
+/*
2164
+** WEBPAGE: srchsetup
2165
+**
2166
+** Configure the search engine.
2167
+*/
2168
+void page_srchsetup(){
2169
+ login_check_credentials();
2170
+ if( !g.perm.Setup && !g.perm.Admin ){
2171
+ login_needed();
2172
+ }
2173
+ style_header("Search Configuration");
2174
+ @ <form action="%s(g.zTop)/srchsetup" method="post"><div>
2175
+ login_insert_csrf_secret();
2176
+ @ <div style="text-align:center;font-weight:bold;">
2177
+ @ Server-specific settings that affect the
2178
+ @ <a href="%R/help?cmd=/search">/search</a> webpage.
2179
+ @ </div>
2180
+ @ <hr />
2181
+ textarea_attribute("Document Glob List", 3, 35, "doc-glob", "dg", "", 0);
2182
+ @ <p>The "Document Glob List" is a comma- or newline-separated list
2183
+ @ of GLOB expressions that identify all documents within the source
2184
+ @ tree that are to be searched when "Document Search" is enabled.
2185
+ @ Some examples:
2186
+ @ <table border=0 cellpadding=2 align=center>
2187
+ @ <tr><td>*.wiki,*.html,*.md,*.txt<td style="width: 4x;">
2188
+ @ <td>Search all wiki, HTML, Markdown, and Text files</tr>
2189
+ @ <tr><td>doc/*.md,*/README.txt,README.txt<td>
2190
+ @ <td>Search all Markdown files in the doc/ subfolder and all README.txt
2191
+ @ files.</tr>
2192
+ @ <tr><td>*<td><td>Search all checked-in files</tr>
2193
+ @ <tr><td><i>(blank)</i><td>
2194
+ @ <td>Search nothing. (Disables document search).</tr>
2195
+ @ </table>
2196
+ @ <hr />
2197
+ entry_attribute("Document Branch", 20, "doc-branch", "db", "trunk", 0);
2198
+ @ <p>When searching documents, use the versions of the files found at the
2199
+ @ type of the "Document Branch" branch. Recommended value: "trunk".
2200
+ @ Document search is disabled if blank.
2201
+ @ <hr/>
2202
+ onoff_attribute("Search Check-in Comments", "search-ci", "sc", 0, 0);
2203
+ @ <br>
2204
+ onoff_attribute("Search Documents", "search-doc", "sd", 0, 0);
2205
+ @ <br>
2206
+ onoff_attribute("Search Tickets", "search-tkt", "st", 0, 0);
2207
+ @ <br>
2208
+ onoff_attribute("Search Wiki","search-wiki", "sw", 0, 0);
2209
+ @ <hr/>
2210
+ @ <p><input type="submit" name="submit" value="Apply Changes" /></p>
2211
+ @ </div></form>
2212
+ style_footer();
2213
+}
21602214
--- src/setup.c
+++ src/setup.c
@@ -70,11 +70,11 @@
70 @ <p class="generalError"><b>Configuration Error:</b> Please add
71 @ <tt>&lt;base href="$secureurl/$current_page"&gt;</tt> after
72 @ <tt>&lt;head&gt;</tt> in the <a href="setup_header">HTML header</a>!</p>
73 }
74
75 @ <table border="0" cellspacing="7">
76 setup_menu_entry("Users", "setup_ulist",
77 "Grant privileges to individual users.");
78 setup_menu_entry("Access", "setup_access",
79 "Control access settings.");
80 setup_menu_entry("Configuration", "setup_config",
@@ -86,10 +86,12 @@
86 setup_menu_entry("Login-Group", "setup_login_group",
87 "Manage single sign-on between this repository and others"
88 " on the same server");
89 setup_menu_entry("Tickets", "tktsetup",
90 "Configure the trouble-ticketing system for this repository");
 
 
91 setup_menu_entry("Transfers", "xfersetup",
92 "Configure the transfer system for this repository");
93 setup_menu_entry("Skins", "setup_skin",
94 "Select from a menu of prepackaged \"skins\" for the web interface");
95 setup_menu_entry("CSS", "setup_editcss",
@@ -2155,5 +2157,57 @@
2155 if(limit>0 && counter<limit){
2156 @ <div>%d(counter) entries shown.</div>
2157 }
2158 style_footer();
2159 }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
2160
--- src/setup.c
+++ src/setup.c
@@ -70,11 +70,11 @@
70 @ <p class="generalError"><b>Configuration Error:</b> Please add
71 @ <tt>&lt;base href="$secureurl/$current_page"&gt;</tt> after
72 @ <tt>&lt;head&gt;</tt> in the <a href="setup_header">HTML header</a>!</p>
73 }
74
75 @ <table border="0" cellspacing="3">
76 setup_menu_entry("Users", "setup_ulist",
77 "Grant privileges to individual users.");
78 setup_menu_entry("Access", "setup_access",
79 "Control access settings.");
80 setup_menu_entry("Configuration", "setup_config",
@@ -86,10 +86,12 @@
86 setup_menu_entry("Login-Group", "setup_login_group",
87 "Manage single sign-on between this repository and others"
88 " on the same server");
89 setup_menu_entry("Tickets", "tktsetup",
90 "Configure the trouble-ticketing system for this repository");
91 setup_menu_entry("Search","srchsetup",
92 "Configure the built-in search engine");
93 setup_menu_entry("Transfers", "xfersetup",
94 "Configure the transfer system for this repository");
95 setup_menu_entry("Skins", "setup_skin",
96 "Select from a menu of prepackaged \"skins\" for the web interface");
97 setup_menu_entry("CSS", "setup_editcss",
@@ -2155,5 +2157,57 @@
2157 if(limit>0 && counter<limit){
2158 @ <div>%d(counter) entries shown.</div>
2159 }
2160 style_footer();
2161 }
2162
2163 /*
2164 ** WEBPAGE: srchsetup
2165 **
2166 ** Configure the search engine.
2167 */
2168 void page_srchsetup(){
2169 login_check_credentials();
2170 if( !g.perm.Setup && !g.perm.Admin ){
2171 login_needed();
2172 }
2173 style_header("Search Configuration");
2174 @ <form action="%s(g.zTop)/srchsetup" method="post"><div>
2175 login_insert_csrf_secret();
2176 @ <div style="text-align:center;font-weight:bold;">
2177 @ Server-specific settings that affect the
2178 @ <a href="%R/help?cmd=/search">/search</a> webpage.
2179 @ </div>
2180 @ <hr />
2181 textarea_attribute("Document Glob List", 3, 35, "doc-glob", "dg", "", 0);
2182 @ <p>The "Document Glob List" is a comma- or newline-separated list
2183 @ of GLOB expressions that identify all documents within the source
2184 @ tree that are to be searched when "Document Search" is enabled.
2185 @ Some examples:
2186 @ <table border=0 cellpadding=2 align=center>
2187 @ <tr><td>*.wiki,*.html,*.md,*.txt<td style="width: 4x;">
2188 @ <td>Search all wiki, HTML, Markdown, and Text files</tr>
2189 @ <tr><td>doc/*.md,*/README.txt,README.txt<td>
2190 @ <td>Search all Markdown files in the doc/ subfolder and all README.txt
2191 @ files.</tr>
2192 @ <tr><td>*<td><td>Search all checked-in files</tr>
2193 @ <tr><td><i>(blank)</i><td>
2194 @ <td>Search nothing. (Disables document search).</tr>
2195 @ </table>
2196 @ <hr />
2197 entry_attribute("Document Branch", 20, "doc-branch", "db", "trunk", 0);
2198 @ <p>When searching documents, use the versions of the files found at the
2199 @ type of the "Document Branch" branch. Recommended value: "trunk".
2200 @ Document search is disabled if blank.
2201 @ <hr/>
2202 onoff_attribute("Search Check-in Comments", "search-ci", "sc", 0, 0);
2203 @ <br>
2204 onoff_attribute("Search Documents", "search-doc", "sd", 0, 0);
2205 @ <br>
2206 onoff_attribute("Search Tickets", "search-tkt", "st", 0, 0);
2207 @ <br>
2208 onoff_attribute("Search Wiki","search-wiki", "sw", 0, 0);
2209 @ <hr/>
2210 @ <p><input type="submit" name="submit" value="Apply Changes" /></p>
2211 @ </div></form>
2212 style_footer();
2213 }
2214

Keyboard Shortcuts

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