#lang racket/base (require racket/list racket/match racket/port racket/runtime-path racket/string xml) (define-runtime-path *js-path* "./mathml-render.js") (provide transform-xexprs get-styles) (define (mathtex-type? s) (and (string? s) (regexp-match #rx"^math/tex" s) #t)) (define (transform-xexprs xexprs) (map transform-xexpr xexprs)) (define (run-mathjax source block?) (define-values [proc out in err] (subprocess #f #f #f "/usr/bin/env" "node" (path->string *js-path*))) (define out-str #f) (define err-str "") (define out-reader (thread (λ () (set! out-str (port->string out))))) (define err-reader (thread (λ () (set! err-str (port->string err))))) (write-string source in) (flush-output in) (close-output-port in) (subprocess-wait proc) (thread-wait out-reader) (thread-wait err-reader) (define err-trimmed (string-trim err-str)) (unless (string=? "" err-trimmed) (error "mathjax process raised error!" err-trimmed)) (unless out-str (error "mathjax process didn't return anything!")) (match-define (list 'math attrs bodies ...) (string->xexpr out-str)) `(math ,(cons (list 'display (if block? "block" "inline")) (filter (λ (x) (not (eq? (first x) 'display))) attrs)) ,@bodies)) (define (transform-xexpr xexpr) (match xexpr [(list 'script (list (list 'type (? mathtex-type? type))) bodies ...) (define body (apply string-append bodies)) (define block? (> (length (string-split type " ")) 1)) (run-mathjax body block?)] [(list tag attrs body ...) (cons tag (cons attrs (map transform-xexpr body)))] [(? string? str) str])) (define (get-styles) "")