much improved search, extended and fixed sendurl, string-based rendering for xrefs
svn: r8577
This commit is contained in:
parent
11d4f9c00c
commit
7539945a3d
|
@ -26,12 +26,12 @@
|
|||
(define exact-score 1000)
|
||||
(define exact-word-score 600)
|
||||
(define words1-score 400)
|
||||
(define words2-score 200)
|
||||
(define prefix-score 100)
|
||||
(define words2-score 100)
|
||||
(define prefix-score 200)
|
||||
(define suffix-score 20)
|
||||
(define contain-score 10)
|
||||
(define exported-entry-bonus 200) ; prefer bindings and modules
|
||||
(define regexp-score-factor 1.25) ; regexps get higher score
|
||||
(define exported-entry-factor 1.1) ; prefer bindings and modules
|
||||
(define regexp-score-factor 1.1) ; regexps get higher score
|
||||
(define nomatch-score -1) ; prefer less irrelevant terms
|
||||
|
||||
(define (perform-search terms #:exact? [exact? #f] #:go-if-one? [go-if-one? #t])
|
||||
|
@ -47,13 +47,15 @@
|
|||
(loop (cdr es)
|
||||
(let* ([e (car es)] [score (scorer e)])
|
||||
(if (score . > . 0) (cons (cons score e) r) r)))))]
|
||||
;; use to debug weird search results
|
||||
;; [_ (for ([x (sort entries scored-entry<?)])
|
||||
;; (printf "~a ~s\n" (car x) (entry-words (cdr x))))]
|
||||
[entries (map cdr (sort entries scored-entry<?))])
|
||||
(if (and go-if-one? (= 1 (length entries)))
|
||||
(let*-values ([(tag) (entry-tag (car entries))]
|
||||
[(path tag) (xref-tag->path+anchor xref tag)])
|
||||
(send-url/file path #:fragment (uri-encode tag)))
|
||||
(let* ([file (next-search-results-file)]
|
||||
[term->label
|
||||
(send-url/file path #:fragment (and tag (uri-encode tag))))
|
||||
(let* ([term->label
|
||||
(λ (t) (format "``~a''" (if (regexp? t) (object-name t) t)))]
|
||||
[search-title ; note: terms is not null at this point (see above)
|
||||
(apply string-append (term->label (car terms))
|
||||
|
@ -65,8 +67,8 @@
|
|||
(list (make-element "schemeerror" (list "No results found.")))
|
||||
(build-itemization entries))]
|
||||
[contents (cons (title search-title) contents)])
|
||||
(xref-render xref (decode contents) file)
|
||||
(send-url/file file))))))
|
||||
(send-url/contents (xref-render xref (decode contents) #f)
|
||||
#:delete-at (* 60 10)))))))
|
||||
|
||||
;; converts a list of search terms to a scoring function
|
||||
(define (terms->scorer terms exact?)
|
||||
|
@ -108,13 +110,16 @@
|
|||
sc))))
|
||||
terms))
|
||||
(lambda (entry)
|
||||
(foldl (lambda (word acc)
|
||||
(+ acc (foldl (lambda (sc acc) (+ acc (sc word))) 0 scorers)))
|
||||
;; give some bonus for bindings and modules
|
||||
(let ([desc (entry-desc entry)])
|
||||
(if (or (exported-index-desc? desc) (module-path-index-desc? desc))
|
||||
exported-entry-bonus 0))
|
||||
(entry-words entry))))
|
||||
(let ([sc (foldl (lambda (word acc)
|
||||
(+ acc (foldl (lambda (sc acc) (+ acc (sc word)))
|
||||
0 scorers)))
|
||||
0
|
||||
(entry-words entry))])
|
||||
;; give some bonus for bindings and modules
|
||||
(let ([desc (entry-desc entry)])
|
||||
(if (or (exported-index-desc? desc) (module-path-index-desc? desc))
|
||||
(* sc exported-entry-factor)
|
||||
sc)))))
|
||||
|
||||
(define (scored-entry<? x y)
|
||||
(let ([xsc (car x)] [ysc (car y)])
|
||||
|
@ -128,14 +133,7 @@
|
|||
(or (loop (cdr xs) (cdr ys))
|
||||
;; Try string<? so "Foo" still precedes "foo"
|
||||
(string<? (car xs) (car ys)))]
|
||||
[else (string-ci<? (car xs) (car xs))]))])))
|
||||
|
||||
|
||||
(define next-search-results-file
|
||||
(let ([n -1] [tmp (find-system-path 'temp-dir)])
|
||||
(lambda ()
|
||||
(set! n (modulo (add1 n) 10))
|
||||
(build-path tmp (format "search-results-~a.html" n)))))
|
||||
[else (string-ci<? (car xs) (car ys))]))])))
|
||||
|
||||
;; build-itemization : (nonempty-listof entry) -> (listof <stuff>)
|
||||
(define (build-itemization entries)
|
||||
|
|
|
@ -13,7 +13,8 @@ See also @schememodname[browser/external], which requires
|
|||
browser preference is set.
|
||||
|
||||
|
||||
@defproc[(send-url [str string?] [separate-window? any/c #t])
|
||||
@defproc[(send-url [str string?] [separate-window? any/c #t]
|
||||
#:escape [escape? any/c #t])
|
||||
void?]{
|
||||
|
||||
Opens @scheme[str], which represents a URL, in a platform-specific
|
||||
|
@ -22,16 +23,51 @@ manner. For some platforms and configurations, the
|
|||
a new window to display the URL or not.
|
||||
|
||||
Under Windows, @scheme[send-url] normally uses @scheme[shell-execute]
|
||||
to launch a browser. If the URL appears to contain a fragment, it may
|
||||
instead use @exec{ftype htmlfile} to obtain a command-line to run,
|
||||
since @scheme[shell-execute] drops a fragment.
|
||||
to launch a browser. (If the URL appears to contain a fragment, it may
|
||||
use an intermediate redirecting file due to a bug in IE7.)
|
||||
|
||||
Under Mac OS X, @scheme[send-url] runs @exec{osascript} to start the
|
||||
user's chosen browser.
|
||||
|
||||
Under Unix, @scheme[send-url] uses the value of the
|
||||
@scheme[external-browser] parameter to select a browser.}
|
||||
@scheme[external-browser] parameter to select a browser.
|
||||
|
||||
The @scheme[url] string is usually escaped to avoid dangerous shell
|
||||
characters (quotations, dollar signs, backslashes, and non-ASCII).
|
||||
Note that it is a good idea to encode URLs before passing them to this
|
||||
function. Also note that the encoding is meant to make the URL work
|
||||
in shell quotes: URLs can still hold characters like @litchar{#},
|
||||
@litchar{?}, and @litchar{&}, so the @scheme[external-browser] should
|
||||
use quotations.}
|
||||
|
||||
@defproc[(send-url/file [path path-string?] [separate-window? any/c #t]
|
||||
#:fragment [fragment (or/c string? false/c) #f]
|
||||
#:query [query (or/c string? false/c) #f])
|
||||
void?]{
|
||||
|
||||
Similar to @scheme[send-url], but accepts a path to a file to be
|
||||
displayed by the browser. Use this function when you want to display
|
||||
a local file: it takes care of the peculiarities of constructing the
|
||||
correct @litchar{file://} URL, and uses @scheme[send-url] to display
|
||||
the file. If you need to use an anchor fragment or a query string,
|
||||
use the corresponding keyword arguments.}
|
||||
|
||||
@defproc[(send-url/contents [contents string?] [separate-window? any/c #t]
|
||||
#:fragment [fragment (or/c string? false/c) #f]
|
||||
#:query [query (or/c string? false/c) #f]
|
||||
#:delete-at [seconds (or/c number? false/c) #f])
|
||||
void?]{
|
||||
|
||||
Similar to @scheme[send-url/file], but it consumes the contents of a
|
||||
page to show, and displayes it from a temporary file.
|
||||
|
||||
If @scheme[delete-at] is a number, the temporary file is removed after
|
||||
this many seconds. The deletion happens in a thread, so if mzscheme
|
||||
exits before that it will not happen --- when this function is called
|
||||
it scans old generated files (this happens randomly, not on every
|
||||
call) and removes them to avoid cluttering the temporary directory.
|
||||
If @scheme[delete-at] is @scheme[#f], no delayed deletion happens, but
|
||||
old temporary files are still deleted as described above.}
|
||||
|
||||
@defparam[external-browser cmd browser-preference?]{
|
||||
|
||||
|
|
|
@ -8,7 +8,7 @@
|
|||
scheme/promise
|
||||
scheme/port)
|
||||
|
||||
(provide send-url send-url/file
|
||||
(provide send-url send-url/file send-url/contents
|
||||
unix-browser-list browser-preference? external-browser)
|
||||
|
||||
(define separate-by-default?
|
||||
|
@ -77,7 +77,7 @@
|
|||
;; only these characters. This is only for protection when passing arguments
|
||||
;; to subprocesses, it's best to pass properly escaped urls to `send-url'.
|
||||
(define (escape-url url)
|
||||
(regexp-replace* #px"(?:[^[:graph:]]|[\"'`\\\\])" url %escape))
|
||||
(regexp-replace* #px"(?:[^[:graph:]]|[$\"'`\\\\])" url %escape))
|
||||
|
||||
;; send-url : str [bool] -> void
|
||||
(define (send-url url-str [separate-window? separate-by-default?]
|
||||
|
@ -117,6 +117,34 @@
|
|||
path)])
|
||||
(send-url path separate-window? #:escape? #f)))
|
||||
|
||||
;; See the documentation for the `delete-at' argument
|
||||
(define (send-url/contents contents [separate-window? separate-by-default?]
|
||||
#:fragment [fragment #f] #:query [query #f]
|
||||
#:delete-at [delete-at #f])
|
||||
(define tmp-tmpl "plt-sendurl-contents-file-~a.html")
|
||||
(define tmp-rx #rx"^plt-sendurl-contents-file-.*\\.html$")
|
||||
;; The code below will often leave leftovers (for example, plt-help will quit
|
||||
;; before deletion happens), so every once in a while, do a cleanup. This
|
||||
;; can also remove files that were created with no intention for deletion
|
||||
;; (when delete-at is #f), so don't remove files that are less than 15
|
||||
;; minutes old.
|
||||
(when (zero? (random 5))
|
||||
(parameterize ([current-directory (find-system-path 'temp-dir)])
|
||||
(let ([now (current-seconds)])
|
||||
(for ([file (directory-list)]
|
||||
#:when (and (file-exists? file)
|
||||
(regexp-match tmp-rx (path-element->string file))
|
||||
(> (- now (file-or-directory-modify-seconds file))
|
||||
(* 15 60))))
|
||||
;; The temp directory may be shared with other users, so silently
|
||||
;; ignore failures to remove files.
|
||||
(with-handlers ([void void]) (delete-file file))))))
|
||||
(let ([temp (make-temporary-file tmp-tmpl)])
|
||||
(with-output-to-file temp #:exists 'truncate
|
||||
(lambda () (display contents)))
|
||||
(when delete-at (thread (lambda () (sleep delete-at) (delete-file temp))))
|
||||
(send-url/file temp)))
|
||||
|
||||
(define osascript (delay (find-exe "osascript")))
|
||||
(define (send-url/mac url)
|
||||
(browser-run (force osascript) "-e" (format "open location \"~a\"" url)))
|
||||
|
@ -176,45 +204,27 @@
|
|||
;; http://support.microsoft.com/default.aspx/kb/942172
|
||||
;; It seems that the IE7 problem happens either way (`shell-execute' or running
|
||||
;; directly) -- but it also happens with firefox when using `shell-execute'.
|
||||
;; The current solution is to run `ftype http' to find the default browser
|
||||
;; command, if it uses `iexplore.exe', then change it to `explorer.exe', and
|
||||
;; One possible solution is to run `ftype http' to find the default browser
|
||||
;; command, and if it uses `iexplore.exe' then change it to `explorer.exe', and
|
||||
;; run the resulting command directly. This is described at
|
||||
;; http://www.tutorials-win.com/IE/Lauching-HTML/
|
||||
;; Hopefully this works. One question is whether IE6 will still work fine;
|
||||
;; another is other browsers work; and finally, we need to parse the command
|
||||
;; and substitute the url for `%1' (if it appears). If there are other `%'s,
|
||||
;; throw an error so we can hack that in too.
|
||||
;; Oh and it seems that there is no way to get this to work on Vista, the above
|
||||
;; MS page says that the problem is that IE will start a more priviliged one,
|
||||
;; handing over the URL -- which, again, gets the fragment+query stripped
|
||||
;; away...
|
||||
|
||||
(define windows-http-command
|
||||
(delay (let ([out (open-output-string)])
|
||||
(parameterize ([current-output-port out]
|
||||
[current-input-port (open-input-string "")]
|
||||
[current-error-port (open-output-nowhere)])
|
||||
(and (system "ftype http")
|
||||
(cond [(regexp-match #rx"(?:^|\r?\n)?http=([^\r\n]+)\r?\n"
|
||||
(get-output-string out))
|
||||
=> cadr]
|
||||
[else #f]))))))
|
||||
;; But this still fails on Vista, since the problem there is that launching a
|
||||
;; browser with a file:// URL makes it start a more priviliged process, and
|
||||
;; doing that drops the fragment again. So the solution that the code below
|
||||
;; implements is to write and use (via `send-url/contents') a trampoline html
|
||||
;; that redirects to the actual file and fragment.
|
||||
|
||||
(define (send-url/win url)
|
||||
(let ([cmd (force windows-http-command)])
|
||||
(browser-run
|
||||
#:shell #t #:ignore-exit-code #t
|
||||
(cond [(and (or (not cmd)
|
||||
(regexp-match? #px"(?:^|[/\\\\])(?i:iexplore.exe)" cmd))
|
||||
;; IE: try to find exeplorer instead
|
||||
(find-exe "explorer.exe"))
|
||||
=> (lambda (exe) (format "\"~a\" ~a" exe url))]
|
||||
[(not (regexp-match? #rx"%" cmd))
|
||||
(format "~a ~a" cmd url)]
|
||||
[(regexp-match? #rx"%[^1]" cmd)
|
||||
(error 'send-url/win "Unknown browser configuration: ~s\n~a"
|
||||
cmd "*** Please report this as a bug!")]
|
||||
[else (regexp-replace* #rx"%1" cmd url)]))))
|
||||
(if (not (regexp-match? #rx"[#?]" url))
|
||||
(shell-execute #f url "" (current-directory) 'SW_SHOWNORMAL)
|
||||
(send-url/contents
|
||||
(string-append
|
||||
"<html><head><meta http-equiv=\"refresh\" content=\"0;URL="url"\"></head>"
|
||||
"<body>Please go <a href=\""url"\">here</a>.</body></html>")
|
||||
;; starting the browser may take a while, don't remove the file
|
||||
;; immediately (this means that when used via plt-help, these files are
|
||||
;; never removed by a timer)
|
||||
#:delete-at 15)))
|
||||
|
||||
;; Process helper
|
||||
(define (browser-run #:shell [shell? #f] #:ignore-exit-code [nowait? #f] . args)
|
||||
|
|
|
@ -279,9 +279,15 @@
|
|||
|
||||
(define/public (render ds fns ri)
|
||||
(map (lambda (d fn)
|
||||
(define (one) (render-one d ri fn))
|
||||
(when report-output? (printf " [Output to ~a]\n" fn))
|
||||
(with-output-to-file fn #:exists 'truncate/replace
|
||||
(lambda () (render-one d ri fn))))
|
||||
(if fn
|
||||
(with-output-to-file fn #:exists 'truncate/replace one)
|
||||
;; a #f filename means return the contents as a string
|
||||
(let ([o (open-output-string)])
|
||||
(parameterize ([current-output-port o])
|
||||
(one)
|
||||
(get-output-string o)))))
|
||||
ds
|
||||
fns))
|
||||
|
||||
|
|
|
@ -53,23 +53,27 @@
|
|||
(define (xref-index xrefs)
|
||||
(filter
|
||||
values
|
||||
(hash-table-map (collect-info-ext-ht (resolve-info-ci (xrefs-ri xrefs)))
|
||||
(lambda (k v)
|
||||
(and (pair? k)
|
||||
(eq? (car k) 'index-entry)
|
||||
(make-entry (car v)
|
||||
(cadr v)
|
||||
(cadr k)
|
||||
(caddr v)))))))
|
||||
(hash-table-map
|
||||
(collect-info-ext-ht (resolve-info-ci (xrefs-ri xrefs)))
|
||||
(lambda (k v)
|
||||
(and (pair? k)
|
||||
(eq? (car k) 'index-entry)
|
||||
(make-entry (car v) (cadr v) (cadr k) (caddr v)))))))
|
||||
|
||||
(define (xref-render xrefs doc dest-file #:render% [render% (html:render-mixin render%)])
|
||||
;; dest-file can be #f, which will make it return a string holding the
|
||||
;; resulting html
|
||||
(define (xref-render xrefs doc dest-file
|
||||
#:render% [render% (html:render-mixin render%)])
|
||||
(let* ([dest-file (if (string? dest-file) (string->path dest-file) dest-file)]
|
||||
[renderer (new render% [dest-dir (path-only dest-file)])]
|
||||
[ci (send renderer collect (list doc) (list dest-file))])
|
||||
(send renderer transfer-info ci (resolve-info-ci (xrefs-ri xrefs)))
|
||||
(let ([ri (send renderer resolve (list doc) (list dest-file) ci)])
|
||||
(send renderer render (list doc) (list dest-file) ri)
|
||||
(void))))
|
||||
[renderer (new render% [dest-dir (and dest-file (path-only dest-file))]
|
||||
[css-path 'inline])]
|
||||
[ci (send renderer collect (list doc) (list dest-file))]
|
||||
[_ (send renderer transfer-info ci (resolve-info-ci (xrefs-ri xrefs)))]
|
||||
[ri (send renderer resolve (list doc) (list dest-file) ci)]
|
||||
[xs (send renderer render (list doc) (list dest-file) ri)])
|
||||
(if dest-file
|
||||
(void)
|
||||
(car xs))))
|
||||
|
||||
;; Returns (values <tag-or-#f> <form?>)
|
||||
(define xref-binding-tag
|
||||
|
|
Loading…
Reference in New Issue
Block a user