From bb072a8a9a09cbcc7c4928412b59f13518244e9e Mon Sep 17 00:00:00 2001 From: Matthew Butterick Date: Wed, 6 May 2015 12:18:20 -0700 Subject: [PATCH] make `detect-paragraphs` work more intuitively --- decode.rkt | 9 +++++---- scribblings/decode.scrbl | 40 +++++++++++++++++++++++++++++----------- tests/tests-decode.rkt | 9 ++++----- 3 files changed, 38 insertions(+), 20 deletions(-) diff --git a/decode.rkt b/decode.rkt index 6dd43f0..a930889 100644 --- a/decode.rkt +++ b/decode.rkt @@ -350,10 +350,11 @@ [(list (? block-txexpr? bxs) ...) bxs] ; leave a series of block xexprs alone [else (list (make-txexpr tag empty elems))])) ; otherwise wrap in p tag - (let ([elements (prep-paragraph-flow elements)]) - (if (ormap my-paragraph-break? elements) ; need this condition to prevent infinite recursion - ;; use append-map rather than map to permit return of multiple elements - (append-map wrap-paragraph (filter-split elements my-paragraph-break?)) ; split into ¶¶ + (let ([elements (prep-paragraph-flow elements)]) + (define explicit-or-implicit-paragraph-break? (λ(x) (or (my-paragraph-break? x) (block-txexpr? x)))) + (if (ormap explicit-or-implicit-paragraph-break? elements) ; need this condition to prevent infinite recursion + ;; 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 (append-map wrap-paragraph (slicef elements block-txexpr?)) ; upconverts non-block elements to paragraphs elements)))) diff --git a/scribblings/decode.scrbl b/scribblings/decode.scrbl index bbc703b..24397ed 100644 --- a/scribblings/decode.scrbl +++ b/scribblings/decode.scrbl @@ -330,26 +330,44 @@ Within @racket[_tagged-xexpr-elements], convert occurrences of @racket[_linebrea [#:linebreak-proc linebreak-proc (txexpr-elements? . -> . txexpr-elements?) detect-linebreaks] [#:force? force-paragraph? boolean? #f]) 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. - -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 '("Explicit para" "\n\n" "Explicit para")) +(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 -(detect-paragraphs '("First para" "\n\n" "Second para")) -(detect-paragraphs '("First para" "\n\n" "Second para" "\n" "Second line")) -(detect-paragraphs '("First para" "\n\n" (div "Second block"))) +(code:comment @#,t{The explicit "\n\n" makes no difference in these cases}) (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) +] + +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") #: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[ diff --git a/tests/tests-decode.rkt b/tests/tests-decode.rkt index 6ab66de..ee200a3 100644 --- a/tests/tests-decode.rkt +++ b/tests/tests-decode.rkt @@ -58,14 +58,13 @@ (check-equal? (detect-paragraphs '("foo") #:force? #t) '((p "foo"))) (check-equal? (detect-paragraphs '((div "foo"))) '((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") "zam")) '("foo" (div "bar") "zam")) -(check-equal? (detect-paragraphs '("foo" (span "zing") (div "bar") "zam")) '("foo" (span "zing") (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")) '((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"))) '(p "\n" "foo" "\n\n" "bar" (em "\n\n\n")))