#!/usr/bin/tclsh.docsrc #### Import of wapp.tcl INCLUDE wapp.tcl #### End of wapp.tcl # Generate all header content for the output document # proc search_header {} { wapp-trim { DOCHEAD {Search SQLite Documentation} {} } } #------------------------------------------------------------------------- # Add an entry to the log database for the current query. Which # returns $nRes results. # proc search_add_log_entry {nRes} { if {[wapp-param-exists donotlog]} return sqlite3 db2 [file dir [wapp-param SCRIPT_FILENAME]]/search.d/searchlog.db db2 timeout 10000 set ip [wapp-param REMOTE_ADDR] set query [wapp-param q] db2 eval { PRAGMA synchronous=OFF; PRAGMA journal_mode=OFF; BEGIN; CREATE TABLE IF NOT EXISTS log( ip, -- IP query was made from query, -- Fts5 query string nres, -- Number of results timestamp DEFAULT CURRENT_TIMESTAMP ); INSERT INTO log(ip, query, nres) VALUES($ip, $query, $nRes); COMMIT; } db2 close } #------------------------------------------------------------------------- # This command is similar to the builtin Tcl [time] command, except that # it only ever runs the supplied script once. Also, instead of returning # a string like "xxx microseconds per iteration", it returns "x.yy ms" or # "x.yy s", depending on the magnitude of the time spent running the # command. For example: # # % ttime {after 1500} # 1.50 s # % ttime {after 45} # 45.02 ms # proc ttime {script} { set t [lindex [time [list uplevel $script]] 0] if {$t>1000000} { return [format "%.2f s" [expr {$t/1000000.0}]] } return [format "%.2f ms" [expr {$t/1000.0}]] } #----------------------------------------------------------------------- # Do a search of the change log # proc searchchanges {} { set q [wapp-param q] if {$q==""} {return {}} set open {} set close {} set query { SELECT url, version, idx, highlight(change, 3, $open, $close) AS text FROM change($q) ORDER BY rowid ASC } wapp-trim {

Change log entries mentioning: %html($q) } set s2 "style=\"margin-top:0\"" set s1 "style=\"font-size:larger; text-align:left\" class=nounderline" set prev "" db eval $query { if {$prev!=$version} { wapp-trim {
%html($version)
    } set prev $version } wapp-subst {
  • (%html($idx)) %unsafe($text)\n} } wapp-trim {

You can also see the entire changelog as a single page if you wish.

} } #----------------------------------------------------------------------- # Do a search over all documentation other than the change log # proc searchresults {} { set q [wapp-param q] if {$q==""} {return ""} # Count the '"' characters in $::A(q). If there is an odd number of # occurences, add a " to the end of the query so that fts5 can parse # it without error. if {[regexp -all \x22 $q] % 2} { append q \x22 } # Set iStart to the index of the first result to display. Results are # indexed starting at zero from most to least relevant. # set iStart 0 catch {set iStart [expr {[wapp-param i 0]*10}]} # Grab a list of rowid results. # set sql { SELECT rowid FROM page WHERE page MATCH $q ORDER BY srank(page) DESC, rank * COALESCE( (SELECT percent FROM weight WHERE id=page.rowid), 100 ); } if {[catch { set lRowid [db eval $sql] }]} { set x "" foreach word [split $q " "] { append x " \"[string map [list "\"" "\"\""] $word]\"" } set q [string trim $x] set lRowid [db eval $sql] } set lRes [list] foreach rowid $lRowid { if {$rowid > 1000} { set parent [expr $rowid / 1000] lappend subsections($parent) $rowid } else { lappend lRes $rowid } } set nRes [llength $lRes] set lRes [lrange $lRes $iStart [expr $iStart+9]] # Add an entry to the log database. # search_add_log_entry $nRes # If there are no results, return a message to that effect. # if {[llength $lRes] == 0} { wapp-subst {

No Results for: %html($q)\n} } # HTML markup used to highlight keywords within FTS5 generated snippets. # set open {} set close {} set ellipsis { ... } # Grab the required data # db eval [string map [list %LIST% [join $lRowid ,]] { SELECT rowid AS parentid, snippet(page, 0, $open, $close, $ellipsis, 6) AS s_apis, snippet(page, 2, $open, $close, '', 40) AS s_title1, snippet(page, 3, $open, $close, $ellipsis, 40) AS s_title2, snippet(page, 4, $open, $close, $ellipsis, 40) AS s_content, url, rank FROM page($q) WHERE rowid IN (%LIST%) }] X { foreach k [array names X] { set data($X(parentid),$k) [set X($k)] } } set i1 [expr {$iStart+1}] set i2 [expr {($nRes < $iStart+10) ? $nRes : $iStart+10}] wapp-trim {

Search results %html($i1)..%html($i2) of %html($nRes) for: %html($q) } foreach rowid $lRes { foreach a {parentid s_apis s_title1 s_content url rank} { set $a $data($rowid,$a) } if {[info exists subsections($parentid)]} { set childid [lindex $subsections($parentid) 0] set link $data($childid,url) set hdr $data($childid,s_title2) if {$hdr==""} { set s_content "" } else { set s_content [subst { $hdr }] } append s_content " $data($childid,s_content)" } wapp-trim {

} } wapp-subst {
%unsafe($s_title1)
(%url($url))
%unsafe($s_apis)
%unsafe($s_content)
\n} # If the query returned more than 10 results, add up to 10 links to # each set of 10 results (first link to results 1-10, second to 11-20, # third to 21-30, as required). # if {$nRes>10} { set s(0) {border:solid #044a64 1px;padding:1ex;margin:1ex;line-height:300%;} set s(1) "$s(0);background:#044a64;color:white" wapp-subst {

\n} for {set i 0} {$i < 10 && ($i*10)<$nRes} {incr i} { set style $s([expr {($iStart/10)==$i}]) wapp-trim { %html([expr $i+1]) } } wapp-subst {

\n} } } # This is the main entry point into the search result page generator # proc wapp-default {} { wapp-content-security-policy off wapp-allow-xorigin-params if {[wapp-param-exists env]} { search_header wapp-trim {

Environment Dump For Debugging

%html([wapp-debug-env])
} return } # When running using the built-in webserver in Wapp (in other words, # when not running as CGI) any filename that contains a "." loads # directly from the filesystem. if {[string match *//127.0.0.1:* [wapp-param BASE_URL]] && [string match *.* [wapp-param PATH_INFO]] } { set altfile [file dir [wapp-param SCRIPT_FILENAME]][wapp-param PATH_INFO] set fd [open $altfile rb] fconfigure $fd -translation binary wapp-unsafe [read $fd] close $fd switch -glob -- $altfile { *.html { wapp-mimetype text/html } *.css { wapp-mimetype text/css } *.gif { wapp-mimetype image/gif } } } search_header sqlite3 db [file dir [wapp-param SCRIPT_FILENAME]]/search.d/search.db set searchType [wapp-param s d] if {$searchType=="c"} { set cmd searchchanges } else { set cmd searchresults } db transaction { set t [ttime {$cmd}] } wapp-trim {

Page generated by FTS5 in about %html($t).

} } wapp-start $argv