|
1 | 1 | #lang racket/base |
2 | | - |
3 | | -(require net/sendurl |
4 | | - net/uri-codec |
5 | | - net/url |
6 | | - racket/string |
7 | | - setup/dirs |
8 | | - racket/contract |
9 | | - racket/list |
10 | | - scribble/xref |
11 | | - setup/language-family) |
12 | | - |
13 | | -(provide |
14 | | - (contract-out |
15 | | - [perform-search |
16 | | - (->* (any/c) |
17 | | - (any/c #:language-family (or/c string? #f)) |
18 | | - void?)] |
19 | | - [send-main-page |
20 | | - (->* () |
21 | | - (#:sub path-string? |
22 | | - #:fragment (or/c string? #f) |
23 | | - #:query (or/c string? #f) |
24 | | - #:notify (-> (or/c string? path?) any) |
25 | | - #:query-table (hash/c symbol? string? #:immutable #t)) |
26 | | - void?)] |
27 | | - [send-language-family-page |
28 | | - (->* ((or/c #f string?)) |
29 | | - () |
30 | | - void?)])) |
31 | | - |
32 | | -(define search-dir "search/") |
33 | | - |
34 | | -;; Almost nothing to do here -- the real work is done in the browser, |
35 | | -;; using javascript. |
36 | | - |
37 | | -(define (send-main-page #:sub [sub "index.html"] |
38 | | - #:fragment [fragment #f] #:query [query #f] |
39 | | - #:notify [notify void] |
40 | | - #:query-table [query-table (hash)]) |
41 | | - (define query-table-list-of-pairs |
42 | | - (for/list ([k (in-list (sort (hash-keys query-table) symbol<?))]) |
43 | | - (cons k (hash-ref query-table k)))) |
44 | | - (define open-url (get-doc-open-url)) |
45 | | - (cond |
46 | | - [open-url |
47 | | - (define u (string->url open-url)) |
48 | | - (define dest-url |
49 | | - (combine-url/relative u |
50 | | - (string-join (for/list ([s (explode-path sub)]) |
51 | | - (if (path? s) (path-element->string s) (format "~a" s))) |
52 | | - "/"))) |
53 | | - (notify (url->string dest-url)) |
54 | | - (send-url (url->string |
55 | | - (struct-copy url dest-url |
56 | | - [fragment (or fragment |
57 | | - (url-fragment dest-url))] |
58 | | - [query (append |
59 | | - (url-query dest-url) |
60 | | - (if query |
61 | | - (url-query |
62 | | - (string->url |
63 | | - (format "q?~a" query))) |
64 | | - null) |
65 | | - query-table-list-of-pairs)])))] |
66 | | - [else |
67 | | - (define doc-dirs (get-doc-search-dirs)) |
68 | | - (define path (or (and (absolute-path? sub) |
69 | | - sub) |
70 | | - (for/or ([dir (in-list doc-dirs)]) |
71 | | - (define path (build-path dir sub)) |
72 | | - (and (file-exists? path) |
73 | | - path)) |
74 | | - ;; Doesn't exist, but notify and then fall back below: |
75 | | - (build-path (find-doc-dir) sub))) |
76 | | - (notify path) |
77 | | - (define parsed-query-table |
78 | | - (if (null? query-table-list-of-pairs) |
79 | | - #f |
80 | | - (substring (url->string (url #f #f #f #f #f (list) query-table-list-of-pairs #f)) |
81 | | - 1))) |
82 | | - (define combined-base-query |
83 | | - (cond |
84 | | - [(and query parsed-query-table) |
85 | | - (string-append query "&" parsed-query-table)] |
86 | | - [else |
87 | | - (or query parsed-query-table)])) |
88 | | - (define combined-query |
89 | | - (cond |
90 | | - [(and (not (equal? sub "index.html")) |
91 | | - (pair? doc-dirs) |
92 | | - (file-exists? (build-path (car doc-dirs) "index.html"))) |
93 | | - ;; the entry point may or may not try to set `PLT_Root` itself |
94 | | - (define root (format "PLT_Root=~a" (uri-encode (path->string (path->directory-path (car doc-dirs)))))) |
95 | | - (if combined-base-query |
96 | | - (string-append combined-base-query "&" root) |
97 | | - root)] |
98 | | - [else combined-base-query])) |
99 | | - (cond |
100 | | - [(or (file-exists? path) (path? sub)) |
101 | | - (send-url/file path #:fragment fragment #:query combined-query)] |
102 | | - [else |
103 | | - (define (part pfx x) |
104 | | - (if x (string-append pfx x) "")) |
105 | | - (send-url |
106 | | - (string-append "https://docs.racket-lang.org/" sub |
107 | | - (part "#" fragment) |
108 | | - (part "?" combined-query)))])])) |
109 | | - |
110 | | -;; This is an example of changing this code to use the online manuals. |
111 | | -;; Normally, it's better to set `doc-open-url` in "etc/config.rktd", |
112 | | -;; but as a last resort, you can change `send-main-page` to compute a URL. |
113 | | -;; This may be useful in cases like schools that use systems that have problems |
114 | | -;; running a browser on local files (like NEU). If you use this, then |
115 | | -;; it is a good idea to put the documentation tree somewhere local, to |
116 | | -;; have better interaction times instead of using the PLT server. |
117 | | -;; (define (send-main-page #:sub [sub "index.html"] |
118 | | -;; #:fragment [fragment #f] #:query [query #f] |
119 | | -;; #:notify [notify void]) |
120 | | -;; (define (part pfx x) (if x (string-append pfx x) "")) |
121 | | -;; (send-url (string-append |
122 | | -;; "http://download.racket-lang.org/docs/" (version) "/html/" |
123 | | -;; sub (part "#" fragment) (part "?" query)))) |
124 | | - |
125 | | -(define (perform-search str [context #f] |
126 | | - #:language-family [language-family #f]) |
127 | | - ;; `context' can be a pre-filter query string to use for a context, |
128 | | - ;; optionally a list of one and a label to display for that context. |
129 | | - ;; In any case, when a context is specified, the search actually |
130 | | - ;; goes through the search-context.html page which tranpolines to |
131 | | - ;; the main search page after setting the cookies (so when the |
132 | | - ;; search page is refreshed it won't reset the context). |
133 | | - (let* ([label (and (list? context) (= 2 (length context)) (cadr context))] |
134 | | - [context (if (pair? context) (car context) context)] |
135 | | - [page (if context "search-context.html" "index.html")] |
136 | | - [query (format "q=~a" (uri-encode str))] |
137 | | - [query (if context |
138 | | - (format "~a&hq=~a~a" |
139 | | - query (uri-encode context) |
140 | | - (if label |
141 | | - (format "&label=~a" (uri-encode label)) |
142 | | - "")) |
143 | | - query)] |
144 | | - [fam (and language-family (get-language-family language-family))] |
145 | | - [famroot (and fam (hash-ref fam 'famroot #f))]) |
146 | | - (send-main-page #:sub (string-append search-dir page) |
147 | | - #:query query |
148 | | - #:query-table (if fam |
149 | | - (family-query-table fam language-family) |
150 | | - (hash))))) |
151 | | - |
152 | | -(define (send-language-family-page name) |
153 | | - (define fam (get-language-family name)) |
154 | | - (define start-doc (and fam |
155 | | - (or (hash-ref fam 'start-doc #f) |
156 | | - (hash-ref fam 'doc #f)))) |
157 | | - (define famroot (and fam (hash-ref fam 'famroot #f))) |
158 | | - (cond |
159 | | - [start-doc |
160 | | - (define xref ((dynamic-require 'setup/xref 'load-collections-xref))) |
161 | | - (define-values (path anchor) |
162 | | - (xref-tag->path+anchor xref `(part (,(format "~a" start-doc) "top")))) |
163 | | - (cond |
164 | | - [path (send-main-page #:sub path #:query-table (family-query-table fam name))] |
165 | | - [else (send-main-page)])] |
166 | | - [famroot |
167 | | - (send-main-page #:sub (format "~a/index.html" famroot) #:query-table (family-query-table fam name))] |
168 | | - [else |
169 | | - (send-main-page)])) |
170 | | - |
171 | | -(define (get-language-family name) |
172 | | - (define fams (get-language-families)) |
173 | | - (for/or ([fam (in-list fams)]) |
174 | | - (and (equal? name (hash-ref fam 'fam #f)) |
175 | | - fam))) |
176 | | - |
177 | | -(define (family-query-table fam name) |
178 | | - (define ht (hash 'fam (hash-ref fam 'fam name))) |
179 | | - (define famroot (hash-ref fam 'famroot #f)) |
180 | | - (if famroot |
181 | | - (hash-set ht 'famroot famroot) |
182 | | - ht)) |
| 2 | +(require racket/lazy-require) |
| 3 | + |
| 4 | +;; this indirection is because these bindings |
| 5 | +;; are now provided by the "racket-index" package, |
| 6 | +;; which depends on this package (and not vice versa) |
| 7 | +(lazy-require |
| 8 | + [help (perform-search |
| 9 | + send-main-page |
| 10 | + send-language-family-page)]) |
| 11 | + |
| 12 | +(provide perform-search |
| 13 | + send-main-page |
| 14 | + send-language-family-page) |
0 commit comments