This commit is contained in:
@@ -9,10 +9,10 @@
|
|||||||
[net.deertopia.doerg.html :as doerg-html]
|
[net.deertopia.doerg.html :as doerg-html]
|
||||||
[hiccup2.core :as hiccup]
|
[hiccup2.core :as hiccup]
|
||||||
[clojure.pprint]
|
[clojure.pprint]
|
||||||
#_
|
;; #_
|
||||||
[net.deertopia.doerg.tex :as tex]
|
[net.deertopia.doerg.tex :as tex]
|
||||||
[net.deertopia.doerg.tex.native :as tex-native]
|
;; [net.deertopia.doerg.tex.native :as tex-native]
|
||||||
[net.deertopia.doerg.tex.temml :as tex-temml]
|
;; [net.deertopia.doerg.tex.temml :as tex-temml]
|
||||||
[clojure.zip :as z]
|
[clojure.zip :as z]
|
||||||
[babashka.fs :as fs]))
|
[babashka.fs :as fs]))
|
||||||
|
|
||||||
@@ -143,72 +143,28 @@
|
|||||||
#(element/of-keyword-type? % "LATEX_HEADER")
|
#(element/of-keyword-type? % "LATEX_HEADER")
|
||||||
(sp/view :value)])))
|
(sp/view :value)])))
|
||||||
|
|
||||||
(defn- read-and-patch-generated-svg [{:keys [file height depth]}]
|
|
||||||
;; dvisvgm writes standalone SVG files, to which we need to make a
|
|
||||||
;; few changes to use them inline within our HTML.
|
|
||||||
;; • XML header: Bad syntax when embedded in an HTML doc. Remove
|
|
||||||
;; it.
|
|
||||||
;; • Width and height: We override these with our own values
|
|
||||||
;; computed by `net.deertopia.doerg.tex` to ensure correct
|
|
||||||
;; positioning relative to the surrounding text. More
|
|
||||||
;; accurately, we remove the height and width attributes from
|
|
||||||
;; the SVG tag, and set the new values for height and
|
|
||||||
;; vertical-align in the style attribute
|
|
||||||
;; • Viewbox: Must be removed entirely for correct positioning.
|
|
||||||
(-> (slurp file)
|
|
||||||
(str/replace-first #"<\?xml version='1.0' encoding='UTF-8'\?>\n?" "")
|
|
||||||
(str/replace-first #" height=['\"][^\"']+[\"']" "")
|
|
||||||
(str/replace-first #" width=['\"][^\"']+[\"']" "")
|
|
||||||
(str/replace-first
|
|
||||||
#"viewBox=['\"][^\"']+[\"']"
|
|
||||||
(fn [s]
|
|
||||||
(format "%s style=\"%s\""
|
|
||||||
s
|
|
||||||
(format "height:%.4fem;vertical-align:%.4fem;display:inline-block"
|
|
||||||
height (- depth)))))))
|
|
||||||
|
|
||||||
(defn render-tex-snippets
|
(defn render-tex-snippets
|
||||||
"Traverse doc, adorning each LaTeX node with a promise resolving to,
|
"Traverse doc, adorning each LaTeX node with a promise resolving to,
|
||||||
optimistically, Hiccup-rendered SVG or MathML code."
|
optimistically, Hiccup-rendered SVG or MathML code."
|
||||||
[doc]
|
[doc]
|
||||||
(let [promises (atom [])
|
(let [snippet-promises (atom [])
|
||||||
r (->> doc (sp/transform
|
r (->> doc (sp/transform
|
||||||
[element/postorder-walker
|
[element/postorder-walker
|
||||||
#(element/of-type?
|
#(element/of-type?
|
||||||
% "latex-fragment" "latex-environment")]
|
% "latex-fragment" "latex-environment")]
|
||||||
(fn [node]
|
(fn [node]
|
||||||
(let [p (promise)]
|
(let [p (promise)]
|
||||||
(swap! promises #(conj % {:promise p :node node}))
|
(swap! snippet-promises #(conj % [(:value node) p]))
|
||||||
(assoc node ::rendered p)))))
|
(assoc node ::rendered p)))))
|
||||||
f (fn []
|
fut (-> #(tex/render-snippets @snippet-promises)
|
||||||
(fs/with-temp-dir [svg-dir {:prefix "doerg-svg"}]
|
bound-fn* future-call)]
|
||||||
(let [rendered-snippets
|
|
||||||
(delay (->> @promises
|
|
||||||
(map #(-> % :node :value))
|
|
||||||
(apply tex-native/render svg-dir)))]
|
|
||||||
(doseq [{:keys [promise node]} @promises]
|
|
||||||
(try (let [{:keys [value]} node
|
|
||||||
temml (tex-temml/render value)]
|
|
||||||
(if (tex-temml/erroneous-output? temml)
|
|
||||||
(let [tex (get @rendered-snippets value)]
|
|
||||||
(if (:errors tex)
|
|
||||||
(deliver promise (hiccup/raw temml))
|
|
||||||
(->> tex
|
|
||||||
read-and-patch-generated-svg
|
|
||||||
hiccup/raw
|
|
||||||
(deliver promise))))
|
|
||||||
(deliver promise (hiccup/raw temml))))
|
|
||||||
(catch Exception e
|
|
||||||
(lr/error e)
|
|
||||||
(throw e)))))))
|
|
||||||
fut (future-call (bound-fn* f))]
|
|
||||||
;; Time out after eight seconds. With all the LaTeX and IPC, there
|
;; Time out after eight seconds. With all the LaTeX and IPC, there
|
||||||
;; are so many opportunities for things to go wrong </3.
|
;; are so many opportunities for things to go wrong </3.
|
||||||
(let [fut-res (deref fut (* 10 1000) ::timed-out)]
|
(let [fut-res (deref fut (* 10 1000) ::timed-out)]
|
||||||
(if (= fut-res ::timed-out)
|
(if (= fut-res ::timed-out)
|
||||||
(do (future-cancel fut)
|
(do (future-cancel fut)
|
||||||
(doseq [{:keys [promise]} @promises]
|
(doseq [[_snippet p] @snippet-promises]
|
||||||
(deliver promise ::timed-out)))
|
(deliver p ::timed-out)))
|
||||||
fut-res))
|
fut-res))
|
||||||
r))
|
r))
|
||||||
|
|
||||||
|
|||||||
@@ -1,4 +1,60 @@
|
|||||||
(ns net.deertopia.doerg.tex
|
(ns net.deertopia.doerg.tex
|
||||||
(:require [net.deertopia.doerg.tex.native :as native]
|
(:require [net.deertopia.doerg.tex.native :as native]
|
||||||
[net.deertopia.doerg.tex.temml :as temml]
|
[net.deertopia.doerg.tex.temml :as temml]
|
||||||
[babashka.fs :as fs]))
|
[babashka.fs :as fs]
|
||||||
|
[clojure.string :as str]
|
||||||
|
[hiccup2.core :as hiccup]
|
||||||
|
[clojure.tools.logging :as l]))
|
||||||
|
|
||||||
|
(defn- read-and-patch-generated-svg [{:keys [file height depth]}]
|
||||||
|
;; dvisvgm writes standalone SVG files, to which we need to make a
|
||||||
|
;; few changes to use them inline within our HTML.
|
||||||
|
;; • XML header: Bad syntax when embedded in an HTML doc. Remove
|
||||||
|
;; it.
|
||||||
|
;; • Width and height: We override these with our own values
|
||||||
|
;; computed by `net.deertopia.doerg.tex` to ensure correct
|
||||||
|
;; positioning relative to the surrounding text. More
|
||||||
|
;; accurately, we remove the height and width attributes from
|
||||||
|
;; the SVG tag, and set the new values for height and
|
||||||
|
;; vertical-align in the style attribute
|
||||||
|
;; • Viewbox: Must be removed entirely for correct positioning.
|
||||||
|
(-> (slurp file)
|
||||||
|
(str/replace-first #"<\?xml version='1.0' encoding='UTF-8'\?>\n?" "")
|
||||||
|
(str/replace-first #" height=['\"][^\"']+[\"']" "")
|
||||||
|
(str/replace-first #" width=['\"][^\"']+[\"']" "")
|
||||||
|
(str/replace-first
|
||||||
|
#"viewBox=['\"][^\"']+[\"']"
|
||||||
|
(fn [s]
|
||||||
|
(format "%s style=\"%s\""
|
||||||
|
s
|
||||||
|
(format "height:%.4fem;vertical-align:%.4fem;display:inline-block"
|
||||||
|
height (- depth)))))))
|
||||||
|
|
||||||
|
(defn render-snippets [snippet-promises]
|
||||||
|
(fs/with-temp-dir [svg-dir {:prefix "doerg-svg-"}]
|
||||||
|
(let [rendered-snippets
|
||||||
|
(delay (->> snippet-promises
|
||||||
|
(map first)
|
||||||
|
(apply native/render svg-dir)))]
|
||||||
|
(doseq [[snippet p] snippet-promises]
|
||||||
|
(try (let [temml (temml/render snippet)]
|
||||||
|
(if (temml/erroneous-output? temml)
|
||||||
|
(let [tex (get @rendered-snippets snippet)]
|
||||||
|
(if (:errors tex)
|
||||||
|
(deliver p (hiccup/raw temml))
|
||||||
|
(->> tex
|
||||||
|
read-and-patch-generated-svg
|
||||||
|
hiccup/raw
|
||||||
|
(deliver p))))
|
||||||
|
(deliver p (hiccup/raw temml))))
|
||||||
|
(catch Exception e
|
||||||
|
(l/error e "Error in TeX thread")
|
||||||
|
(throw e)))))))
|
||||||
|
|
||||||
|
(comment
|
||||||
|
(let [snippets (for [x ["\\(\\ifxetex blah \\fi\\)"
|
||||||
|
"\\(\\sqrt{x^2 + y^2}\\)"]]
|
||||||
|
[x (promise)])]
|
||||||
|
(temml/binding-worker
|
||||||
|
(render-snippets snippets)
|
||||||
|
(map #(-> % second deref) snippets))))
|
||||||
|
|||||||
@@ -61,7 +61,9 @@
|
|||||||
(render-display s)
|
(render-display s)
|
||||||
(if-let [[_ inner] (re-matches #"(?s)\\\((.*)\\\)" s)]
|
(if-let [[_ inner] (re-matches #"(?s)\\\((.*)\\\)" s)]
|
||||||
(render-inline inner)
|
(render-inline inner)
|
||||||
(throw (ex-info "weird" {:snippet s}))))))
|
(throw (IllegalArgumentException.
|
||||||
|
(str "`net.deertopia.doerg.tex.temml` argument should"
|
||||||
|
" be enclosed in math delimiters.")))))))
|
||||||
|
|
||||||
;; hackky....
|
;; hackky....
|
||||||
(defn erroneous-output? [s]
|
(defn erroneous-output? [s]
|
||||||
|
|||||||
Reference in New Issue
Block a user