improve `smart-quotes` when adjacent to txexprs (fixes #136)

pull/139/head
Matthew Butterick 7 years ago
parent a4bff463b4
commit 897c32ef8d

@ -16,9 +16,9 @@ Quick & dirty utilities. I use them, but I haven't tested them with enough edge
@defproc[ @defproc[
(smart-quotes (smart-quotes
[str string?]) [xexpr (or/c string? txexpr?)])
string?] (or/c string? txexpr?)]
Convert straight quotes in @racket[_str] to curly according to American English conventions. Convert straight quotes in @racket[_xexepr] to curly according to American English conventions.
@examples[#:eval my-eval @examples[#:eval my-eval
(define tricky-string (define tricky-string

@ -1,5 +1,5 @@
#lang racket/base #lang racket/base
(require racket/list sugar/define sugar/test txexpr/base racket/match sugar/unstable/container sugar/coerce sugar/unstable/len "../private/whitespace.rkt") (require racket/list racket/string sugar/define sugar/test txexpr/base racket/match sugar/unstable/container sugar/coerce sugar/unstable/len "../private/whitespace.rkt")
(provide whitespace? whitespace/nbsp?) (provide whitespace? whitespace/nbsp?)
@ -22,20 +22,42 @@
(check-equal? (smart-dashes "I had --- maybe 13 -- 20 --- hob-nobs.") "I had—maybe 1320—hob-nobs.") (check-equal? (smart-dashes "I had --- maybe 13 -- 20 --- hob-nobs.") "I had—maybe 1320—hob-nobs.")
(check-equal? (smart-quotes "\"Why,\" she could've asked, \"are we in Oahu watching 'Mame'?\"") (check-equal? (smart-quotes "\"Why,\" she could've asked, \"are we in Oahu watching 'Mame'?\"")
"“Why,” she couldve asked, “are we in Oahu watching Mame?”") "“Why,” she couldve asked, “are we in Oahu watching Mame?”")
(check-equal? (smart-quotes "\"\'Impossible.\' Yes.\"") "Impossible. Yes.”")) (check-equal? (smart-quotes "\"\'Impossible.\' Yes.\"") "Impossible. Yes.”")
(check-equal? (smart-quotes '(div "don'" (em "t"))) '(div "don" (em "t")))
(check-equal? (smart-quotes '(div "do '" (em "not'"))) '(div "do " (em "not"))))
(define+provide/contract (smart-quotes str) (define+provide/contract (smart-quotes x)
(string? . -> . string?) ((or/c string? txexpr?) . -> . (or/c string? txexpr?))
(define quotes (define quotes
'((#px"(?<=\\w)'(?=\\w)" "") ; apostrophe '((#px"(?<=\\w)'(?=\\w)" "") ; apostrophe
(#px"(?<!\\w)'(?=\\S)" "") ; single_at_beginning (#px"(?<!\\w)'(?=\\S)" "") ; single_at_beginning
(#px"(?<=\\S)'(?!\\w)" "") ; single_at_end (#px"(?<=\\S)'(?!\\w)" "") ; single_at_end
(#px"(?<!\\w)\"(?=\\S)" "") ; double_at_beginning (#px"(?<!\\w)\"(?=\\S)" "") ; double_at_beginning
(#px"(?<=\\S)\"(?!\\w)" ""))) ; double_at_end (#px"(?<=\\S)\"(?!\\w)" ""))) ; double_at_end
((make-replacer quotes) str)) (cond
[(string? x) ((make-replacer quotes) x)]
[(txexpr? x)
;; convert the quotes as if the txexpr were a flat string, to get proximity right
;; then replace the actual strings with substrings from this converted result
;; todo: handle entities & chars correctly, for now they are ignored
(define flat-str (string-append* (filter string? (flatten (map remove-attrs x)))))
(define char-vec (for/vector ([c (in-string (smart-quotes flat-str))])
c))
(define offset 0)
(let loop ([x x])
(cond
[(txexpr? x) (txexpr (get-tag x) (get-attrs x) (map loop (get-elements x)))]
[(string? x)
(define prev-offset offset)
(set! offset (+ prev-offset (string-length x)))
(list->string
(for/list ([c (in-vector char-vec prev-offset offset)])
c))]
[else x]))]
[else x]))
; wrap initial quotes for hanging punctuation ; wrap initial quotes for hanging punctuation
; todo: improve this ; todo: improve this

Loading…
Cancel
Save