1495 lines
72 KiB
Racket
1495 lines
72 KiB
Racket
#lang at-exp racket/base
|
||
(require "core.rkt"
|
||
"latex-properties.rkt"
|
||
"private/render-utils.rkt"
|
||
"private/latex-index.rkt"
|
||
racket/class
|
||
racket/runtime-path
|
||
racket/port
|
||
racket/string
|
||
racket/path
|
||
racket/list
|
||
setup/collects
|
||
file/convertible)
|
||
(provide render-mixin
|
||
make-render-part-mixin
|
||
extra-character-conversions)
|
||
|
||
(define current-table-mode (make-parameter #f))
|
||
(define rendering-tt (make-parameter #f))
|
||
(define show-link-page-numbers (make-parameter #f))
|
||
(define done-link-page-numbers (make-parameter #f))
|
||
(define multiple-page-references (make-parameter #f))
|
||
(define disable-images (make-parameter #f))
|
||
(define escape-brackets (make-parameter #f))
|
||
(define suppress-newline-content (make-parameter #f))
|
||
(define disable-hyperref (make-parameter #f))
|
||
|
||
(define-struct (toc-paragraph paragraph) ())
|
||
|
||
(define-runtime-path scribble-prefix-tex "scribble-prefix.tex")
|
||
(define-runtime-path scribble-packages-tex "scribble-packages.tex")
|
||
(define-runtime-path scribble-load-tex "scribble-load.tex")
|
||
(define-runtime-path scribble-tex "scribble.tex")
|
||
(define-runtime-path scribble-style-tex "scribble-style.tex")
|
||
(define-runtime-path scribble-load-replace-tex "scribble-load-replace.tex")
|
||
|
||
(define (color->string c)
|
||
(if (string? c)
|
||
c
|
||
(format "~a,~a,~a"
|
||
(/ (car c) 255.0)
|
||
(/ (cadr c) 255.0)
|
||
(/ (caddr c) 255.0))))
|
||
|
||
(define (make-render-part-mixin n)
|
||
(lambda (%)
|
||
(class (render-mixin %)
|
||
(define/override (render-part-depth) n)
|
||
(super-new))))
|
||
|
||
(define-runtime-path skull-tex "scribble-skull.tex")
|
||
(define skull-style (make-style #f (list (tex-addition skull-tex))))
|
||
|
||
(define extra-character-conversions (make-parameter (λ (c) #f)))
|
||
|
||
(define (render-mixin % #:image-mode [image-mode #f])
|
||
(class %
|
||
(super-new)
|
||
|
||
(inherit-field prefix-file style-file style-extra-files image-preferences)
|
||
|
||
(define/override (current-render-mode)
|
||
'(latex))
|
||
|
||
(inherit sort-image-requests)
|
||
(define image-reqs
|
||
(sort-image-requests (cond
|
||
[(eq? image-mode 'pdf)
|
||
'(pdf-bytes png@2x-bytes png-bytes)]
|
||
[(eq? image-mode 'ps)
|
||
'(eps-bytes)]
|
||
[else
|
||
'(pdf-bytes png@2x-bytes png-bytes eps-bytes)])
|
||
image-preferences))
|
||
|
||
(define/override (get-suffix) #".tex")
|
||
|
||
(inherit render-block
|
||
render-part
|
||
install-file
|
||
format-number
|
||
number-depth
|
||
extract-part-style-files
|
||
extract-version
|
||
extract-date
|
||
extract-authors
|
||
extract-pretitle-content
|
||
link-render-style-at-element)
|
||
|
||
(define/public (extract-short-title d)
|
||
(ormap (lambda (v)
|
||
(and (short-title? v)
|
||
(short-title-text v)))
|
||
(style-properties (part-style d))))
|
||
|
||
(define/override (auto-extra-files? v) (latex-defaults? v))
|
||
(define/override (auto-extra-files-paths v) (latex-defaults-extra-files v))
|
||
|
||
(define/public (render-part-depth) #f)
|
||
|
||
(define/override (render-one d ri fn)
|
||
(define (maybe-replace file defaults)
|
||
(cond [(and defaults
|
||
(latex-defaults+replacements? defaults)
|
||
(hash-ref (latex-defaults+replacements-replacements defaults)
|
||
(path->string (file-name-from-path file))
|
||
#f)) =>
|
||
(lambda (v)
|
||
(cond
|
||
[(bytes? v) v]
|
||
[else (collects-relative->path v)]))]
|
||
[else file]))
|
||
(let* ([defaults (ormap (lambda (v) (and (latex-defaults? v) v))
|
||
(style-properties (part-style d)))]
|
||
[prefix-file (or prefix-file
|
||
(and defaults
|
||
(let ([v (latex-defaults-prefix defaults)])
|
||
(cond
|
||
[(bytes? v) v]
|
||
[else (collects-relative->path v)])))
|
||
scribble-prefix-tex)]
|
||
[style-file (or style-file
|
||
(and defaults
|
||
(let ([v (latex-defaults-style defaults)])
|
||
(cond
|
||
[(bytes? v) v]
|
||
[else (collects-relative->path v)])))
|
||
scribble-style-tex)]
|
||
[all-style-files (list* scribble-load-tex
|
||
(maybe-replace scribble-load-replace-tex defaults)
|
||
scribble-tex
|
||
(append (extract-part-style-files
|
||
d
|
||
ri
|
||
(lambda (p) #f)
|
||
tex-addition?
|
||
tex-addition-path)
|
||
(list style-file)
|
||
style-extra-files))]
|
||
[whole-doc? (not (render-part-depth))])
|
||
(if whole-doc?
|
||
(for ([style-file (in-list (cons prefix-file all-style-files))])
|
||
(if (bytes? style-file)
|
||
(display style-file)
|
||
(with-input-from-file style-file
|
||
(lambda ()
|
||
(copy-port (current-input-port) (current-output-port))))))
|
||
(for ([style-file (in-list all-style-files)])
|
||
(if (bytes? style-file)
|
||
(display style-file)
|
||
(install-file style-file))))
|
||
(when whole-doc?
|
||
(printf "\\begin{document}\n\\preDoc\n")
|
||
(when (part-title-content d)
|
||
(let ([vers (extract-version d)]
|
||
[date (extract-date d)]
|
||
[pres (extract-pretitle-content d)]
|
||
[auths (extract-authors d)]
|
||
[short (extract-short-title d)])
|
||
(for ([pre (in-list pres)])
|
||
(printf "\n\n")
|
||
(cond
|
||
[(paragraph? pre)
|
||
(do-render-paragraph pre d ri #t #f)]
|
||
[(nested-flow? pre)
|
||
(do-render-nested-flow pre d ri #t #f #t)]))
|
||
(when date (printf "\\date{~a}\n" date))
|
||
(printf "\\titleAnd~aVersionAnd~aAuthors~a{"
|
||
|
||
(if (equal? vers "") "Empty" "")
|
||
(if (null? auths) "Empty" "")
|
||
(if short "AndShort" ""))
|
||
(render-content (part-title-content d) d ri)
|
||
(printf "}{~a}{" vers)
|
||
(unless (null? auths)
|
||
(printf "\\SNumberOfAuthors{~a}" (length auths)))
|
||
(for/fold ([first? #t]) ([auth (in-list auths)])
|
||
(unless first? (printf "\\SAuthorSep{}"))
|
||
(do-render-paragraph auth d ri #t #f)
|
||
#f)
|
||
(if short
|
||
(printf "}{~a}\n" short)
|
||
(printf "}\n")))))
|
||
(render-part d ri)
|
||
(when whole-doc?
|
||
(printf "\n\n\\postDoc\n\\end{document}\n"))))
|
||
|
||
(define/override (render-part-content d ri)
|
||
(let ([number (collected-info-number (part-collected-info d ri))]
|
||
[completely-hidden?
|
||
(and (part-style? d 'hidden)
|
||
(equal? "" (content->string (part-title-content d))))])
|
||
(when (and (part-title-content d)
|
||
(or (pair? number)
|
||
(let ([d (render-part-depth)])
|
||
(and d (positive? d)))))
|
||
(when (eq? (style-name (part-style d)) 'index)
|
||
(printf "\\twocolumn\n\\parskip=0pt\n\\addcontentsline{toc}{section}{Index}\n"))
|
||
(let ([pres (extract-pretitle-content d)])
|
||
(for ([pre (in-list pres)])
|
||
(printf "\n\n")
|
||
(do-render-paragraph pre d ri #t #f)))
|
||
(define depth (+ (number-depth number) (or (render-part-depth) 0)))
|
||
(define grouper? (part-style? d 'grouper))
|
||
(define (inc-section-number)
|
||
(printf "\\Sinc~a" (case depth
|
||
[(0 1) (if grouper? "part" "section")]
|
||
[(2) "subsection"]
|
||
[(3) "subsubsection"]
|
||
[(4) "subsubsubsection"]
|
||
[else "subsubsubsubsection"])))
|
||
(cond
|
||
[completely-hidden?
|
||
(printf "\n\n\\notitlesection")
|
||
(unless (part-style? d 'unnumbered)
|
||
(inc-section-number))]
|
||
[else
|
||
(define no-number? (and (pair? number)
|
||
(or (not (car number))
|
||
(equal? "" (car number))
|
||
((length number) . > . 3))))
|
||
(define no-toc? (part-style? d 'toc-hidden))
|
||
(define (show-number)
|
||
(when (and (part-style? d 'grouper)
|
||
(depth . > . 1)
|
||
(not no-number?))
|
||
(printf "~a\\quad{}" (car (format-number number null)))))
|
||
(printf "\n\n\\~a~a~a"
|
||
(case depth
|
||
[(0 1) (if grouper?
|
||
"partNewpage\n\n\\Spart"
|
||
"sectionNewpage\n\n\\Ssection")]
|
||
[(2) "Ssubsection"]
|
||
[(3) "Ssubsubsection"]
|
||
[(4) "Ssubsubsubsection"]
|
||
[else "Ssubsubsubsubsection"])
|
||
(if (and grouper?
|
||
(depth . > . 1))
|
||
"grouper"
|
||
"")
|
||
(if no-number?
|
||
(if no-toc?
|
||
"star"
|
||
"starx")
|
||
""))
|
||
(unless (and no-number? no-toc?)
|
||
(printf "{")
|
||
(show-number)
|
||
(parameterize ([disable-images #t]
|
||
[escape-brackets #t]
|
||
[disable-hyperref #t])
|
||
(render-content (part-title-content d) d ri))
|
||
(printf "}"))
|
||
(printf "{")
|
||
(show-number)
|
||
(parameterize ([disable-hyperref #t])
|
||
(render-content (part-title-content d) d ri))
|
||
(printf "}")
|
||
(when (and (part-style? d 'hidden-number)
|
||
(not (part-style? d 'unnumbered)))
|
||
(inc-section-number))
|
||
(when (eq? (style-name (part-style d)) 'index) (printf "\n\n"))]))
|
||
(for ([t (part-tags d)])
|
||
(printf "\\label{t:~a}~a" (t-encode (add-current-tag-prefix (tag-key t ri)))
|
||
(if completely-hidden? "" "\n\n")))
|
||
(render-flow (part-blocks d) d ri #f)
|
||
(for ([sec (part-parts d)]) (render-part sec ri))
|
||
(when (eq? (style-name (part-style d)) 'index) (printf "\\onecolumn\n\n"))
|
||
null))
|
||
|
||
(define/override (render-paragraph p part ri)
|
||
(do-render-paragraph p part ri #f #f))
|
||
|
||
(define/private (do-render-paragraph p part ri show-pre? as-box-mode)
|
||
(let* ([sn (style-name (paragraph-style p))]
|
||
[style (cond
|
||
[as-box-mode
|
||
(or
|
||
(ormap (lambda (a)
|
||
(and (box-mode? a)
|
||
((box-mode-selector as-box-mode) a)))
|
||
(style-properties
|
||
(paragraph-style p)))
|
||
"hbox")]
|
||
[(eq? sn 'author) "SAuthor"]
|
||
[(eq? sn 'pretitle) #f]
|
||
[(eq? sn 'wraps) #f]
|
||
[else sn])])
|
||
(unless (and (not show-pre?)
|
||
(or (eq? sn 'author)
|
||
(eq? sn 'pretitle)))
|
||
(let ([use-style? (string? style)])
|
||
(when use-style?
|
||
(printf "\\~a{" style))
|
||
(if (toc-paragraph? p)
|
||
(printf "\\newpage \\tableofcontents \\newpage")
|
||
(if as-box-mode
|
||
(parameterize ([suppress-newline-content #t])
|
||
(super render-paragraph p part ri))
|
||
(super render-paragraph p part ri)))
|
||
(when use-style? (printf "}")))))
|
||
null)
|
||
|
||
(define/private (no-noindent? p ri)
|
||
(cond
|
||
[(delayed-block? p)
|
||
(no-noindent? (delayed-block-blocks p ri) ri)]
|
||
[(traverse-block? p)
|
||
(no-noindent? (traverse-block-block p ri) ri)]
|
||
[else
|
||
(or
|
||
(memq 'never-indents
|
||
(style-properties
|
||
(cond
|
||
[(paragraph? p) (paragraph-style p)]
|
||
[(compound-paragraph? p) (compound-paragraph-style p)]
|
||
[(nested-flow? p) (nested-flow-style p)]
|
||
[(table? p) (table-style p)]
|
||
[(itemization? p) (itemization-style p)]
|
||
[else plain])))
|
||
(and (nested-flow? p)
|
||
(pair? (nested-flow-blocks p))
|
||
(no-noindent? (car (nested-flow-blocks p)) ri))
|
||
(and (compound-paragraph? p)
|
||
(pair? (compound-paragraph-blocks p))
|
||
(no-noindent? (car (compound-paragraph-blocks p)) ri)))]))
|
||
|
||
(define/override (render-intrapara-block p part ri first? last? starting-item?)
|
||
(unless first?
|
||
(printf "\n\n")
|
||
(unless (no-noindent? p ri)
|
||
(printf "\\noindent ")))
|
||
(super render-intrapara-block p part ri first? last? starting-item?))
|
||
|
||
(define/override (render-content e part ri)
|
||
(let ([part-label? (and (link-element? e)
|
||
(pair? (link-element-tag e))
|
||
(eq? 'part (car (link-element-tag e)))
|
||
(empty-content? (element-content e)))])
|
||
(parameterize ([done-link-page-numbers (or (done-link-page-numbers)
|
||
(link-element? e))])
|
||
(when (target-element? e)
|
||
(printf "\\label{t:~a}"
|
||
(t-encode (add-current-tag-prefix (tag-key (target-element-tag e) ri)))))
|
||
(when part-label?
|
||
(define-values (dest ext?) (resolve-get/ext? part ri (link-element-tag e)))
|
||
(let* ([number (and dest (vector-ref dest 2))]
|
||
[formatted-number (and dest
|
||
(list? number)
|
||
(format-number number null))]
|
||
[lbl? (and dest
|
||
(not ext?)
|
||
(not (show-link-page-numbers)))]
|
||
[link-number? (and lbl?
|
||
(eq? 'number (link-render-style-at-element e)))])
|
||
(printf "\\~aRef~a~a~a{"
|
||
(case (and dest (number-depth number))
|
||
[(0) "Book"]
|
||
[(1) (if (string? (car number)) "Part" "Chap")]
|
||
[else "Sec"])
|
||
(if (and lbl? (not link-number?))
|
||
"Local"
|
||
"")
|
||
(if (let ([s (element-style e)])
|
||
(and (style? s) (memq 'uppercase (style-properties s))))
|
||
"UC"
|
||
"")
|
||
(if (null? formatted-number)
|
||
"UN"
|
||
""))
|
||
(when (and lbl? (not link-number?))
|
||
(printf "t:~a}{" (t-encode (vector-ref dest 1))))
|
||
(unless (null? formatted-number)
|
||
(when link-number? (printf "\\SectionNumberLink{t:~a}{" (t-encode (vector-ref dest 1))))
|
||
(render-content
|
||
(if dest
|
||
(if (list? number)
|
||
formatted-number
|
||
(begin (eprintf "Internal tag error: ~s -> ~s\n"
|
||
(link-element-tag e)
|
||
dest)
|
||
'("!!!")))
|
||
(list "???"))
|
||
part ri)
|
||
(when link-number? (printf "}"))
|
||
(printf "}{"))))
|
||
(let* ([es (cond
|
||
[(element? e) (element-style e)]
|
||
[(multiarg-element? e) (multiarg-element-style e)]
|
||
[else #f])]
|
||
[style-name (if (style? es)
|
||
(style-name es)
|
||
es)]
|
||
[style (and (style? es) es)]
|
||
[hyperref? (and (not part-label?)
|
||
(link-element? e)
|
||
(not (disable-hyperref))
|
||
(let-values ([(dest ext?) (resolve-get/ext? part ri (link-element-tag e))])
|
||
(and dest (not ext?))))]
|
||
[check-render
|
||
(lambda ()
|
||
(when (render-element? e)
|
||
((render-element-render e) this part ri)))]
|
||
[core-render (lambda (e tt?)
|
||
(cond
|
||
[(and (image-element? e)
|
||
(not (disable-images)))
|
||
(check-render)
|
||
(let ([fn (install-file
|
||
(select-suffix
|
||
(collects-relative->path
|
||
(image-element-path e))
|
||
(image-element-suffixes e)
|
||
'(".pdf" ".ps" ".png")))])
|
||
(printf "\\includegraphics[scale=~a]{~a}"
|
||
(image-element-scale e) fn))]
|
||
[(and (convertible? e)
|
||
(not (disable-images))
|
||
(let ([ftag (lambda (v suffix [scale 1]) (and v (list v suffix scale)))]
|
||
[xxlist (lambda (v) (and v (list v #f #f #f #f #f #f #f #f)))]
|
||
[xlist (lambda (v) (and v (append v (list 0 0 0 0))))])
|
||
(for/or ([req (in-list image-reqs)])
|
||
(case req
|
||
[(eps-bytes)
|
||
(or (ftag (convert e 'eps-bytes+bounds8) ".ps")
|
||
(ftag (xlist (convert e 'eps-bytes+bounds)) ".ps")
|
||
(ftag (xxlist (convert e 'eps-bytes)) ".ps"))]
|
||
[(pdf-bytes)
|
||
(or (ftag (convert e 'pdf-bytes+bounds8) ".pdf")
|
||
(ftag (xlist (convert e 'pdf-bytes+bounds)) ".pdf")
|
||
(ftag (xxlist (convert e 'pdf-bytes)) ".pdf"))]
|
||
[(png@2x-bytes)
|
||
(or (ftag (convert e 'png@2x-bytes+bounds8) ".png" 0.5)
|
||
(ftag (xxlist (convert e 'png@2x-bytes)) ".png" 0.5))]
|
||
[(png-bytes)
|
||
(or (ftag (convert e 'png-bytes+bounds8) ".png")
|
||
(ftag (xxlist (convert e 'png-bytes)) ".png"))]))))
|
||
=> (lambda (bstr+info+suffix)
|
||
(check-render)
|
||
(let* ([bstr (list-ref (list-ref bstr+info+suffix 0) 0)]
|
||
[suffix (list-ref bstr+info+suffix 1)]
|
||
[scale (list-ref bstr+info+suffix 2)]
|
||
[height (list-ref (list-ref bstr+info+suffix 0) 2)]
|
||
[pad-left (or (list-ref (list-ref bstr+info+suffix 0) 5) 0)]
|
||
[pad-top (or (list-ref (list-ref bstr+info+suffix 0) 6) 0)]
|
||
[pad-right (or (list-ref (list-ref bstr+info+suffix 0) 7) 0)]
|
||
[pad-bottom (or (list-ref (list-ref bstr+info+suffix 0) 8) 0)]
|
||
[descent (and height
|
||
(- (+ (list-ref (list-ref bstr+info+suffix 0) 3)
|
||
(- (ceiling height) height))
|
||
pad-bottom))]
|
||
[width (let ([w (list-ref (list-ref bstr+info+suffix 0) 1)])
|
||
(and w (- w pad-left pad-right)))]
|
||
[fn (install-file (format "pict~a" suffix) bstr)])
|
||
(if descent
|
||
(printf "\\raisebox{-~abp}{\\makebox[~abp][l]{\\includegraphics[~atrim=~a ~a ~a ~a]{~a}}}"
|
||
descent
|
||
width
|
||
(if (= scale 1) "" (format "scale=~a," scale))
|
||
(/ pad-left scale) (/ pad-bottom scale) (/ pad-right scale) (/ pad-top scale)
|
||
fn)
|
||
(printf "\\includegraphics{~a}" fn))))]
|
||
[else
|
||
(parameterize ([rendering-tt (or tt? (rendering-tt))])
|
||
(super render-content e part ri))]))]
|
||
[wrap (lambda (e s tt?)
|
||
(when s (printf "\\~a{" s))
|
||
(core-render e tt?)
|
||
(when s (printf "}")))])
|
||
(define (finish tt?)
|
||
(cond
|
||
[(symbol? style-name)
|
||
(case style-name
|
||
[(italic) (wrap e "textit" tt?)]
|
||
[(bold) (wrap e "textbf" tt?)]
|
||
[(tt) (wrap e "Scribtexttt" #t)]
|
||
[(url) (wrap e "Snolinkurl" 'url)]
|
||
[(no-break) (wrap e "mbox" tt?)]
|
||
[(sf) (wrap e "textsf" #f)]
|
||
[(roman) (wrap e "textrm" #f)]
|
||
[(subscript) (wrap e "textsub" #f)]
|
||
[(superscript) (wrap e "textsuper" #f)]
|
||
[(smaller) (wrap e "Smaller" #f)]
|
||
[(larger) (wrap e "Larger" #f)]
|
||
[(hspace)
|
||
(check-render)
|
||
(let ([s (content->string e)])
|
||
(case (string-length s)
|
||
[(0) (void)]
|
||
[else
|
||
(printf "\\mbox{\\hphantom{\\Scribtexttt{~a}}}"
|
||
(regexp-replace* #rx"." s "x"))]))]
|
||
[(newline)
|
||
(check-render)
|
||
(unless (suppress-newline-content)
|
||
(printf "\\hspace*{\\fill}\\\\"))]
|
||
[else (error 'latex-render
|
||
"unrecognized style symbol: ~s" style)])]
|
||
[(string? style-name)
|
||
(let* ([v (if style (style-properties style) null)]
|
||
[tt? (cond
|
||
[(memq 'tt-chars v) #t]
|
||
[(memq 'exact-chars v) 'exact]
|
||
[else tt?])])
|
||
(cond
|
||
[(multiarg-element? e)
|
||
(check-render)
|
||
(printf "\\~a" style-name)
|
||
(define maybe-optional-args
|
||
(findf command-optional? (if style (style-properties style) '())))
|
||
(when maybe-optional-args
|
||
(for ([i (in-list (command-optional-arguments maybe-optional-args))])
|
||
(printf "[~a]" i)))
|
||
(if (null? (multiarg-element-contents e))
|
||
(printf "{}")
|
||
(for ([i (in-list (multiarg-element-contents e))])
|
||
(printf "{")
|
||
(parameterize ([rendering-tt (or tt? (rendering-tt))])
|
||
(render-content i part ri))
|
||
(printf "}")))]
|
||
[else
|
||
(define maybe-optional
|
||
(findf command-optional? (if style (style-properties style) '())))
|
||
(if maybe-optional
|
||
(wrap e
|
||
(string-join #:before-first (format "~a[" style-name)
|
||
#:after-last "]"
|
||
(command-optional-arguments maybe-optional)
|
||
"][")
|
||
tt?)
|
||
(wrap e style-name tt?))]))]
|
||
[(and (not style-name)
|
||
style
|
||
(memq 'exact-chars (style-properties style)))
|
||
(wrap e style-name 'exact)]
|
||
[else
|
||
(core-render e tt?)]))
|
||
(when hyperref?
|
||
(printf "\\hyperref[t:~a]{"
|
||
(t-encode (link-element-tag e))))
|
||
(let loop ([l (if style (style-properties style) null)] [tt? #f])
|
||
(if (null? l)
|
||
(if hyperref?
|
||
(parameterize ([disable-hyperref #t])
|
||
(finish tt?))
|
||
(finish tt?))
|
||
(let ([v (car l)])
|
||
(cond
|
||
[(target-url? v)
|
||
(define target (let* ([s (let ([p (target-url-addr v)])
|
||
(if (path? p)
|
||
(path->string p)
|
||
p))]
|
||
[s (regexp-replace* #rx"\\\\" s "%5c")]
|
||
[s (regexp-replace* #rx"{" s "%7b")]
|
||
[s (regexp-replace* #rx"}" s "%7d")]
|
||
[s (regexp-replace* #rx"%" s "\\\\%")])
|
||
s))
|
||
(if (regexp-match? #rx"^[^#]*#[^#]*$" target)
|
||
;; work around a problem with `\href' as an
|
||
;; argument to other macros, such as `\marginpar':
|
||
(let ([l (string-split target "#")])
|
||
(printf "\\Shref{~a}{~a}{" (car l) (cadr l)))
|
||
;; normal:
|
||
(printf "\\href{~a}{" target))
|
||
(loop (cdr l) #t)
|
||
(printf "}")]
|
||
[(color-property? v)
|
||
(printf "\\intext~acolor{~a}{"
|
||
(if (string? (color-property-color v)) "" "rgb")
|
||
(color->string (color-property-color v)))
|
||
(loop (cdr l) tt?)
|
||
(printf "}")]
|
||
[(background-color-property? v)
|
||
(printf "\\in~acolorbox{~a}{"
|
||
(if (string? (background-color-property-color v)) "" "rgb")
|
||
(color->string (background-color-property-color v)))
|
||
(loop (cdr l) tt?)
|
||
(printf "}")]
|
||
[(command-extras? (car l))
|
||
(loop (cdr l) tt?)
|
||
(for ([l (in-list (command-extras-arguments (car l)))])
|
||
(printf "{~a}" l))]
|
||
[else (loop (cdr l) tt?)]))))
|
||
(when hyperref?
|
||
(printf "}"))))
|
||
(when part-label?
|
||
(printf "}"))
|
||
(when (and (link-element? e)
|
||
(show-link-page-numbers)
|
||
(not (done-link-page-numbers)))
|
||
(define (make-ref e)
|
||
(string-append
|
||
"t:"
|
||
(t-encode
|
||
(let ([v (resolve-get part ri (link-element-tag e))])
|
||
(and v (vector-ref v 1))))))
|
||
(cond
|
||
[(multiple-page-references) ; for index
|
||
=> (lambda (l)
|
||
(printf ", \\Smanypageref{~a}" ; using cleveref
|
||
(string-join (map make-ref l) ",")))]
|
||
[else
|
||
(printf ", \\pageref{~a}" (make-ref e))]))
|
||
null))
|
||
|
||
(define/private (t-encode s)
|
||
(string-append*
|
||
(map (lambda (c)
|
||
(cond
|
||
[(and (or (char-alphabetic? c) (char-numeric? c))
|
||
((char->integer c) . < . 128))
|
||
(string c)]
|
||
[(char=? c #\space) "_"]
|
||
[else (format "x~x" (char->integer c))]))
|
||
(string->list (format "~s" s)))))
|
||
|
||
(define/override (render-flow p part ri starting-item? [wrap-each? #f])
|
||
(if (null? p)
|
||
null
|
||
(begin
|
||
(when wrap-each? (printf "{"))
|
||
(render-block (car p) part ri starting-item?)
|
||
(when wrap-each? (printf "}"))
|
||
(for ([b (in-list (cdr p))])
|
||
(if wrap-each?
|
||
(printf "%\n{")
|
||
(printf "\n\n"))
|
||
(render-block b part ri #f)
|
||
(when wrap-each? (printf "}")))
|
||
null)))
|
||
|
||
(define/override (render-table t part ri starting-item?)
|
||
(render-table* t part ri starting-item? "[t]"))
|
||
|
||
(define/private (render-table* t part ri starting-item? alignment)
|
||
(let* ([s-name (style-name (table-style t))]
|
||
[boxed? (eq? 'boxed s-name)]
|
||
[index? (eq? 'index s-name)]
|
||
[merge-index? (let loop ([part part])
|
||
(or (memq 'enable-index-merge (style-properties (part-style part)))
|
||
(let* ([ci (part-collected-info part ri)]
|
||
[p (and ci (collected-info-parent ci))])
|
||
(and p (loop p)))))]
|
||
[tableform
|
||
(cond [index? "list"]
|
||
[(eq? 'block s-name) "tabular"]
|
||
[(not (current-table-mode)) "bigtabular"]
|
||
[else "tabular"])]
|
||
[opt (cond [(equal? tableform "bigtabular") ""]
|
||
[(equal? tableform "tabular") alignment]
|
||
[else ""])]
|
||
[blockss (if index? (cddr (table-blockss t)) (table-blockss t))]
|
||
[cell-styless (extract-table-cell-styles t)]
|
||
[twidth (if (null? (table-blockss t))
|
||
1
|
||
(length (car (table-blockss t))))]
|
||
[single-column? (and (= 1 twidth)
|
||
(or (not s-name) (string? s-name))
|
||
(not (ormap (lambda (cell-styles)
|
||
(ormap (lambda (s)
|
||
(or (string? (style-name s))
|
||
(let ([l (style-properties s)])
|
||
(or (memq 'right l)
|
||
(memq 'center l)))))
|
||
cell-styles))
|
||
cell-styless))
|
||
(not (current-table-mode)))]
|
||
[inline?
|
||
(and (not single-column?)
|
||
(not boxed?)
|
||
(not index?)
|
||
(ormap (lambda (rs)
|
||
(ormap (lambda (cs) (style-name cs)) rs))
|
||
cell-styless)
|
||
(= 1 twidth)
|
||
(let ([m (current-table-mode)])
|
||
(and m
|
||
(equal? "bigtabular" (car m))
|
||
(= 1 (length (car (table-blockss (cadr m))))))))])
|
||
(if single-column?
|
||
(begin
|
||
(when (string? s-name)
|
||
(printf "\\begin{~a}" s-name))
|
||
(do-render-nested-flow
|
||
(make-nested-flow (make-style "SingleColumn" null) (map car (table-blockss t)))
|
||
part
|
||
ri
|
||
#t
|
||
#f
|
||
#f)
|
||
(when (string? s-name)
|
||
(printf "\\end{~a}" s-name)))
|
||
(unless (or (null? blockss) (null? (car blockss)))
|
||
(define all-left-line?s
|
||
(if (null? cell-styless)
|
||
null
|
||
(for/list ([i (in-range (length (car cell-styless)))])
|
||
(for/and ([cell-styles (in-list cell-styless)])
|
||
(let ([cell-style (list-ref cell-styles i)])
|
||
(or (memq 'left-border (style-properties cell-style))
|
||
(memq 'border (style-properties cell-style))))))))
|
||
(define all-right-line?
|
||
(and (pair? cell-styless)
|
||
(let ([i (sub1 (length (car cell-styless)))])
|
||
(for/and ([cell-styles (in-list cell-styless)])
|
||
(let ([cell-style (list-ref cell-styles i)])
|
||
(or (memq 'right-border (style-properties cell-style))
|
||
(memq 'border (style-properties cell-style))))))))
|
||
(parameterize ([current-table-mode
|
||
(if inline? (current-table-mode) (list tableform t))]
|
||
[show-link-page-numbers
|
||
(or index? (show-link-page-numbers))])
|
||
(cond
|
||
[index? (printf "\\begin{list}{}{\\parsep=0pt \\itemsep=1pt \\leftmargin=2ex \\itemindent=-2ex}\n")]
|
||
[inline? (void)]
|
||
[single-column? (printf "\\begin{tabbing}\n")]
|
||
[else
|
||
(printf "~a~a\\begin{~a}~a{@{~a}~a}\n~a"
|
||
(if (and starting-item? (equal? tableform "bigtabular"))
|
||
"\\bigtableinlinecorrect"
|
||
"")
|
||
(if (string? s-name)
|
||
(format "\\begin{~a}" s-name)
|
||
"")
|
||
tableform
|
||
opt
|
||
(if (equal? tableform "bigtabular")
|
||
"\\bigtableleftpad"
|
||
"")
|
||
(string-append*
|
||
(let ([l
|
||
(map (lambda (i cell-style left-line?)
|
||
(format "~a~a@{}"
|
||
(if left-line? "|@{}" "")
|
||
(cond
|
||
[(memq 'center (style-properties cell-style)) "c"]
|
||
[(memq 'right (style-properties cell-style)) "r"]
|
||
[else "l"])))
|
||
(car blockss)
|
||
(car cell-styless)
|
||
all-left-line?s)])
|
||
(let ([l (if all-right-line? (append l '("|")) l)])
|
||
(if boxed? (cons "@{\\SBoxedLeft}" l) l))))
|
||
"")])
|
||
;; Helper to add row-separating lines:
|
||
(define (add-clines prev-styles next-styles)
|
||
(let loop ([pos 1] [start #f] [prev-styles prev-styles] [next-styles next-styles])
|
||
(cond
|
||
[(or (and prev-styles (null? prev-styles))
|
||
(and next-styles (null? next-styles)))
|
||
(when start
|
||
(if (= start 1)
|
||
(printf "\\hline ")
|
||
(printf "\\cline{~a-~a}" start (sub1 pos))))]
|
||
[else
|
||
(define prev-style (and prev-styles (car prev-styles)))
|
||
(define next-style (and next-styles (car next-styles)))
|
||
(define line? (or (and prev-style
|
||
(or (memq 'bottom-border (style-properties prev-style))
|
||
(memq 'border (style-properties prev-style))))
|
||
(and next-style
|
||
(or (memq 'top-border (style-properties next-style))
|
||
(memq 'border (style-properties next-style))))))
|
||
(when (and start (not line?))
|
||
(printf "\\cline{~a-~a}" start (sub1 pos)))
|
||
(loop (add1 pos) (and line? (or start pos))
|
||
(and prev-styles (cdr prev-styles))
|
||
(and next-styles (cdr next-styles)))])))
|
||
;; Loop through rows:
|
||
(let loop ([blockss blockss]
|
||
[cell-styless cell-styless]
|
||
[prev-styles #f]) ; for 'bottom-border styles
|
||
(let ([flows (car blockss)]
|
||
[cell-styles (car cell-styless)])
|
||
(unless index? (add-clines prev-styles cell-styles))
|
||
(define group-size
|
||
(cond
|
||
[merge-index?
|
||
;; Merge entries that have the same text & style
|
||
(let loop ([blockss (cdr blockss)] [group-size 1])
|
||
(cond
|
||
[(null? blockss) group-size]
|
||
[(same-index-entry? flows (car blockss))
|
||
(loop (cdr blockss) (add1 group-size))]
|
||
[else group-size]))]
|
||
[else 1]))
|
||
(let loop ([flows flows]
|
||
[cell-styles cell-styles]
|
||
[all-left-line?s all-left-line?s]
|
||
[need-left? #f])
|
||
(unless (null? flows)
|
||
(define (render-cell cnt)
|
||
(render-table-cell (car flows) part ri (/ twidth cnt) (car cell-styles) (not index?)))
|
||
(define right-line?
|
||
(cond
|
||
[index?
|
||
(printf "\n\\item ")
|
||
(parameterize ([multiple-page-references
|
||
(and (group-size . > . 1)
|
||
(extract-index-link-targets (take blockss group-size)))])
|
||
(render-cell 1))
|
||
#f]
|
||
[(eq? 'cont (car flows))
|
||
#f]
|
||
[else
|
||
(let ([cnt (let loop ([flows (cdr flows)][n 1])
|
||
(cond [(null? flows) n]
|
||
[(eq? (car flows) 'cont)
|
||
(loop (cdr flows) (add1 n))]
|
||
[else n]))])
|
||
(unless (= cnt 1) (printf "\\multicolumn{~a}{l}{" cnt))
|
||
(when (and (not (car all-left-line?s))
|
||
(or need-left?
|
||
(memq 'left-border (style-properties (car cell-styles)))
|
||
(memq 'border (style-properties (car cell-styles)))))
|
||
(printf "\\vline "))
|
||
(render-cell cnt)
|
||
(define right-line? (or (memq 'right-border (style-properties (list-ref cell-styles (sub1 cnt))))
|
||
(memq 'border (style-properties (list-ref cell-styles (sub1 cnt))))))
|
||
(when (and right-line? (null? (list-tail flows cnt)) (not all-right-line?))
|
||
(printf "\\vline "))
|
||
(unless (= cnt 1) (printf "}"))
|
||
(unless (null? (list-tail flows cnt))
|
||
(printf " &\n"))
|
||
right-line?)]))
|
||
(unless (null? (cdr flows)) (loop (cdr flows)
|
||
(cdr cell-styles)
|
||
(cdr all-left-line?s)
|
||
right-line?))))
|
||
(define rest-blockss (list-tail blockss group-size))
|
||
(unless (or index?
|
||
(and (null? rest-blockss)
|
||
(not (for/or ([cell-style (in-list cell-styles)])
|
||
(or (memq 'bottom-border (style-properties cell-style))
|
||
(memq 'border (style-properties cell-style)))))))
|
||
(printf " \\\\\n"))
|
||
(cond
|
||
[(null? rest-blockss)
|
||
(unless index? (add-clines cell-styles #f))]
|
||
[else
|
||
(loop rest-blockss (list-tail cell-styless group-size) cell-styles)])))
|
||
(unless inline?
|
||
(printf "\\end{~a}~a"
|
||
tableform
|
||
(if (string? s-name)
|
||
(format "\\end{~a}" s-name)
|
||
"")))))))
|
||
null)
|
||
|
||
(define/private (render-table-cell p part ri twidth vstyle can-box?)
|
||
(let* ([top? (or (memq 'top (style-properties vstyle))
|
||
(memq 'baseline (style-properties vstyle)))]
|
||
[bottom? (and (not top?)
|
||
(memq 'bottom (style-properties vstyle)))]
|
||
[center? (and (not bottom?)
|
||
(not top?))]
|
||
[as-box? (and can-box? (boxable? p))])
|
||
(when (string? (style-name vstyle))
|
||
(printf "\\~a{" (style-name vstyle)))
|
||
(let ([minipage? (and can-box? (not as-box?))])
|
||
(when minipage?
|
||
(printf "\\begin{minipage}~a{~a\\linewidth}\n"
|
||
(cond
|
||
[top? "[t]"]
|
||
[center? "[c]"]
|
||
[else ""])
|
||
(/ 1.0 twidth)))
|
||
(cond
|
||
[(table? p)
|
||
(render-table* p part ri #f (cond
|
||
[top? "[t]"]
|
||
[center? "[c]"]
|
||
[else "[b]"]))]
|
||
[as-box?
|
||
(render-boxable-block p part ri (cond
|
||
[top? 't]
|
||
[center? 'c]
|
||
[else 'b]))]
|
||
[else
|
||
(render-block p part ri #f)])
|
||
(when minipage?
|
||
(printf " \\end{minipage}\n")))
|
||
(when (string? (style-name vstyle))
|
||
(printf "}"))
|
||
null))
|
||
|
||
(define/private (boxable? p)
|
||
(or (and (table? p)
|
||
(for* ([l (in-list (table-blockss p))]
|
||
[p (in-list l)])
|
||
(boxable? p)))
|
||
(and (nested-flow? p)
|
||
(or (and (= 1 (length (nested-flow-blocks p)))
|
||
(memq (style-name (nested-flow-style p))
|
||
'(code-inset vertical-inset)))
|
||
(and
|
||
(ormap box-mode? (style-properties (nested-flow-style p)))
|
||
(andmap (lambda (p) (boxable? p)) (nested-flow-blocks p)))))
|
||
(and (paragraph? p)
|
||
(or (not (style-name (paragraph-style p)))
|
||
(ormap box-mode? (style-properties (paragraph-style p)))))))
|
||
|
||
(define/private (render-boxable-block p part ri mode)
|
||
(cond
|
||
[(table? p)
|
||
(render-table* p part ri #f (format "[~a]" mode))]
|
||
[(nested-flow? p)
|
||
(do-render-nested-flow p part ri #f mode #f)]
|
||
[(paragraph? p)
|
||
(do-render-paragraph p part ri #f mode)]))
|
||
|
||
(define/private (box-mode-selector as-box-mode)
|
||
(case as-box-mode
|
||
[(t) box-mode-top-name]
|
||
[(c) box-mode-center-name]
|
||
[(b) box-mode-bottom-name]))
|
||
|
||
(define/override (render-itemization t part ri)
|
||
(let* ([style-str (let ([s (style-name (itemization-style t))])
|
||
(if (eq? s 'compact)
|
||
"compact"
|
||
s))]
|
||
[mode (or (and (string? style-str)
|
||
style-str)
|
||
(if (eq? 'ordered style-str)
|
||
"enumerate"
|
||
"itemize"))])
|
||
(printf "\\begin{~a}\\atItemizeStart" mode)
|
||
(for ([flow (in-list (itemization-blockss t))])
|
||
(printf "\n\n\\~a" (if (string? style-str)
|
||
(format "~aItem{" style-str)
|
||
"item "))
|
||
(render-flow flow part ri #t)
|
||
(when (string? style-str)
|
||
(printf "}")))
|
||
(printf "\\end{~a}" mode)
|
||
null))
|
||
|
||
(define/private (do-render-nested-flow t part ri single-column? as-box-mode show-pre?)
|
||
(let* ([props (style-properties (nested-flow-style t))]
|
||
[kind (or (and as-box-mode
|
||
(or
|
||
(ormap (lambda (a)
|
||
(and (box-mode? a)
|
||
((box-mode-selector as-box-mode) a)))
|
||
props)
|
||
(case (style-name (nested-flow-style t))
|
||
[(code-inset) "SCodeInsetBox"]
|
||
[(vertical-inset) "SVInsetBox"]
|
||
[else (error "unexpected style for box mode")])))
|
||
(let ([s (style-name (nested-flow-style t))])
|
||
(or (and (string? s) s)
|
||
(and (eq? s 'inset) "SInsetFlow")
|
||
(and (eq? s 'code-inset) "SCodeFlow")
|
||
(and (eq? s 'vertical-inset) "SVInsetFlow")))
|
||
"Subflow")]
|
||
[multicommand? (memq 'multicommand props)]
|
||
[command? (or (and as-box-mode (not multicommand?))
|
||
(memq 'command props))])
|
||
(unless (and (not show-pre?)
|
||
(member 'pretitle props))
|
||
(cond
|
||
[command? (printf "\\~a{" kind)]
|
||
[multicommand? (printf "\\~a" kind)]
|
||
[else (printf "\\begin{~a}" kind)])
|
||
(parameterize ([current-table-mode (if (or single-column?
|
||
(not (current-table-mode)))
|
||
(current-table-mode)
|
||
(list "nested-flow" t))])
|
||
(if as-box-mode
|
||
(for-each (lambda (p)
|
||
(when multicommand? (printf "{"))
|
||
(render-boxable-block p part ri as-box-mode)
|
||
(when multicommand? (printf "}")))
|
||
(nested-flow-blocks t))
|
||
(render-flow (nested-flow-blocks t) part ri #f multicommand?)))
|
||
(cond
|
||
[command? (printf "}")]
|
||
[multicommand? (void)]
|
||
[else (printf "\\end{~a}" kind)])
|
||
null)))
|
||
|
||
(define/override (render-nested-flow t part ri starting-item?)
|
||
(do-render-nested-flow t part ri #f #f #f))
|
||
|
||
(define/override (render-compound-paragraph t part ri starting-item?)
|
||
(let ([kind (style-name (compound-paragraph-style t))]
|
||
[command? (memq 'command (style-properties (compound-paragraph-style t)))])
|
||
(when kind
|
||
(if command?
|
||
(printf "\\~a{" kind)
|
||
(printf "\\begin{~a}" kind)))
|
||
(super render-compound-paragraph t part ri starting-item?)
|
||
(when kind
|
||
(if command?
|
||
(printf "}")
|
||
(printf "\\end{~a}" kind)))
|
||
null))
|
||
|
||
(define/override (render-other i part ri)
|
||
(cond
|
||
[(string? i) (display-protected i)]
|
||
[(symbol? i)
|
||
(display (case i
|
||
[(nbsp) "~"]
|
||
[(mdash) "{---}"]
|
||
[(ndash) "{--}"]
|
||
[(ldquo) "{``}"]
|
||
[(rdquo) "{''}"]
|
||
[(rsquo) "{'}"]
|
||
[(lsquo) "{`}"]
|
||
[(prime) "$'$"]
|
||
[(rarr) "$\\rightarrow$"]
|
||
[(larr) "$\\leftarrow$"]
|
||
[(alpha) "$\\alpha$"]
|
||
[(infin) "$\\infty$"]
|
||
[(lang) "$\\langle$"]
|
||
[(rang) "$\\rangle$"]
|
||
[else (error 'render "unknown symbol element: ~e" i)]))]
|
||
[else (display-protected (format "~s" i))])
|
||
null)
|
||
|
||
(define/override (string-to-implicit-styles e)
|
||
(for/fold ([ses null]) ([ch (in-string e)])
|
||
(case ch
|
||
[(#\☠) (cons skull-style ses)]
|
||
[else ses])))
|
||
|
||
(define/private (display-protected s)
|
||
(define rtt (rendering-tt))
|
||
(define convs (extra-character-conversions))
|
||
(cond
|
||
[(eq? rtt 'exact)
|
||
(display s)]
|
||
[(eq? rtt 'url)
|
||
(for ([c (in-string s)])
|
||
(case c
|
||
[(#\%) (display "\\%")]
|
||
[(#\#) (display "\\#")]
|
||
[(#\\) (display "\\%5c")]
|
||
[(#\{) (display "\\%7b")]
|
||
[(#\}) (display "\\%7d")]
|
||
[else (display c)]))]
|
||
[else
|
||
;; Start by normalizing to "combined" form, so that Racket characters
|
||
;; are closer to Unicode characters (e.g., ä is one character, instead
|
||
;; of a combining character followed by "a").
|
||
(let ([s (string-normalize-nfc s)])
|
||
(let ([len (string-length s)])
|
||
(let loop ([i 0])
|
||
(unless (= i len)
|
||
(display
|
||
(let char-loop ([c (string-ref s i)])
|
||
(case c
|
||
[(#\\) (if (rendering-tt)
|
||
"{\\char`\\\\}"
|
||
"$\\backslash$")]
|
||
[(#\_) (if (rendering-tt)
|
||
"{\\char`\\_}"
|
||
"$\\_$")]
|
||
[(#\^) "{\\char'136}"]
|
||
[(#\>) (if (rendering-tt) "{\\Stttextmore}" "$>$")]
|
||
[(#\<) (if (rendering-tt) "{\\Stttextless}" "$<$")]
|
||
[(#\|) (if (rendering-tt) "{\\Stttextbar}" "$|$")]
|
||
[(#\-) "{-}"] ;; avoid en- or em-dash
|
||
[(#\`) "{\\textasciigrave}"]
|
||
[(#\') "{\\textquotesingle}"]
|
||
[(#\? #\! #\. #\:)
|
||
(if (rendering-tt) (format "{\\hbox{\\texttt{~a}}}" c) c)]
|
||
[(#\~) "$\\sim$"]
|
||
[(#\{ #\}) (if (rendering-tt)
|
||
(format "{\\char`\\~a}" c)
|
||
(format "\\~a" c))]
|
||
[(#\[ #\]) (if (escape-brackets)
|
||
(if (eq? c #\[)
|
||
"{\\SOpenSq}"
|
||
"{\\SCloseSq}")
|
||
c)]
|
||
[(#\# #\% #\& #\$) (format "\\~a" c)]
|
||
[(#\uA0) "~"] ; non-breaking space
|
||
[(#\uAD) "\\-"] ; soft hyphen; unfortunately, also disables auto-hyphen
|
||
[(#\uDF) "{\\ss}"]
|
||
[else
|
||
(if ((char->integer c) . > . 127)
|
||
;; first, try user-defined conversions
|
||
(or (convs c)
|
||
;; latex-prefix.rkt enables utf8 input, but this does not work for
|
||
;; all the characters below (e.g. ∞). Some parts of the table
|
||
;; below are therefore necessary, but some parts probably are not.
|
||
;; Which parts are necessary may depend on the latex version,
|
||
;; though, so we keep this table around to avoid regressions.
|
||
(case c
|
||
[(#\╔ #\═ #\╗ #\║ #\╚ #\╝ #\╦ #\╠ #\╣ #\╬ #\╩) (box-character c)]
|
||
[(#\┌ #\─ #\┐ #\│ #\└ #\┘ #\┬ #\├ #\┤ #\┼ #\┴) (box-character c)]
|
||
[(#\┏ #\━ #\┓ #\┃ #\┗ #\┛ #\┳ #\┣ #\┫ #\╋ #\┻) (box-character c 2)]
|
||
[(#\u2011) "\\mbox{-}"] ; non-breaking hyphen
|
||
[(#\uB0) "$^{\\circ}$"] ; degree
|
||
[(#\uB2) "$^2$"]
|
||
[(#\u039A) "K"] ; kappa
|
||
[(#\u0391) "A"] ; alpha
|
||
[(#\u039F) "O"] ; omicron
|
||
[(#\u03A3) "$\\Sigma$"]
|
||
[(#\u03BA) "$\\kappa$"]
|
||
[(#\u03B1) "$\\alpha$"]
|
||
[(#\u03B2) "$\\beta$"]
|
||
[(#\u03B3) "$\\gamma$"]
|
||
[(#\u03BF) "o"] ; omicron
|
||
[(#\u03C3) "$\\sigma$"]
|
||
[(#\u03C2) "$\\varsigma$"]
|
||
[(#\u03BB) "$\\lambda$"]
|
||
[(#\u039B) "$\\Lambda$"]
|
||
[(#\u03BC) "$\\mu$"]
|
||
[(#\u03C0) "$\\pi$"]
|
||
[(#\₀) "$_0$"]
|
||
[(#\₁) "$_1$"]
|
||
[(#\₂) "$_2$"]
|
||
[(#\₃) "$_3$"]
|
||
[(#\₄) "$_4$"]
|
||
[(#\₅) "$_5$"]
|
||
[(#\₆) "$_6$"]
|
||
[(#\₇) "$_7$"]
|
||
[(#\₈) "$_8$"]
|
||
[(#\₉) "$_9$"]
|
||
[(#\‘) "{`}"]
|
||
[(#\’) "{'}"]
|
||
[(#\“) "{``}"]
|
||
[(#\”) "{''}"]
|
||
[(#\u2013) "{--}"]
|
||
[(#\u2014) "{---}"]
|
||
[(#\⟨ #\〈) "$\\langle$"] ; [MATHEMATICAL] LEFT ANGLE BRACKET
|
||
[(#\⟩ #\〉) "$\\rangle$"] ; [MATHEMATICAL] RIGHT ANGLE BRACKET
|
||
[(#\∞) "$\\infty$"]
|
||
[(#\⇓) "$\\Downarrow$"]
|
||
[(#\↖) "$\\nwarrow$"]
|
||
[(#\↓) "$\\downarrow$"]
|
||
[(#\⇒) "$\\Rightarrow$"]
|
||
[(#\→) "$\\rightarrow$"]
|
||
[(#\↘) "$\\searrow$"]
|
||
[(#\↙) "$\\swarrow$"]
|
||
[(#\←) "$\\leftarrow$"]
|
||
[(#\↑) "$\\uparrow$"]
|
||
[(#\⇐) "$\\Leftarrow$"]
|
||
[(#\−) "$\\longrightarrow$"]
|
||
[(#\⇑) "$\\Uparrow$"]
|
||
[(#\⇔) "$\\Leftrightarrow$"]
|
||
[(#\↕) "$\\updownarrow$"]
|
||
[(#\↔) "$\\leftrightarrow$"]
|
||
[(#\↗) "$\\nearrow$"]
|
||
[(#\↝) "$\\leadsto$"]
|
||
[(#\↱) "$\\Lsh$"]
|
||
[(#\↰) "$\\Rsh$"]
|
||
[(#\⇕) "$\\Updownarrow$"]
|
||
[(#\א) "$\\aleph$"]
|
||
[(#\′) "$\\prime$"]
|
||
[(#\∅) "$\\emptyset$"]
|
||
[(#\∇) "$\\nabla$"]
|
||
[(#\♦) "$\\diamondsuit$"]
|
||
[(#\♠) "$\\spadesuit$"]
|
||
[(#\♣) "$\\clubsuit$"]
|
||
[(#\♥) "$\\heartsuit$"]
|
||
[(#\♯) "$\\sharp$"]
|
||
[(#\♭) "$\\flat$"]
|
||
[(#\♮) "$\\natural$"]
|
||
[(#\√) "$\\surd$"]
|
||
[(#\∆) "$\\Delta$"] ; no better mapping for than \Delta for "increment"
|
||
[(#\u2211) "$\\sum$"] ; better than \Sigma, right?
|
||
[(#\u220F) "$\\prod$"] ; better than \Pi, right?
|
||
[(#\u2210) "$\\coprod$"]
|
||
[(#\u222B) "$\\int$"]
|
||
[(#\u222E) "$\\oint$"]
|
||
[(#\¬) "$\\neg$"]
|
||
[(#\△) "$\\triangle$"]
|
||
[(#\∀) "$\\forall$"]
|
||
[(#\∃) "$\\exists$"]
|
||
[(#\∘) "$\\circ$"]
|
||
[(#\θ) "$\\theta$"]
|
||
[(#\ϑ) "$\\vartheta$"]
|
||
[(#\τ) "$\\tau$"]
|
||
[(#\υ) "$\\upsilon$"]
|
||
[(#\φ) "$\\varphi$"]
|
||
[(#\ϕ) "$\\phi$"]
|
||
[(#\δ) "$\\delta$"]
|
||
[(#\ρ) "$\\rho$"]
|
||
[(#\ϱ) "$\\varrho$"]
|
||
[(#\ϵ) "$\\epsilon$"]
|
||
[(#\ε) "$\\varepsilon$"]
|
||
[(#\ϖ) "$\\varpi$"]
|
||
[(#\χ) "$\\chi$"]
|
||
[(#\ψ) "$\\psi$"]
|
||
[(#\ζ) "$\\zeta$"]
|
||
[(#\ν) "$\\nu$"]
|
||
[(#\ω) "$\\omega$"]
|
||
[(#\η) "$\\eta$"]
|
||
[(#\ι) "$\\iota$"]
|
||
[(#\ξ) "$\\xi$"]
|
||
[(#\Γ) "$\\Gamma$"]
|
||
[(#\Ψ) "$\\Psi$"]
|
||
[(#\Δ) "$\\Delta$"]
|
||
[(#\Ξ) "$\\Xi$"]
|
||
[(#\Υ) "$\\Upsilon$"]
|
||
[(#\Ω) "$\\Omega$"]
|
||
[(#\Θ) "$\\Theta$"]
|
||
[(#\Π) "$\\Pi$"]
|
||
[(#\Φ) "$\\Phi$"]
|
||
[(#\±) "$\\pm$"]
|
||
[(#\∩) "$\\cap$"]
|
||
[(#\◇) "$\\diamond$"]
|
||
[(#\⊕) "$\\oplus$"]
|
||
[(#\∓) "$\\mp$"]
|
||
[(#\∪) "$\\cup$"]
|
||
[(#\△) "$\\bigtriangleup$"]
|
||
[(#\⊖) "$\\ominus$"]
|
||
[(#\×) "$\\times$"]
|
||
[(#\⊎) "$\\uplus$"]
|
||
[(#\▽) "$\\bigtriangledown$"]
|
||
[(#\⊗) "$\\otimes$"]
|
||
[(#\÷) "$\\div$"]
|
||
[(#\⊓) "$\\sqcap$"]
|
||
[(#\▹) "$\\triangleleft$"]
|
||
[(#\⊘) "$\\oslash$"]
|
||
[(#\∗) "$\\ast$"]
|
||
[(#\⊔) "$\\sqcup$"]
|
||
[(#\∨) "$\\vee$"]
|
||
[(#\∧) "$\\wedge$"]
|
||
[(#\◃) "$\\triangleright$"]
|
||
[(#\◊) "$\\Diamond$"]
|
||
[(#\⊙) "$\\odot$"]
|
||
[(#\★) "$\\star$"]
|
||
[(#\†) "$\\dagger$"]
|
||
[(#\•) "$\\bullet$"]
|
||
[(#\‡) "$\\ddagger$"]
|
||
[(#\≀) "$\\wr$"]
|
||
[(#\⨿) "$\\amalg$"]
|
||
[(#\≤) "$\\leq$"]
|
||
[(#\≥) "$\\geq$"]
|
||
[(#\≡) "$\\equiv$"]
|
||
[(#\⊨) "$\\models$"]
|
||
[(#\≺) "$\\prec$"]
|
||
[(#\≻) "$\\succ$"]
|
||
[(#\∼) "$\\sim$"]
|
||
[(#\⊥) "$\\perp$"]
|
||
[(#\≼) "$\\preceq$"]
|
||
[(#\≽) "$\\succeq$"]
|
||
[(#\≃) "$\\simeq$"]
|
||
[(#\≪) "$\\ll$"]
|
||
[(#\≫) "$\\gg$"]
|
||
[(#\≍) "$\\asymp$"]
|
||
[(#\∥) "$\\parallel$"]
|
||
[(#\⊂) "$\\subset$"]
|
||
[(#\⊃) "$\\supset$"]
|
||
[(#\≈) "$\\approx$"]
|
||
[(#\⋈) "$\\bowtie$"]
|
||
[(#\⊆) "$\\subseteq$"]
|
||
[(#\⊇) "$\\supseteq$"]
|
||
[(#\≌) "$\\cong$"]
|
||
[(#\⊏) "$\\sqsubset$"]
|
||
[(#\⊐) "$\\sqsupset$"]
|
||
[(#\≠) "$\\neq$"]
|
||
[(#\⌣) "$\\smile$"]
|
||
[(#\⊑) "$\\sqsubseteq$"]
|
||
[(#\⊒) "$\\sqsupseteq$"]
|
||
[(#\≐) "$\\doteq$"]
|
||
[(#\⌢) "$\\frown$"]
|
||
[(#\∈) "$\\in$"]
|
||
[(#\∉) "$\\not\\in$"]
|
||
[(#\∋) "$\\ni$"]
|
||
[(#\∝) "$\\propto$"]
|
||
[(#\⊢) "$\\vdash$"]
|
||
[(#\⊣) "$\\dashv$"]
|
||
[(#\☠) "$\\skull$"]
|
||
[(#\☺) "$\\smiley$"]
|
||
[(#\☻) "$\\blacksmiley$"]
|
||
[(#\☹) "$\\frownie$"]
|
||
[(#\ø) "{\\o}"]
|
||
[(#\Ø) "{\\O}"]
|
||
[(#\ł) "{\\l}"]
|
||
[(#\Ł) "{\\L}"]
|
||
[(#\uA7) "{\\S}"]
|
||
[(#\⟦ #\〚) "$[\\![$"]
|
||
[(#\⟧ #\〛) "$]\\!]$"]
|
||
[(#\↦) "$\\mapsto$"]
|
||
[(#\⊤) "$\\top$"]
|
||
[(#\¥) "{\\textyen}"]
|
||
[(#\™) "{\\texttrademark}"]
|
||
[(#\®) "{\\textregistered}"]
|
||
[(#\©) "{\\textcopyright}"]
|
||
[(#\u2070) "$^0$"]
|
||
[(#\u00b9) "$^1$"]
|
||
[(#\u00b2) "$^2$"]
|
||
[(#\u00b3) "$^3$"]
|
||
[(#\u2074) "$^4$"]
|
||
[(#\u2075) "$^5$"]
|
||
[(#\u2076) "$^6$"]
|
||
[(#\u2077) "$^7$"]
|
||
[(#\u2078) "$^8$"]
|
||
[(#\u2079) "$^9$"]
|
||
[(#\u207a) "$^+$"]
|
||
[(#\u207b) "$^-$"]
|
||
[(#\⋖) "$\\precdot$"]
|
||
[(#\⋗) "$\\succdot$"]
|
||
[(#\⋮) "\\vdots"]
|
||
[(#\⋱) "$\\ddots$"]
|
||
[(#\⋯) "$\\cdots$"]
|
||
[(#\⋯) "\\hdots"]
|
||
[else
|
||
(cond
|
||
[(char<=? #\uAC00 c #\uD7AF) ; Korean Hangul
|
||
(format "\\begin{CJK}{UTF8}{mj}~a\\end{CJK}" c)]
|
||
[else
|
||
;; Detect characters that can be formed with combining characters
|
||
;; and translate them to Latex combinations:
|
||
(define s (string-normalize-nfd (string c)))
|
||
(define len (string-length s))
|
||
(cond
|
||
[(len . > . 1)
|
||
(define combiner (case (string-ref s (sub1 len))
|
||
[(#\u300) "\\`{~a}"]
|
||
[(#\u301) "\\'{~a}"]
|
||
[(#\u302) "\\^{~a}"]
|
||
[(#\u303) "\\~~{~a}"]
|
||
[(#\u304) "\\={~a}"]
|
||
[(#\u306) "\\u{~a}"]
|
||
[(#\u307) "\\.{~a}"]
|
||
[(#\u308) "\\\"{~a}"]
|
||
[(#\u30a) "\\r{~a}"]
|
||
[(#\u30b) "\\H{~a}"]
|
||
[(#\u30c) "\\v{~a}"]
|
||
[(#\u327) "\\c{~a}"]
|
||
[(#\u328) "\\k{~a}"]
|
||
[else #f]))
|
||
(define base (string-normalize-nfc (substring s 0 (sub1 len))))
|
||
(if (and combiner
|
||
(= 1 (string-length base)))
|
||
(format combiner (char-loop (string-ref base 0)))
|
||
c)]
|
||
[else c])])]))
|
||
c)])))
|
||
(loop (add1 i))))))]))
|
||
|
||
|
||
(define/private (box-character c [line-thickness 1])
|
||
(define (combine . args)
|
||
(apply string-append
|
||
"\\setlength{\\unitlength}{0.05em}"
|
||
(if (= line-thickness 1)
|
||
""
|
||
(format "\\linethickness{~apt}" (* 0.4 line-thickness)))
|
||
(filter (λ (x) (not (regexp-match #rx"^[ \n]*$" x)))
|
||
(flatten args))))
|
||
(define (adjust % v)
|
||
(define num (* % (/ v 10) 10))
|
||
(define i-part (floor num))
|
||
(define d-part (floor (* 10 (- num i-part))))
|
||
(format "~a.~a" i-part d-part))
|
||
(define (x v) (adjust 1 v))
|
||
(define (y v) (adjust 6/4 v))
|
||
(define upper-horizontal @list{\put(@x[0],@y[6]){\line(1,0){@x[10]}}})
|
||
(define mid-horizontal @list{\put(@x[0],@y[5]){\line(1,0){@x[10]}}})
|
||
(define lower-horizontal @list{\put(@x[0],@y[4]){\line(1,0){@x[10]}}})
|
||
(define righter-vertical @list{\put(@x[6],@y[10]){\line(0,-1){@y[10]}}})
|
||
(define mid-vertical @list{\put(@x[5],@y[10]){\line(0,-1){@y[10]}}})
|
||
(define lefter-vertical @list{\put(@x[4],@y[10]){\line(0,-1){@y[10]}}})
|
||
(define bottom-right @list{\put(@x[6],@y[4]){\line(1,0){@x[4]}}
|
||
\put(@x[6],@y[0]){\line(0,1){@y[4]}}})
|
||
(define bottom-left @list{\put(@x[0],@y[4]){\line(1,0){@x[4]}}
|
||
\put(@x[4],@y[0]){\line(0,1){@y[4]}}})
|
||
(define upper-right @list{\put(@x[6],@y[6]){\line(1,0){@x[4]}}
|
||
\put(@x[6],@y[10]){\line(0,-1){@y[4]}}})
|
||
(define upper-left @list{\put(@x[0],@y[6]){\line(1,0){@x[4]}}
|
||
\put(@x[4],@y[10]){\line(0,-1){@y[4]}}})
|
||
(define header @list{\begin{picture}(@x[10],@y[10])(0,0)})
|
||
(define footer @list{\end{picture}})
|
||
|
||
(case c
|
||
[(#\╔)
|
||
@combine{@header
|
||
\put(@x[4],@y[6]){\line(1,0){@x[6]}}
|
||
\put(@x[4],@y[0]){\line(0,1){@y[6]}}
|
||
@bottom-right
|
||
@footer}]
|
||
[(#\═) @combine{@header
|
||
@upper-horizontal
|
||
@lower-horizontal
|
||
@footer}]
|
||
[(#\╗) @combine{@header
|
||
\put(@x[0],@y[6]){\line(1,0){@x[6]}}
|
||
\put(@x[6],@y[0]){\line(0,1){@y[6]}}
|
||
@bottom-left
|
||
@footer}]
|
||
[(#\║) @combine{@header
|
||
@lefter-vertical
|
||
@righter-vertical
|
||
@footer}]
|
||
[(#\╚) @combine{@header
|
||
@upper-right
|
||
\put(@x[4],@y[4]){\line(1,0){@x[6]}}
|
||
\put(@x[4],@y[10]){\line(0,-1){@y[6]}}
|
||
@footer}]
|
||
[(#\╝)
|
||
@combine{@header
|
||
@upper-left
|
||
\put(@x[0],@y[4]){\line(1,0){@x[6]}}
|
||
\put(@x[6],@y[10]){\line(0,-1){@y[6]}}
|
||
@footer}]
|
||
[(#\╣)
|
||
@combine{@header
|
||
@upper-left
|
||
@bottom-left
|
||
@righter-vertical
|
||
@footer}]
|
||
[(#\╠)
|
||
@combine{@header
|
||
@upper-right
|
||
@bottom-right
|
||
@lefter-vertical
|
||
@footer}]
|
||
[(#\╩)
|
||
@combine{@header
|
||
@upper-right
|
||
@upper-left
|
||
@lower-horizontal
|
||
@footer}]
|
||
[(#\╦)
|
||
@combine{@header
|
||
@bottom-right
|
||
@bottom-left
|
||
@upper-horizontal
|
||
@footer}]
|
||
[(#\╬)
|
||
@combine{@header
|
||
@upper-left
|
||
@bottom-left
|
||
@upper-right
|
||
@bottom-right
|
||
@footer}]
|
||
[(#\┌ #\┏)
|
||
@combine{@header
|
||
\put(@x[5],@y[5]){\line(1,0){@x[5]}}
|
||
\put(@x[5],@y[0]){\line(0,1){@y[5]}}
|
||
@footer}]
|
||
[(#\─ #\━) @combine{@header
|
||
@mid-horizontal
|
||
@footer}]
|
||
[(#\┐ #\┓) @combine{@header
|
||
\put(@x[0],@y[5]){\line(1,0){@x[5]}}
|
||
\put(@x[5],@y[0]){\line(0,1){@y[5]}}
|
||
@footer}]
|
||
[(#\│ #\┃) @combine{@header
|
||
@mid-vertical
|
||
@footer}]
|
||
[(#\└ #\┗) @combine{@header
|
||
\put(@x[5],@y[5]){\line(1,0){@x[5]}}
|
||
\put(@x[5],@y[10]){\line(0,-1){@y[5]}}
|
||
@footer}]
|
||
[(#\┘ #\┛)
|
||
@combine{@header
|
||
\put(@x[0],@y[5]){\line(1,0){@x[5]}}
|
||
\put(@x[5],@y[10]){\line(0,-1){@y[5]}}
|
||
@footer}]
|
||
[(#\┤ #\┫)
|
||
@combine{@header
|
||
\put(@x[0],@y[5]){\line(1,0){@x[5]}}
|
||
@mid-vertical
|
||
@footer}]
|
||
[(#\├ #\┣)
|
||
@combine{@header
|
||
\put(@x[5],@y[5]){\line(1,0){@x[5]}}
|
||
@mid-vertical
|
||
@footer}]
|
||
[(#\┴ #\┻)
|
||
@combine{@header
|
||
\put(@x[5],@y[10]){\line(0,-1){@y[5]}}
|
||
@mid-horizontal
|
||
@footer}]
|
||
[(#\┬ #\┳)
|
||
@combine{@header
|
||
\put(@x[5],@y[5]){\line(0,-1){@y[5]}}
|
||
@mid-horizontal
|
||
@footer}]
|
||
[(#\┼ #\╋)
|
||
@combine{@header
|
||
@mid-horizontal
|
||
@mid-vertical
|
||
@footer}]))
|
||
|
||
;; ----------------------------------------
|
||
|
||
(define/override (table-of-contents sec ri)
|
||
;; FIXME: isn't local to the section
|
||
(make-toc-paragraph plain null))
|
||
|
||
(define/override (local-table-of-contents part ri style)
|
||
(make-paragraph plain null))))
|