introduce `printable?`

main
Matthew Butterick 7 years ago
parent 5305a037a4
commit 6efcc8cdd7

@ -7,8 +7,9 @@
(out quad)
(inner quad)
(size quad [signal])
(offset quad [signal])
(printable? quad [signal])
(size quad)
(offset quad)
(origin quad)
(set-origin! quad where)

@ -18,8 +18,8 @@
(define (coerce-int x) (if (integer? x) (inexact->exact x) x))
(define/contract (anchor->point q anchor [signal #f])
((quad? symbol?) (any/c) . ->* . point?)
(define/contract (anchor->point q anchor)
(quad? symbol? . -> . point?)
(unless (valid-anchor? anchor)
(raise-argument-error 'relative-anchor-pt "valid anchor" anchor))
(match-define (list x-fac y-fac)
@ -27,22 +27,22 @@
[(nw) '(0 0 )] [(n) '(0.5 0 )] [(ne) '(1 0 )]
[( w) '(0 0.5)] [(c) '(0.5 0.5)] [( e) '(1 0.5)]
[(sw) '(0 1 )] [(s) '(0.5 1 )] [(se) '(1 1 )]))
(match-define (list x y) (size q signal))
(match-define (list x y) (size q))
(pt (coerce-int (* x x-fac)) (coerce-int (* y y-fac))))
(define point/c ((quad?) (any/c) . ->* . point?))
(define point/c (quad? . -> . point?))
(define/contract (inner-point q [signal #f])
(define/contract (inner-point q)
point/c
(pt+ (origin q) (anchor->point q (inner q) signal) (offset q)))
(pt+ (origin q) (anchor->point q (inner q)) (offset q)))
(define/contract (in-point q [signal #f])
(define/contract (in-point q)
point/c
(anchor->point q (in q) signal))
(anchor->point q (in q)))
(define/contract (out-point q [signal #f])
(define/contract (out-point q)
point/c
(pt+ (origin q) (anchor->point q (out q) signal))) ; no offset because end-point is calculated without padding
(pt+ (origin q) (anchor->point q (out q)))) ; no offset because end-point is calculated without padding
(define/contract (position q [previous-end-pt (origin q)])

@ -3,12 +3,12 @@
(provide (all-defined-out))
(module+ test (require rackunit))
(define (default-size-proc q sig)
(define (default-visibility-proc q sig)
(match (elems q)
[(list (? (λ (x) (and (char? x) (char-whitespace? x))) c)) (case sig
[(start end) '(0 0)]
[else '(1 1)])]
[else '(1 1)]))
[(start end) #f]
[else #t])]
[else #t]))
(struct $quad (attrs elems) #:transparent #:mutable
#:methods gen:quad
@ -17,11 +17,17 @@
(define (in q) (hash-ref (attrs q) 'in 'nw))
(define (out q) (hash-ref (attrs q) 'out 'ne))
(define (inner q) (hash-ref (attrs q) 'inner (λ () (in q))))
(define (size q [signal #f]) (let ([v (hash-ref (attrs q) 'size (λ () (default-size-proc q signal)))])
(cond
[(procedure? v) (v signal)]
[(promise? v) (force v)]
[else v])))
(define (printable? q [signal #f])
(let ([v (hash-ref (attrs q) 'printable? (λ () (default-visibility-proc q signal)))])
(cond
[(procedure? v) (v signal)]
[(promise? v) (force v)]
[else v])))
(define (size q) (let ([v (hash-ref (attrs q) 'size '(1 1))])
(cond
[(procedure? v) (v)]
[(promise? v) (force v)]
[else v])))
(define (offset q [signal #f]) (hash-ref (attrs q) 'offset '(0 0)))
(define (origin q) (hash-ref (attrs q) 'origin '(0 0)))
(define (set-origin! q val) (set-$quad-attrs! q (hash-set (attrs q) 'origin val)))
@ -38,7 +44,7 @@
[(list #f xs ...) (apply quad #:type type (hasheq) xs)]
[(list (list (? symbol? sym) rest ...) (? quad-elem? elems) ...) (type (apply hasheq (cons sym rest)) elems)]
[(list (? dict? attrs) (? quad-elem? elems) ...) (type (for/hasheq ([(k v) (in-dict attrs)])
(values k v)) elems)]
(values k v)) elems)]
[(list (? quad-attrs? attrs) (? quad-elem? elems) ...) (type attrs elems)]
[(list (? quad-elem? elems) ...) (apply quad #:type type #f elems)]
[else (error 'bad-quad-input)]))

@ -8,21 +8,22 @@
(struct $char $quad () #:transparent)
(define (charify q)
($char (hash-set* (attrs q)
'size (case (car (elems q))
[(#\u00AD)
(λ (sig) (case sig
[(end) '(7.2 12)]
[else #f]))]
[(#\space) (λ (sig) (case sig
[(start end) #f]
[else '(7.2 12)]))]
[else (const '(7.2 12))])
'size (const '(7.2 12))
'printable? (case (car (elems q))
[(#\u00AD)
(λ (sig) (case sig
[(end) #t]
[else #f]))]
[(#\space) (λ (sig) (case sig
[(start end) #f]
[else #t]))]
[else #t])
'draw (λ (q doc) (send/apply doc text (apply string (elems q)) (origin q)))) (elems q)))
(struct $line $quad () #:transparent)
(struct $page $quad () #:transparent)
(struct $doc $quad () #:transparent)
(struct $break $quad () #:transparent)
(define (break . xs) ($break (hasheq 'size #f) xs))
(define (break . xs) ($break (hasheq 'printable? #f) xs))
(define line-height 16)
(define (line-wrap xs size [debug #f])

@ -2,18 +2,16 @@
(require racket/contract racket/list racket/match txexpr sugar/debug sugar/define sugar/list racket/promise racket/function (only-in racket/control call/prompt)
"param.rkt" "qexpr.rkt" "atomize.rkt" "quad.rkt" "generic.rkt" "position.rkt")
(define/contract (distance q [signal #f])
((any/c) (any/c) . ->* . (or/c #f real?))
(define/contract (distance q)
(any/c . -> . real?)
;; linear distance from in point to out point
;; or #f if quad is nonprinting
(cond
[(quad? q)
(and (size q signal)
(match-let ([(list ∆x ∆y) (map - (out-point q signal) (in-point q signal))])
(cond
[(zero? ∆x) ∆y]
[(zero? ∆y) ∆x]
[else (sqrt (+ (* ∆x ∆x) (* ∆y ∆y)))])))]
(match-define (list ∆x ∆y) (map - (out-point q) (in-point q)))
(cond
[(zero? ∆x) ∆y]
[(zero? ∆y) ∆x]
[else (sqrt (+ (* ∆x ∆x) (* ∆y ∆y)))])]
[else 0]))
@ -30,12 +28,12 @@
#:optional-break-proc procedure?
#:finish-wrap-proc procedure?) . ->* . (listof any/c))
(define start-signal (gensym))
(define (nonprinting-at-start? x) (not (distance x 'start)))
(define (nonprinting-at-end? x) (not (distance x 'end)))
(define (nonprinting-at-start? x) (if (quad? x) (not (printable? x 'start)) #t))
(define (nonprinting-at-end? x) (if (quad? x) (not (printable? x 'end)) #t))
(define (finish-wrap pieces) (finish-wrap-proc (reverse (dropf pieces (λ (x) (and (optional-break? x)
(nonprinting-at-end? x)))))))
(define last-optional-break-k #f)
(define (capture-optional-break-k!) (let/cc k (set! last-optional-break-k k) #f))
(define (capture-optional-break-k!) (when debug (report 'capturing-break)) (let/cc k (set! last-optional-break-k k) #f))
(call/prompt ;; continuation boundary for last-optional-break-k
(thunk
(let loop ([wraps null][wrap-pieces null][dist-so-far start-signal][xs xs])
@ -47,11 +45,13 @@
[else
(define x (car xs))
(define at-start? (eq? dist-so-far start-signal))
(define underflow? (and (not at-start?) (<= (+ dist-so-far (or (distance x 'end) 0)) target-size)))
(define underflow? (and (not at-start?) (<= (+ dist-so-far (if (and (quad? x) (printable? x 'end)) (distance x) 0)) target-size)))
(define (add-to-current-wrap)
(define dist (distance x (and at-start? 'start)))
(define printable (and (quad? x) (printable? x (and at-start? 'start))))
(define dist (and printable (distance x)))
(loop wraps
(if dist (cons x wrap-pieces) wrap-pieces) ; omit nonprinting quad
(if (and (quad? x) (not printable)) wrap-pieces (cons x wrap-pieces)) ; omit nonprinting quad
(if at-start? (or dist start-signal) (+ dist-so-far (or dist 0)))
(cdr xs)))
(define (insert-break [before? #f])
@ -115,19 +115,19 @@
(define x (q #f #\x))
(define zwx (q (list 'size (pt 0 0)) #\z))
(define hyph (q #f #\-))
(define shy (q (list 'size (λ (sig)
(case sig
[(end) (pt 1 1)]
[else #f]))) #\-))
(define shy (q (list 'size (pt 1 1) 'printable? (λ (sig)
(case sig
[(end) #t]
[else #f]))) #\-))
(define a (q #f #\a))
(define b (q #f #\b))
(define c (q #f #\c))
(define d (q #f #\d))
(define sp (q (list 'size (λ (sig)
(case sig
[(start end) #f]
[else (pt 1 1)]))) #\space))
(define br (q (list 'size #f) #\newline))
(define sp (q (list 'size (pt 1 1) 'printable? (λ (sig)
(case sig
[(start end) #f]
[else #t]))) #\space))
(define br (q (list 'size (pt 0 0) 'printable? #f) #\newline))
(define optional-break? (λ (q) (and (quad? q) (memv (car (elems q)) '(#\space #\-)))))
(define (linewrap xs size [debug #f])
@ -136,6 +136,7 @@
#:mandatory-break-proc (λ (q) (and (quad? q) (memv (car (elems q)) '(#\newline))))
#:optional-break-proc optional-break?))
(module+ test
(require rackunit)
@ -151,6 +152,7 @@
(check-equal? (linewrap (list x x x x x) 1) (list x 'lb x 'lb x 'lb x 'lb x))
(check-equal? (linewrap (list x x x x x) 10) (list x x x x x)))
(test-case
"chars and spaces"
(check-equal? (linewrap (list x sp x) 1) (list x 'lb x))
@ -158,6 +160,7 @@
(check-equal? (linewrap (list a sp b) 3) (list a sp b))
(check-equal? (linewrap (list x sp x x) 3) (list x 'lb x x)))
(test-case
"leading & trailing spaces"
(check-equal? (linewrap (list sp x) 2) (list x))
@ -166,7 +169,6 @@
(check-equal? (linewrap (list sp sp x sp sp) 2) (list x))
(check-equal? (linewrap (list sp sp x sp sp x sp) 1) (list x 'lb x)))
(test-case
"hard hyphens"
(check-equal? (linewrap (list hyph) 1) (list hyph))
@ -222,20 +224,17 @@
(check-equal? (linewrap (list a sp b sp sp br sp c) 3) (list a sp b 'lb c))
(check-equal? (linewrap (list x x x x) 3) (list x x x 'lb x))
(check-equal? (linewrap (list x x x sp x x) 2) (list x x 'lb x 'lb x x))
(check-equal? (linewrap (list x x x sp x x) 3) (list x x x 'lb x x)))
(check-equal? (linewrap (list x x x sp x x) 3) (list x x x 'lb x x))))
(define (visual-wrap str int [debug #f])
(apply string (for/list ([b (in-list (linewrap (atomize str) int debug))])
(cond
[(quad? b) (car (elems b))]
[else #\|]))))
(check-equal? (visual-wrap "M d" 1 1) "M|d")
#|
(test-case
(module+ test
(test-case
"visual breaks"
(check-equal? (visual-wrap "My dog has fleas" 1 1) "M|y|d|o|g|h|a|s|f|l|e|a|s")
(check-equal? (visual-wrap "My dog has fleas" 1) "M|y|d|o|g|h|a|s|f|l|e|a|s")
(check-equal? (visual-wrap "My dog has fleas" 2) "My|do|g|ha|s|fl|ea|s")
(check-equal? (visual-wrap "My dog has fleas" 3) "My|dog|has|fle|as")
(check-equal? (visual-wrap "My dog has fleas" 4) "My|dog|has|flea|s")
@ -250,7 +249,7 @@
(check-equal? (visual-wrap "My dog has fleas" 13) "My dog has|fleas")
(check-equal? (visual-wrap "My dog has fleas" 14) "My dog has|fleas")
(check-equal? (visual-wrap "My dog has fleas" 15) "My dog has|fleas")
(check-equal? (visual-wrap "My dog has fleas" 16) "My dog has fleas"))
(check-equal? (visual-wrap "My dog has fleas" 16) "My dog has fleas")))
(define (pagewrap xs size [debug #f])
@ -260,6 +259,7 @@
#:optional-break-proc (λ (x) (eq? x 'lb))))
(define pbr (q '(size #f) #\page))
(module+ test
(test-case
"soft page breaks"
(check-equal? (pagewrap null 2) null)
@ -278,7 +278,6 @@
(check-equal? (pagewrap (list x pbr pbr x x) 1) (list x 'pb 'pb x 'pb x))
(check-equal? (pagewrap (list x pbr pbr x x) 2) (list x 'pb 'pb x x))
(check-equal? (pagewrap (list 'lb x 'lb 'lb pbr 'lb x x 'lb) 2) (list x 'pb x x)))
(test-case
"composed line breaks and page breaks"
(check-equal? (pagewrap (linewrap null 1) 2) null)
@ -305,7 +304,4 @@
(check-equal? (linewrap2 (list a sp b sp sp br sp c) 3) (list (slug a sp b) 'lb (slug c)))
(check-equal? (linewrap2 (list x x x x) 3) (list (slug x x x) 'lb (slug x)))
(check-equal? (linewrap2 (list x x x sp x x) 2) (list (slug x x) 'lb (slug x) 'lb (slug x x)))
(check-equal? (linewrap2 (list x x x sp x x) 3) (list (slug x x x) 'lb (slug x x))))
|#
)
(check-equal? (linewrap2 (list x x x sp x x) 3) (list (slug x x x) 'lb (slug x x)))))
Loading…
Cancel
Save