From 5f37b5e912f099b1558b7a40ee950b3342a2dfa3 Mon Sep 17 00:00:00 2001 From: Matthew Flatt Date: Sat, 26 May 2007 06:31:34 +0000 Subject: [PATCH] continued work on the guide svn: r6338 --- collects/scribble/base-render.ss | 1 - collects/scribble/eval.ss | 31 +++-- collects/scribble/html-render.ss | 107 +++++++++++++----- collects/scribble/scheme.ss | 72 +++++++++--- collects/scribble/scribble.css | 2 +- collects/scribblings/guide/byte-strings.scrbl | 75 ++++++++++++ collects/scribblings/guide/char-strings.scrbl | 43 +++++-- collects/scribblings/guide/chars.scrbl | 6 +- collects/scribblings/guide/data.scrbl | 3 +- collects/scribblings/guide/guide.scrbl | 34 +----- collects/scribblings/guide/vectors.scrbl | 58 ++++++++++ collects/scribblings/reference/bytes.scrbl | 2 +- collects/scribblings/reference/read.scrbl | 2 +- 13 files changed, 335 insertions(+), 101 deletions(-) create mode 100644 collects/scribblings/guide/byte-strings.scrbl create mode 100644 collects/scribblings/guide/vectors.scrbl diff --git a/collects/scribble/base-render.ss b/collects/scribble/base-render.ss index b7e5ac2c3e..85741ba45f 100644 --- a/collects/scribble/base-render.ss +++ b/collects/scribble/base-render.ss @@ -278,7 +278,6 @@ (append (format-number number (list - "." (make-element 'hspace '(" ")))) (part-title-content part)) `(part ,(part-tag part)))))))) diff --git a/collects/scribble/eval.ss b/collects/scribble/eval.ss index eeeddd87e6..8244737cf3 100644 --- a/collects/scribble/eval.ss +++ b/collects/scribble/eval.ss @@ -122,19 +122,36 @@ (with-handlers ([exn? (lambda (e) (exn-message e))]) (cons (let ([v (do-plain-eval s #t)]) - (copy-value v)) + (copy-value v (make-hash-table))) (get-output-string o)))))])) + (define (install ht v v2) + (hash-table-put! ht v v2) + v2) + ;; Since we evaluate everything in an interaction before we typeset, ;; copy each value to avoid side-effects. - (define (copy-value v) + (define (copy-value v ht) (cond - [(string? v) (string-copy v)] - [(bytes? v) (bytes-copy v)] - [(pair? v) (cons (copy-value (car v)) - (copy-value (cdr v)))] + [(and v (hash-table-get ht v #f)) + => (lambda (v) v)] + [(string? v) (install ht v (string-copy v))] + [(bytes? v) (install ht v (bytes-copy v))] + [(pair? v) (let ([p (cons #f #f)]) + (hash-table-put! ht v p) + (set-car! p (copy-value (car v) ht)) + (set-cdr! p (copy-value (cdr v) ht)) + p)] + [(vector? v) (let ([v2 (make-vector (vector-length v))]) + (hash-table-put! ht v v2) + (let loop ([i (vector-length v2)]) + (unless (zero? i) + (let ([i (sub1 i)]) + (vector-set! v2 i (copy-value (vector-ref v i) ht)) + (loop i)))) + v2)] [else v])) - + (define (strip-comments s) (cond [(and (pair? s) diff --git a/collects/scribble/html-render.ss b/collects/scribble/html-render.ss index 2edcd09ed1..06f4c5711a 100644 --- a/collects/scribble/html-render.ss +++ b/collects/scribble/html-render.ss @@ -92,7 +92,7 @@ [(0) 'h2] [(1) 'h3] [else 'h4]) - ,@(format-number number '("." (tt nbsp))) + ,@(format-number number '((tt nbsp))) ,@(if (part-tag d) `((a ((name ,(format "~a" `(part ,(part-tag d))))))) null) @@ -186,6 +186,7 @@ [(boxed) '((width "100%") (bgcolor "lightgray"))] [(centered) '((align "center"))] [(at-right) '((align "right"))] + [(at-left) '((align "left"))] [else null])) ,@(map (lambda (flows) `(tr ,@(map (lambda (d a) @@ -278,6 +279,8 @@ ds fns)) + (define contents-content '("contents")) + (define index-content '("index")) (define prev-content '(larr " prev")) (define up-content '("up")) (define next-content '("next " rarr)) @@ -299,9 +302,12 @@ (and (pair? (cdr l)) (cadr l)))] [else (loop (cdr l) (car l))])))) + + (define/private (part-parent d) + (collected-info-parent (part-collected-info d))) (define/private (navigation d ht) - (let ([parent (collected-info-parent (part-collected-info d))]) + (let ([parent (part-parent d)]) (let*-values ([(prev next) (find-siblings d)] [(prev) (if prev (let loop ([prev prev]) @@ -322,39 +328,78 @@ (let-values ([(prev next) (find-siblings parent)]) next)] - [else next])]) - (render-table (make-table - 'at-right - (list - (list - (make-flow - (list - (make-paragraph - (list - (if parent + [else next])] + [(index) (let loop ([d d]) + (let ([p (part-parent d)]) + (if p + (loop p) + (let ([subs (part-parts d)]) + (and (pair? subs) + (let ([d (car (last-pair subs))]) + (and (equal? '("Index") (part-title-content d)) + d)))))))]) + `(,@(render-table (make-table + 'at-left + (list + (cons + (make-flow + (list + (make-paragraph + (list (make-element - (make-target-url (if prev - (derive-filename prev) - "index.html")) + (if parent + (make-target-url "index.html") + "nonavigation") + contents-content))))) + (if index + (list + (make-flow + (list + (make-paragraph + (list + 'nbsp + (if (eq? d index) + (make-element + "nonavigation" + index-content) + (make-link-element + #f + index-content + `(part ,(part-tag index))))))))) + null)))) + d ht) + ,@(render-table (make-table + 'at-right + (list + (list + (make-flow + (list + (make-paragraph + (list + (make-element + (if parent + (make-target-url (if prev + (derive-filename prev) + "index.html")) + "nonavigation") prev-content) - "") - sep-element - (if parent + sep-element (make-element - (make-target-url - (if (toc-part? parent) - (derive-filename parent) - "index.html")) + (if parent + (make-target-url + (if (toc-part? parent) + (derive-filename parent) + "index.html")) + "nonavigation") up-content) - "") - sep-element - (make-element - (if next - (make-target-url (derive-filename next)) - "nonavigation") - next-content)))))))) - d - ht)))) + sep-element + (make-element + (if next + (make-target-url (derive-filename next)) + "nonavigation") + next-content)))))))) + d + ht))))) (define/override (render-part d ht) (let ([number (collected-info-number (part-collected-info d))]) diff --git a/collects/scribble/scheme.ss b/collects/scribble/scheme.ss index 453a19640c..afc858a47c 100644 --- a/collects/scribble/scheme.ss +++ b/collects/scribble/scheme.ss @@ -200,15 +200,21 @@ (convert-infix c quote-depth)) => (lambda (converted) ((loop init-line! quote-depth) converted))] - [(pair? (syntax-e c)) + [(or (pair? (syntax-e c)) + (vector? (syntax-e c))) (let* ([sh (or (syntax-property c 'paren-shape) #\()] + [quote-depth (if (vector? (syntax-e c)) + +inf.0 + quote-depth)] [p-color (if (positive? quote-depth) value-color (if (eq? sh #\?) opt-color paren-color))]) (advance c init-line!) + (when (vector? (syntax-e c)) + (out (format "#~a" (vector-length (syntax-e c))) p-color)) (out (case sh [(#\[ #\?) "["] [(#\{) "{"] @@ -216,7 +222,9 @@ p-color) (set! src-col (+ src-col 1)) (hash-table-put! col-map src-col dest-col) - (let lloop ([l c]) + (let lloop ([l (if (vector? (syntax-e c)) + (vector->short-list (syntax-e c) syntax-e) + c)]) (cond [(and (syntax? l) (pair? (syntax-e l))) @@ -357,6 +365,29 @@ (define syntax-ize-hook (make-parameter (lambda (v col) #f))) + (define (vector->short-list v extract) + (let ([l (vector->list v)]) + (reverse (list-tail + (reverse l) + (- (vector-length v) + (let loop ([i (sub1 (vector-length v))]) + (cond + [(zero? i) 1] + [(eq? (extract (vector-ref v i)) + (extract (vector-ref v (sub1 i)))) + (loop (sub1 i))] + [else (add1 i)]))))))) + + (define (short-list->vector v l) + (list->vector + (let ([n (length l)]) + (if (n . < . (vector-length v)) + (reverse (let loop ([r (reverse l)][i (- (vector-length v) n)]) + (if (zero? i) + r + (loop (cons (car r) r) (sub1 i))))) + l)))) + (define (syntax-ize v col) (cond [((syntax-ize-hook) v col) @@ -370,20 +401,29 @@ c) (list #f 1 col (+ 1 col) (+ 1 (syntax-span c)))))] - [(list? v) - (let ([l (let loop ([col (+ col 1)] - [v v]) - (if (null? v) - null - (let ([i (syntax-ize (car v) col)]) - (cons i - (loop (+ col 1 (syntax-span i)) (cdr v))))))]) - (datum->syntax-object #f - l - (list #f 1 col (+ 1 col) - (+ 2 - (sub1 (length l)) - (apply + (map syntax-span l))))))] + [(or (list? v) + (vector? v)) + (let* ([vec-sz (if (vector? v) + (+ 1 (string-length (format "~a" (vector-length v)))) + 0)]) + (let ([l (let loop ([col (+ col 1 vec-sz)] + [v (if (vector? v) + (vector->short-list v values) + v)]) + (if (null? v) + null + (let ([i (syntax-ize (car v) col)]) + (cons i + (loop (+ col 1 (syntax-span i)) (cdr v))))))]) + (datum->syntax-object #f + (if (vector? v) + (short-list->vector v l) + l) + (list #f 1 col (+ 1 col) + (+ 2 + vec-sz + (sub1 (length l)) + (apply + (map syntax-span l)))))))] [(pair? v) (let* ([a (syntax-ize (car v) (+ col 1))] [sep (if (pair? (cdr v)) 0 3)] diff --git a/collects/scribble/scribble.css b/collects/scribble/scribble.css index 28db2160c2..4641e4d937 100644 --- a/collects/scribble/scribble.css +++ b/collects/scribble/scribble.css @@ -219,7 +219,7 @@ } .nonavigation { - color: gray; + color: #EEEEEE; } .disable { diff --git a/collects/scribblings/guide/byte-strings.scrbl b/collects/scribblings/guide/byte-strings.scrbl new file mode 100644 index 0000000000..f658ff29c9 --- /dev/null +++ b/collects/scribblings/guide/byte-strings.scrbl @@ -0,0 +1,75 @@ +#reader(lib "docreader.ss" "scribble") +@require[(lib "manual.ss" "scribble")] +@require[(lib "eval.ss" "scribble")] +@require["guide-utils.ss"] + +@title[#:tag "bytes"]{Bytes and Byte Strings} + +A @defterm{byte} is an inexact integer between @scheme[0] and +@scheme[255], inclusive. The @scheme[byte?] predicate recognizes +numbers that represent bytes. + +@examples[ +(byte? 0) +(byte? 256) +] + +A @defterm{byte string} is similar to a string---see +@secref["strings"]---but its content is a sequence of bytes instead of +characters. Byte strings can be used in applications that process pure +ASCII instead of Unicode text. The printed and form of a byte string +supports such uses in particular, because a byte string prints like +the ASCII decoding of the byte string, but prefixed with a +@schemefont{#}. Unprintable ASCII characters or non-ASCII bytes in the +byte string are written with octal notation. + +@refdetails["mz:parse-string"]{the syntax of byte strings} + +@examples[ +#"Apple" +(bytes-ref #"Apple" 0) +(make-bytes 3 65) +(define b (make-bytes 2 0)) +b +(bytes-set! b 0 1) +(bytes-set! b 1 255) +b +] + +The @scheme[display] form of a byte string writes its raw bytes to the +current output port (see @secref["output"]). Technically, +@scheme[display] of a normal (i.e,. character) string prints the UTF-8 +encoding of the string to the current output port, since output is +ultimately defined in terms of bytes; @scheme[display] of a byte +string, however, writes the raw bytes with no encoding. Along the same +lines, when this documentation shows output, it technically shows the +UTF-8-decoded form of the output. + +@examples[ +(display #"Apple") +(eval:alts (code:line (display #, @schemevalfont{"\316\273"}) (code:comment #, @t{same as @scheme["\316\273"]})) + (display "\316\273")) +(code:line (display #"\316\273") (code:comment #, @t{UTF-8 encoding of @elem["\u03BB"]})) +] + +For explicitly converting between strings and byte strings, Scheme +supports three kinds of encodings directly: UTF-8, Latin-1, and the +current locale's encoding. General facilities for byte-to-byte +conversions (especially to and from UTF-8) fill the gap to support +arbitrary string encodings. + +@examples[ +(bytes->string/utf-8 #"\316\273") +(bytes->string/latin-1 #"\316\273") +(code:line + (parameterize ([current-locale "C"]) (code:comment #, @elem{C locale supports ASCII,}) + (bytes->string/locale #"\316\273")) (code:comment #, @elem{only, so...})) +(let ([cvt (bytes-open-converter "cp1253" (code:comment #, @elem{Greek code page}) + "UTF-8")] + [dest (make-bytes 2)]) + (bytes-convert cvt #"\353" 0 1 dest) + (bytes-close-converter cvt) + (bytes->string/utf-8 dest)) +] + +@refdetails["mz:bytestrings"]{byte strings and byte-string procedures} diff --git a/collects/scribblings/guide/char-strings.scrbl b/collects/scribblings/guide/char-strings.scrbl index f70097b282..7569366bab 100644 --- a/collects/scribblings/guide/char-strings.scrbl +++ b/collects/scribblings/guide/char-strings.scrbl @@ -3,7 +3,7 @@ @require[(lib "eval.ss" "scribble")] @require["guide-utils.ss"] -@title{Strings (Unicode)} +@title[#:tag "strings"]{Strings (Unicode)} A @defterm{string} is a fixed-length array of @seclink["characters"]{characters}. It prints using doublequotes, @@ -18,8 +18,8 @@ shown with @schemefont["\\u"] when the string is printed. @refdetails["mz:parse-string"]{the syntax of strings} The @scheme[display] procedure directly writes the characters of a -string to the current output stream, in contrast to the -string-constant syntax used to print a string result. +string to the current output port (see @secref["output"]), in contrast +to the string-constant syntax used to print a string result. @examples[ "Apple" @@ -30,19 +30,42 @@ string-constant syntax used to print a string result. (eval:alts (display #, @schemevalfont{"\u03BB"}) (display "\u03BB")) ] -A string can be mutable or immutable; strings written as constant +A string can be mutable or immutable; strings written directly as expressions are immutable, but most other strings are mutable. The -@scheme[string] procedure creates a mutable string given content -characters. The @scheme[string-ref] procedure accesses a character -from a string (with 0-based indexing); the @scheme[string-set!] -procedure changes a character in a mutable string. +@scheme[make-string] procedure creates a mutable string given a length +and optional fill character. The @scheme[string-ref] procedure +accesses a character from a string (with 0-based indexing); the +@scheme[string-set!] procedure changes a character in a mutable +string. @examples[ (string-ref "Apple" 0) -(define s (string #\A #\p #\p #\l #\e)) +(define s (make-string 5 #\.)) s -(string-set! s 3 #\u03BB) +(string-set! s 2 #\u03BB) s ] +String ordering and case operations are generally +@defterm{locale-independent}; that is, they work the same for all +users. A few @defterm{locale-dependent} operations are provided that +allow the way that strings are case-folded and sorted to depend on the +end-user's locale. If you're sorting strings, for example, use +@scheme[stringvector] and @scheme[vector->list]; such conversions are +particularly useful in combination with predefined procedures on +lists. When allocating extra lists seems too expensive, use consider +using looping forms like @scheme[fold-for], which recognize vectors as +well as lists. + +@examples[ +(list->vector (map string-titlecase + (vector->list #("three" "blind" "mice")))) +] + +@refdetails["mz:vectors"]{vectors and vector procedures} diff --git a/collects/scribblings/reference/bytes.scrbl b/collects/scribblings/reference/bytes.scrbl index a313bd2509..9aa39483b1 100644 --- a/collects/scribblings/reference/bytes.scrbl +++ b/collects/scribblings/reference/bytes.scrbl @@ -1,7 +1,7 @@ #reader(lib "docreader.ss" "scribble") @require["mz.ss"] -@title[#:tag "bytestrings"]{Byte Strings} +@title[#:tag "mz:bytestrings"]{Byte Strings} A @pidefterm{byte string} is a fixed-length arary of bytes. A @pidefterm{byte} is an exact integer between @scheme[0] and diff --git a/collects/scribblings/reference/read.scrbl b/collects/scribblings/reference/read.scrbl index 14ab6808df..b56c1a21ca 100644 --- a/collects/scribblings/reference/read.scrbl +++ b/collects/scribblings/reference/read.scrbl @@ -430,7 +430,7 @@ constant, the @exnraise[exn:fail:read]. @index['("byte strings" "parsing")]{A} string constant preceded by @litchar{#} is parsed as a byte-string. (That is, @as-index{@litchar{#"}} starts -a byte-string literal.) See @secref["byte-strings"] for +a byte-string literal.) See @secref["mz:bytestrings"] for information on byte strings. Byte string constants support the same escape sequences as character strings, except @litchar["\\u"] and @litchar["\\U"].