make `detect-paragraphs` work more intuitively

pull/58/head
Matthew Butterick 10 years ago
parent afb03ccf18
commit bb072a8a9a

@ -351,9 +351,10 @@
[else (list (make-txexpr tag empty elems))])) ; otherwise wrap in p tag [else (list (make-txexpr tag empty elems))])) ; otherwise wrap in p tag
(let ([elements (prep-paragraph-flow elements)]) (let ([elements (prep-paragraph-flow elements)])
(if (ormap my-paragraph-break? elements) ; need this condition to prevent infinite recursion (define explicit-or-implicit-paragraph-break? (λ(x) (or (my-paragraph-break? x) (block-txexpr? x))))
;; use append-map rather than map to permit return of multiple elements (if (ormap explicit-or-implicit-paragraph-break? elements) ; need this condition to prevent infinite recursion
(append-map wrap-paragraph (filter-split elements my-paragraph-break?)) ; split into ¶¶ ;; use append-map on wrap-paragraph rather than map to permit return of multiple elements
(append-map wrap-paragraph (append-map (λ(es) (filter-split es my-paragraph-break?)) (slicef elements block-txexpr?))) ; split into ¶¶, using both implied and explicit paragraph breaks
(if force-paragraph (if force-paragraph
(append-map wrap-paragraph (slicef elements block-txexpr?)) ; upconverts non-block elements to paragraphs (append-map wrap-paragraph (slicef elements block-txexpr?)) ; upconverts non-block elements to paragraphs
elements)))) elements))))

@ -330,26 +330,44 @@ Within @racket[_tagged-xexpr-elements], convert occurrences of @racket[_linebrea
[#:linebreak-proc linebreak-proc (txexpr-elements? . -> . txexpr-elements?) detect-linebreaks] [#:linebreak-proc linebreak-proc (txexpr-elements? . -> . txexpr-elements?) detect-linebreaks]
[#:force? force-paragraph? boolean? #f]) [#:force? force-paragraph? boolean? #f])
txexpr-elements?] txexpr-elements?]
Find paragraphs within @racket[_elements] (as denoted by @racket[_paragraph-sep]) and wrap them with @racket[_paragraph-tag]. Also handle linebreaks using @racket[detect-linebreaks]. Find paragraphs within @racket[_elements] and wrap them with @racket[_paragraph-tag]. Also handle linebreaks using @racket[detect-linebreaks].
If @racket[_element] is already a @racket[block-txexpr?], it will not be wrapped as a paragraph (because in that case, the wrapping would be superfluous). Thus, as a consequence, if @racket[_paragraph-sep] occurs between two blocks, it will be ignored (as in the example below using two sequential @racket['div] blocks.) What counts as a paragraph? Any @racket[_elements] that are either a) explicitly set apart with @racket[_paragraph-sep], or b) adjacent to a @racket[block-txexpr?] (in which case the paragraph-ness is implied).
The @racket[_paragraph-tag] argument sets the tag used to wrap paragraphs. @examples[#:eval my-eval
(detect-paragraphs '("Explicit para" "\n\n" "Explicit para"))
The @racket[_linebreak-proc] argument allows you to use a different linebreaking procedure other than the usual @racket[detect-linebreaks]. (detect-paragraphs '("Explicit para" "\n\n" "Explicit para" "\n" "Explicit line"))
(detect-paragraphs '("Implied para" (div "Block") "Implied para"))
]
The @racket[#:force?] option will wrap a paragraph tag around @racket[_elements], even if no paragraph break is found. If any @racket[_element] is already a @racket[block-txexpr?], it is skipped, but the remaining sequences of non-block @racket[_elements] are wrapped. The @racket[#:force?] option is useful for when you want to guarantee that you get a list of blocks. If @racket[_element] is already a block, it will not be wrapped as a paragraph (because in that case, the wrapping would be superfluous). Thus, as a consequence, if @racket[_paragraph-sep] occurs between two blocks, it will be ignored (as in the example below using two sequential @racket[div] blocks.) Likewise, @racket[_paragraph-sep] will also be ignored if it occurs between a block and a non-block (because a paragraph break is already implied).
@examples[#:eval my-eval @examples[#:eval my-eval
(detect-paragraphs '("First para" "\n\n" "Second para")) (code:comment @#,t{The explicit "\n\n" makes no difference in these cases})
(detect-paragraphs '("First para" "\n\n" "Second para" "\n" "Second line"))
(detect-paragraphs '("First para" "\n\n" (div "Second block")))
(detect-paragraphs '((div "First block") "\n\n" (div "Second block"))) (detect-paragraphs '((div "First block") "\n\n" (div "Second block")))
(detect-paragraphs '((div "First block") (div "Second block")))
(detect-paragraphs '("Para" "\n\n" (div "Block")))
(detect-paragraphs '("Para" (div "Block")))
]
The @racket[_paragraph-tag] argument sets the tag used to wrap paragraphs.
@examples[#:eval my-eval
(detect-paragraphs '("First para" "\n\n" "Second para") #:tag 'ns:p) (detect-paragraphs '("First para" "\n\n" "Second para") #:tag 'ns:p)
]
The @racket[_linebreak-proc] argument allows you to use a different linebreaking procedure other than the usual @racket[detect-linebreaks].
@examples[#:eval my-eval
(detect-paragraphs '("First para" "\n\n" "Second para" "\n" "Second line") (detect-paragraphs '("First para" "\n\n" "Second para" "\n" "Second line")
#:linebreak-proc (λ(x) (detect-linebreaks x #:insert '(newline)))) #:linebreak-proc (λ(x) (detect-linebreaks x #:insert '(newline))))
(detect-paragraphs '("First" (span "para") (div "Block") "Second para") ]
#:force? #t)
The @racket[#:force?] option will wrap a paragraph tag around @racket[_elements], even if no explicit or implicit paragraph breaks are found. The @racket[#:force?] option is useful for when you want to guarantee that you always get a list of blocks.
@examples[#:eval my-eval
(detect-paragraphs '("This" (span "will not be") "a paragraph"))
(detect-paragraphs '("But this" (span "will be") "a paragraph") #:force? #t)
] ]
@defproc[ @defproc[

@ -58,14 +58,13 @@
(check-equal? (detect-paragraphs '("foo") #:force? #t) '((p "foo"))) (check-equal? (detect-paragraphs '("foo") #:force? #t) '((p "foo")))
(check-equal? (detect-paragraphs '((div "foo"))) '((div "foo"))) (check-equal? (detect-paragraphs '((div "foo"))) '((div "foo")))
(check-equal? (detect-paragraphs '((div "foo")) #:force? #t) '((div "foo"))) (check-equal? (detect-paragraphs '((div "foo")) #:force? #t) '((div "foo")))
(check-equal? (detect-paragraphs '("foo" (div "bar"))) '("foo" (div "bar"))) (check-equal? (detect-paragraphs '("foo" "\n\n" (div "bar"))) '((p "foo") (div "bar")))
(check-equal? (detect-paragraphs '("foo" (div "bar"))) '((p "foo") (div "bar")))
(check-equal? (detect-paragraphs '("foo" (div "bar")) #:force? #t) '((p "foo") (div "bar"))) (check-equal? (detect-paragraphs '("foo" (div "bar")) #:force? #t) '((p "foo") (div "bar")))
(check-equal? (detect-paragraphs '("foo" (div "bar") "zam")) '("foo" (div "bar") "zam")) (check-equal? (detect-paragraphs '("foo" (div "bar") "zam")) '((p "foo") (div "bar") (p "zam")))
(check-equal? (detect-paragraphs '("foo" (span "zing") (div "bar") "zam")) '("foo" (span "zing") (div "bar") "zam")) (check-equal? (detect-paragraphs '("foo" (span "zing") (div "bar") "zam")) '((p "foo" (span "zing")) (div "bar") (p "zam")))
(check-equal? (detect-paragraphs '("foo" (span "zing") (div "bar") "zam") #:force? #t) '((p "foo" (span "zing")) (div "bar") (p "zam"))) (check-equal? (detect-paragraphs '("foo" (span "zing") (div "bar") "zam") #:force? #t) '((p "foo" (span "zing")) (div "bar") (p "zam")))
(check-equal? (merge-newlines '(p "\n" "foo" "\n" "\n" "bar" (em "\n" "\n" "\n"))) (check-equal? (merge-newlines '(p "\n" "foo" "\n" "\n" "bar" (em "\n" "\n" "\n")))
'(p "\n" "foo" "\n\n" "bar" (em "\n\n\n"))) '(p "\n" "foo" "\n\n" "bar" (em "\n\n\n")))

Loading…
Cancel
Save