diff --git a/scribble-doc/scribblings/scribble/manual.scrbl b/scribble-doc/scribblings/scribble/manual.scrbl index 653a4932d2..edec450d12 100644 --- a/scribble-doc/scribblings/scribble/manual.scrbl +++ b/scribble-doc/scribblings/scribble/manual.scrbl @@ -249,7 +249,9 @@ definition in the reference manual. Like other forms defined via @racket[define-code], @racket[racketblock] expands identifiers that are bound as -@tech{element transformers}. +@tech{element transformers}. Also, since @racket[racketblock] uses +@racket[to-paragraph], the @racket['display-string] syntax property on +any form can supply a string for the typeset version of the form. An @racket[#:escape] clause specifies an identifier to escape back to an expression that produces an @racket[element]. By default, @@ -1039,7 +1041,8 @@ Examples: (code:line #:link-target? link-target?-expr)] [maybe-id code:blank (code:line #:id id) - (code:line #:id [id id-expr])] + (code:line #:id [id id-expr]) + (code:line #:id [(id ...) ids-expr])] [maybe-literals code:blank (code:line #:literals (literal-id ...))] [maybe-grammar code:blank @@ -1050,30 +1053,47 @@ Examples: Produces a sequence of flow elements (encapsulated in a @racket[splice]) to document a syntatic form named by @racket[id] (or the -result of @racket[id-expr]) whose syntax is described by +result of @racket[id-expr] or @racket[ids-expr]). +The documented form's syntax is described by @racket[form-datum]. If no @racket[#:id] is used to specify -@racket[id], then @racket[form-datum] must have the form @racket[(id +@racket[id]s, then @racket[form-datum] must have the form @racket[(id . _datum)]. If @racket[#:kind kind-content-expr] is supplied, it is used in the same way as for @racket[defproc], but the default kind is @racket["syntax"]. -If @racket[#:id [id id-expr]] is supplied, then @racket[id] is the -identifier as it appears in the @racket[form-datum] (to be replaced by -a defining instance), and @racket[id-expr] produces the identifier to -be documented. This split between @racket[id] and @racket[id-expr] -roles is useful for functional abstraction of @racket[defform]. - Unless @racket[link-target?-expr] is specified and produces @racket[#f], -the @racket[id] (or result of @racket[id-expr]) is indexed, and it is +the @racket[id] (or result of @racket[id-expr] or @racket[ids-expr]) is indexed, and it is also registered so that @racket[racket]-typeset uses of the identifier -(with the same for-label binding) are hyperlinked to this +(with the same @racket[for-label] binding) are hyperlinked to this documentation. The @racket[defmodule] or @racket[declare-exporting] requirements, as well as the binding requirements for @racket[id] (or result of @racket[id-expr]), are the same as for @racket[defproc]. +If @racket[#:id [id id-expr]] is supplied, then @racket[id] is the +identifier as it appears in the @racket[form-datum], and @racket[id-expr] produces the identifier to +be documented (i.e., one with a @racket[for-label] binding). The +@racket[id] in @racket[form-datum] is replaced with a defining +typeset form of the identifier from @racket[id-expr]. This +split between @racket[id] and @racket[id-expr] roles is useful for +functional abstraction of @racket[defform]. Even more generally, the +name to show as defined in @racket[form-datum] can be different than +the symbolic part of @racket[id-expr]'s result, because a +@racket['display-string] syntax property can provide alternate +text for typesetting; see @racket[racketblock] for more information. + +If @racket[#:id [(id ...) ids-expr]] is supplied, then +@racket[ids-expr] should produce a list of identifiers, one for each +@racket[id] listed. Each @racket[id] is replaced in +@racket[form-datum] with the corresponding defining instance from +@racket[ids-expr]. At least one of the @racket[id]s must appear in +@racket[form-datum], but they need not all appear; all identifiers +listed by @racket[ids-expr] will still be documented and linked to some +@racket[id] that does appear (as long as @racket[link-target?-expr] +does not produce @racket[#f]). + The @tech{decode}d @racket[pre-flow] documents the form. In this description, a reference to any identifier in @racket[form-datum] via @racket[racket], @racket[racketblock], @|etc| is typeset as a sub-form @@ -1162,6 +1182,9 @@ Examples: the factory will be named. Each of the @racket[factory-component] clauses adds an additional ingredient to the sandwich pipeline. }] + + @history[#:changed "1.63" @elem{Added support for multiple + @racket[id]s after @racket[#:id].}] } @defform[(defform* options [form-datum ...+] diff --git a/scribble-doc/scribblings/scribble/scheme.scrbl b/scribble-doc/scribblings/scribble/scheme.scrbl index 3e295363de..01f04f637e 100644 --- a/scribble-doc/scribblings/scribble/scheme.scrbl +++ b/scribble-doc/scribblings/scribble/scheme.scrbl @@ -72,6 +72,10 @@ In addition, the given @racket[v] can contain @racket[var-id], structure type for details), or it can contain @racket[element] structures that are used directly in the output. +If a syntax object within @racket[v] has the @racket['display-string] +syntax property on any form can supply a string to use for the typeset +form, instead of the way it would typeset otherwise. + If @racket[expr?] is true, then @racket[v] is rendered in expression style, much like @racket[print] with the @racket[print-as-expression] parameter set to @racket[#t]. In that case, @racket[for-label] diff --git a/scribble-lib/info.rkt b/scribble-lib/info.rkt index 59a6a6608f..74f39ae32f 100644 --- a/scribble-lib/info.rkt +++ b/scribble-lib/info.rkt @@ -21,7 +21,7 @@ (define pkg-authors '(mflatt eli)) -(define version "1.62") +(define version "1.63") (define license '((Apache-2.0 OR MIT) diff --git a/scribble-lib/scribble/private/manual-bind.rkt b/scribble-lib/scribble/private/manual-bind.rkt index 1ed96ce4b6..f542688e1a 100644 --- a/scribble-lib/scribble/private/manual-bind.rkt +++ b/scribble-lib/scribble/private/manual-bind.rkt @@ -2,7 +2,8 @@ (require racket/string racket/format "../struct.rkt" - "../scheme.rkt" + "../racket.rkt" + (submod "../racket.rkt" id-element) "../search.rkt" "../basic.rkt" "../manual-struct.rkt" @@ -89,13 +90,20 @@ (lambda (render part ri) (proc (or (get-exporting-libraries render part ri) null))))) -(define (definition-site name stx-id form?) +(define (definition-site name stx-id form? [display-string #f]) (define sig (current-signature)) (define (gen defn?) (if sig (*sig-elem #:defn? defn? (sig-id sig) name) ((if defn? annote-exporting-library values) - (to-element #:defn? defn? (make-just-context name stx-id))))) + (if display-string + (make-element + symbol-color + (make-id-element (datum->syntax stx-id name) + display-string + #t + #:unlinked-ok? #t)) + (to-element #:defn? defn? (make-just-context name stx-id)))))) (values (gen #t) (gen #f))) (define checkers (make-hash)) diff --git a/scribble-lib/scribble/private/manual-form.rkt b/scribble-lib/scribble/private/manual-form.rkt index 17c6879418..a1306759f4 100644 --- a/scribble-lib/scribble/private/manual-form.rkt +++ b/scribble-lib/scribble/private/manual-form.rkt @@ -1,7 +1,8 @@ #lang racket/base (require "../decode.rkt" "../struct.rkt" - "../scheme.rkt" + "../racket.rkt" + (submod "../racket.rkt" id-element) "../basic.rkt" "../manual-struct.rkt" "qsloc.rkt" @@ -37,14 +38,20 @@ (define-splicing-syntax-class id-kw #:description "#:id keyword" - (pattern (~seq #:id [defined-id:id defined-id-expr])) - (pattern (~seq #:id defined-id:id) - #:with defined-id-expr #'(quote-syntax defined-id)) + (pattern (~seq #:id [(defined-id:id ...) defined-id-expr])) + (pattern (~seq #:id [one-defined-id:id defined-id-expr]) + #:with (defined-id ...) #'(one-defined-id)) + (pattern (~seq #:id one-defined-id:id) + #:with defined-id-expr #'(quote-syntax one-defined-id) + #:with (defined-id ...) #'(one-defined-id)) (pattern (~seq #:id [#f #f]) - #:with defined-id #'#f + #:with (defined-id ...) #'(#f) + #:with defined-id-expr #'#f) + (pattern (~seq #:id [(#f) #f]) + #:with (defined-id ...) #'(#f) #:with defined-id-expr #'#f) (pattern (~seq) - #:with defined-id #'#f + #:with (defined-id ...) #'(#f) #:with defined-id-expr #'#f)) (define-splicing-syntax-class link-target?-kw @@ -82,42 +89,56 @@ g:grammar c:contracts-kw desc:expr ...) - (with-syntax* ([defined-id (if (syntax-e #'d.defined-id) - #'d.defined-id - (syntax-case #'spec () - [(spec-id . _) #'spec-id]))] + (with-syntax* ([(defined-id ...) (if (ormap syntax-e (syntax->list #'(d.defined-id ...))) + #'(d.defined-id ...) + (syntax-case #'spec () + [(spec-id . _) #'(spec-id)]))] [defined-id-expr (if (syntax-e #'d.defined-id-expr) #'d.defined-id-expr - #'(quote-syntax defined-id))] - [(new-spec ...) - (for/list ([spec (in-list (syntax->list #'(spec spec1 ...)))]) - (let loop ([spec spec]) - (if (and (identifier? spec) - (free-identifier=? spec #'defined-id)) - (datum->syntax #'here '(unsyntax x) spec spec) - (syntax-case spec () - [(a . b) - (datum->syntax spec - (cons (loop #'a) (loop #'b)) - spec - spec)] - [_ spec]))))]) - #'(with-togetherable-racket-variables - (l.lit ...) - ([form [defined-id spec]] [form [defined-id spec1]] ... - [non-term (g.non-term-id g.non-term-form ...)] ...) - (*defforms k.kind lt.expr defined-id-expr - '(spec spec1 ...) - (list (lambda (x) (racketblock0/form new-spec)) ...) - '((g.non-term-id g.non-term-form ...) ...) - (list (list (lambda () (racket g.non-term-id)) - (lambda () (racketblock0/form g.non-term-form)) - ...) - ...) - (list (list (lambda () (racket c.contract-nonterm)) - (lambda () (racketblock0 c.contract-expr))) - ...) - (lambda () (list desc ...)))))])) + ;; there will be one `defined-id` + #'(quote-syntax defined-id ...))] + [(x ...) (generate-temporaries #'(defined-id ...))]) + (define-values (add-unused is-used?s) + (make-unused-name-adder #'spec (syntax->list #'(defined-id ...)) (syntax->list #'(x ...)))) + (with-syntax* ([(is-used? ...) is-used?s] + [(new-spec ...) + (let ([defined-ids (syntax->list #'(defined-id ...))] + [xs (syntax->list #'(x ...))]) + (for/list ([spec (in-list (syntax->list #'(spec spec1 ...)))] + [pos (in-naturals)]) + (define add-unused-now (if (eqv? pos 0) + add-unused + (lambda (x) x))) + (let loop ([spec spec]) + (or (and (identifier? spec) + (for/or ([defined-id (in-list defined-ids)] + [x (in-list xs)]) + (and (free-identifier=? spec defined-id) + (datum->syntax #'here `(unsyntax ,(add-unused x)) spec spec)))) + (syntax-case spec () + [(a . b) + (datum->syntax spec + (cons (loop #'a) (loop #'b)) + spec + spec)] + [_ spec])))))]) + #'(with-togetherable-racket-variables + (l.lit ...) + ([form [(defined-id ...) spec]] [form [(defined-id ...) spec1]] ... + [non-term (g.non-term-id g.non-term-form ...)] ...) + (*defforms k.kind lt.expr defined-id-expr + '(is-used? ...) + '(spec spec1 ...) + (list (lambda (x ...) (racketblock0/form new-spec)) ...) + '((g.non-term-id g.non-term-form ...) ...) + (list (list (lambda () (racket g.non-term-id)) + (lambda () (racketblock0/form g.non-term-form)) + ...) + ...) + (list (list (lambda () (racket c.contract-nonterm)) + (lambda () (racketblock0 c.contract-expr))) + ...) + (lambda () (list desc ...))))))])) (define-syntax (defform* stx) (syntax-parse stx @@ -126,7 +147,7 @@ (syntax/loc stx (defform*/subs #:kind k.kind #:link-target? lt.expr - #:id [d.defined-id d.defined-id-expr] + #:id [(d.defined-id ...) d.defined-id-expr] #:literals (l.lit ...) [spec ...] subs.g #:contracts c.cs desc ...))])) @@ -137,7 +158,7 @@ (syntax/loc stx (defform*/subs #:kind k.kind #:link-target? lt.expr - #:id [d.defined-id d.defined-id-expr] + #:id [(d.defined-id ...) d.defined-id-expr] #:literals (l.lit ...) [spec] subs.g #:contracts c.cs desc ...))])) @@ -147,7 +168,7 @@ (syntax/loc stx (defform*/subs #:kind k.kind #:link-target? lt.expr - #:id [d.defined-id d.defined-id-expr] + #:id [(d.defined-id ...) d.defined-id-expr] #:literals (l.lit ...) [spec] subs #:contracts c.cs desc ...))])) @@ -160,6 +181,7 @@ ([form/none spec] [non-term (subs.g.non-term-id subs.g.non-term-form ...)] ...) (*defforms k.kind lt.expr #f + '(#t) '(spec) (list (lambda (ignored) (racketblock0/form spec))) '((subs.g.non-term-id subs.g.non-term-form ...) ...) @@ -187,6 +209,7 @@ () () (*defforms k.kind lt.expr (quote-syntax/loc spec-id) + '(#t) '(spec-id) (list (lambda (x) (make-omitable-paragraph (list x)))) null @@ -305,9 +328,10 @@ (define (meta-symbol? s) (memq s '(... ...+ ?))) -(define (defform-site kw-id #:kind [kind "syntax"]) +(define (defform-site kw-id #:kind [kind "syntax"] #:is-used? [is-used? #t]) (define target-maker (id-to-form-target-maker kw-id #t)) - (define-values (content ref-content) (definition-site (syntax-e kw-id) kw-id #t)) + (define str (syntax-property kw-id 'display-string)) + (define-values (content ref-content) (definition-site (syntax-e kw-id) kw-id #t str)) (if target-maker (target-maker content @@ -316,7 +340,7 @@ #f (if kw-id (make-index-element - #f content tag + #f (if is-used? content null) tag (list (datum-intern-literal (symbol->string (syntax-e kw-id)))) (list ref-content) (with-exporting-libraries @@ -327,10 +351,16 @@ content) tag ref-content))) - content)) + (if is-used? + content + null))) -(define (*defforms kind link? kw-id forms form-procs subs sub-procs contract-procs content-thunk) +(define (*defforms kind link? kw-id/s is-used?s forms form-procs subs sub-procs contract-procs content-thunk) (define kind* (or kind "syntax")) + (define (map-kw-id/s kw/ids is-used?s proc) + (if (list? kw/ids) + (map proc kw-id/s is-used?s) + (list (proc kw-id/s #t)))) (parameterize ([current-meta-list '(... ...+)]) (make-box-splice (cons @@ -346,16 +376,21 @@ (list ((if (zero? i) (add-background-label kind*) values) (list - ((or form-proc + (apply + (or form-proc (lambda (x) (make-omitable-paragraph (list (to-element `(,x . ,(cdr form))))))) - (and kw-id - (if (eq? form (car forms)) - (if link? - (defform-site kw-id #:kind kind*) - (to-element #:defn? #t kw-id)) - (to-element #:defn? #t kw-id)))))))) + (if kw-id/s + (map-kw-id/s + kw-id/s + is-used?s + (lambda (kw-id is-used?) + (define linking? (and link? (eq? form (car forms)))) + (if linking? + (defform-site kw-id #:kind kind* #:is-used? is-used?) + (to-element #:defn? #t kw-id)))) + (list #f))))))) (if (null? sub-procs) null (list (list flow-empty-line) @@ -451,3 +486,28 @@ (to-flow ":") flow-spacer (make-flow (list ((cadr c)))))))))))))) + +(define-for-syntax (make-unused-name-adder spec defined-ids xs) + (define unused xs) + (let loop ([spec spec]) + (cond + [(null? unused) (void)] + [(identifier? spec) + (for ([defined-id (in-list defined-ids)] + [x (in-list xs)]) + (when (free-identifier=? spec defined-id) + (set! unused (remq x unused))))] + [(syntax? spec) + (loop (syntax-e spec))] + [(pair? spec) + (loop (car spec)) + (loop (cdr spec))])) + (values + (lambda (x) + (if (null? unused) + x + (let ([e `(make-element #f (list ,x ,@unused))]) + (set! unused null) + e))) + (for/list ([x (in-list xs)]) + (not (memq x unused))))) diff --git a/scribble-lib/scribble/private/manual-vars.rkt b/scribble-lib/scribble/private/manual-vars.rkt index a707d8270e..ba23c695f3 100644 --- a/scribble-lib/scribble/private/manual-vars.rkt +++ b/scribble-lib/scribble/private/manual-vars.rkt @@ -116,14 +116,13 @@ (do-proc (car s-exp)))))]) (do-proc s-exp))] [(form form/none form/maybe non-term) - (define skip-id (case (syntax-e kind) - [(form) - (syntax-case s-exp () - [(defined-id actual-s-exp) (let ([id #'defined-id]) - (and (identifier? id) - id))] - [_ #f])] - [else #f])) + (define skip-ids (case (syntax-e kind) + [(form) + (syntax-parse s-exp + [((defined-id:id ...) actual-s-exp) (syntax->list #'(defined-id ...))] + [(defined-id:id actual-s-exp) (list #'defined-id)] + [_ null])] + [else null])) (let loop ([form (case (syntax-e kind) [(form) (syntax-case s-exp () @@ -135,8 +134,8 @@ [(#t (id . form)) #'form])] [(non-term) s-exp])]) (if (identifier? form) - (unless (or (and skip-id - (free-identifier=? skip-id form)) + (unless (or (for/or ([skip-id (in-list skip-ids)]) + (free-identifier=? skip-id form)) (eq? (syntax-e form) '...) (eq? (syntax-e form) '...+) (eq? (syntax-e form) 'code:line)