From 701887c17864e3408927152c2e023f98d4d71cca Mon Sep 17 00:00:00 2001 From: Matthew Butterick Date: Tue, 12 Nov 2019 17:24:49 -0800 Subject: [PATCH] better kwn --- quad/qtest/test-keep-with-next-tester.pdf | Bin 0 -> 13934 bytes quad/qtest/test-keep-with-next.rkt | 11 +++++++++++ quad/quadwriter/layout.rkt | 19 ++++++++++--------- 3 files changed, 21 insertions(+), 9 deletions(-) create mode 100644 quad/qtest/test-keep-with-next-tester.pdf create mode 100644 quad/qtest/test-keep-with-next.rkt diff --git a/quad/qtest/test-keep-with-next-tester.pdf b/quad/qtest/test-keep-with-next-tester.pdf new file mode 100644 index 0000000000000000000000000000000000000000..bff4504c4b3e1d1639a67321fb9ae8c36d9f0b50 GIT binary patch literal 13934 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 literal 0 HcmV?d00001 diff --git a/quad/qtest/test-keep-with-next.rkt b/quad/qtest/test-keep-with-next.rkt new file mode 100644 index 00000000..24ced271 --- /dev/null +++ b/quad/qtest/test-keep-with-next.rkt @@ -0,0 +1,11 @@ +#lang quadwriter/markdown + +#:page-width "4in" +#:page-height "2in" +#:footer-display "none" + +Page 1 text many lines of the quad are kept together. + +## heading sticks to p.2 + +Page 2 text are kept together near a page break. \ No newline at end of file diff --git a/quad/quadwriter/layout.rkt b/quad/quadwriter/layout.rkt index f994acdf..31244b0f 100644 --- a/quad/quadwriter/layout.rkt +++ b/quad/quadwriter/layout.rkt @@ -466,16 +466,17 @@ (define (make-nobreak! q) (quad-set! q :no-colbr #true)) ; cooperates with col-wrap (define (do-keep-with-next! reversed-lines) - ;; paints nobreak onto spacers that follow keep-with-next lines + ;; paints nobreak onto the kwn line itself, + ;; and any line spacers that follow (could be one or more) ;; (we are iterating backward, so the geometrically previous ln follows the spacer) - (match reversed-lines - [(? null?) null] - [_ (for ([this-ln (in-list reversed-lines)] - [prev-ln (in-list (cdr reversed-lines))] - #:when (and (line-spacer-quad? this-ln) - (quad-ref prev-ln :keep-with-next))) - (make-nobreak! this-ln) - (make-nobreak! prev-ln))])) + (define (is-kwn-line? ln) (quad-ref ln :keep-with-next)) + (let loop ([lines (reverse reversed-lines)]) + (unless (null? lines) + (match lines + [(list* (? is-kwn-line? kwn) (? line-spacer-quad? lsqs) ..1 rest) + (for-each make-nobreak! (cons kwn lsqs)) + (loop rest)] + [(cons ln rest) (loop rest)])))) (define (apply-keeps lines) (define groups-of-lines (contiguous-group-by (λ (x) (quad-ref x :display)) lines))