feat: tex rendering via temml
This commit is contained in:
18
doerg/src/net/deertopia/doerg/common.clj
Normal file
18
doerg/src/net/deertopia/doerg/common.clj
Normal file
@@ -0,0 +1,18 @@
|
||||
(ns net.deertopia.doerg.common
|
||||
(:require [babashka.process :as p]
|
||||
[clojure.string :as str]))
|
||||
|
||||
(defn deref-with-timeout [process ms]
|
||||
(let [p (promise)
|
||||
process-future (future (deliver p @process))
|
||||
timeout-future (future (Thread/sleep ms)
|
||||
(future-cancel process-future)
|
||||
(p/destroy-tree process)
|
||||
(deliver p ::timed-out))]
|
||||
(if (= @p ::timed-out)
|
||||
(throw (ex-info (format "external command `%s' timed out after %.2fs."
|
||||
(str/join " " (:cmd process))
|
||||
(/ (double ms) 1000))
|
||||
{:process process
|
||||
:timed-out-after-milliseconds ms}))
|
||||
@p)))
|
||||
@@ -1,5 +1,6 @@
|
||||
(ns net.deertopia.doerg.element
|
||||
(:require [babashka.process :as p]
|
||||
[net.deertopia.doerg.common :as common]
|
||||
[clojure.string :as str]
|
||||
[clojure.zip]
|
||||
[babashka.fs :as fs]
|
||||
@@ -16,24 +17,11 @@
|
||||
|
||||
(defonce ^:private uniorg-script-path-atom (atom nil))
|
||||
|
||||
(def ^:dynamic *uniorg-timeout-after-milliseconds*
|
||||
(def ^:dynamic *uniorg-timeout-duration*
|
||||
"Number of milliseconds to wait before killing the external Uniorg
|
||||
process."
|
||||
(* 10 1000))
|
||||
|
||||
(defn deref-with-timeout [process ms]
|
||||
(let [p (promise)
|
||||
process-future (future (deliver p @process))
|
||||
timeout-future (future (Thread/sleep ms)
|
||||
(future-cancel process-future)
|
||||
(p/destroy-tree process)
|
||||
(deliver p ::timed-out))]
|
||||
(if (= @p ::timed-out)
|
||||
(throw (ex-info (format "external command `%s' timed out after %.2fs."
|
||||
(str/join " " (:cmd process))
|
||||
(/ (double ms) 1000))
|
||||
{:process process
|
||||
:timed-out-after-milliseconds ms}))
|
||||
@p)))
|
||||
|
||||
(defn- camel->kebab [s]
|
||||
(->> (str/split s #"(?<=[a-z])(?=[A-Z])")
|
||||
(map str/lower-case)
|
||||
@@ -44,7 +32,7 @@
|
||||
(let [r (-> (p/process
|
||||
{:in in :out :string}
|
||||
"doerg-parser")
|
||||
(deref-with-timeout *uniorg-timeout-after-milliseconds*))]
|
||||
(common/deref-with-timeout *uniorg-timeout-duration*))]
|
||||
(if (zero? (:exit r))
|
||||
(-> r :out (json/parse-string (comp keyword camel->kebab))))))
|
||||
|
||||
|
||||
@@ -7,7 +7,9 @@
|
||||
[clojure.tools.logging.readable :as lr]
|
||||
[com.rpl.specter :as sp]
|
||||
[net.deertopia.doerg.html :as doerg-html]
|
||||
[hiccup2.core :as hiccup]
|
||||
[clojure.pprint]
|
||||
[net.deertopia.doerg.tex :as tex]
|
||||
[clojure.zip :as z]))
|
||||
|
||||
;;; Top-level API
|
||||
@@ -43,15 +45,16 @@
|
||||
(defn org-element-recursive
|
||||
"Recursively render an Org-mode element to Hiccup."
|
||||
[e]
|
||||
(->> e
|
||||
;; gather-footnotes
|
||||
(sp/transform
|
||||
(tex/binding-tex-worker
|
||||
(->> e
|
||||
;; gather-footnotes
|
||||
(sp/transform
|
||||
[element/postorder-walker view-children-as-seq]
|
||||
(fn [node]
|
||||
(try (org-element node)
|
||||
(catch Throwable e
|
||||
(lr/error e "Error in renderer" {:node node})
|
||||
(render-renderer-error e)))))))
|
||||
(render-renderer-error e))))))))
|
||||
|
||||
(defn org-document
|
||||
"Recursively render an Org-mode document to Hiccup."
|
||||
@@ -276,11 +279,16 @@
|
||||
(defmethod org-element "citation-reference" [{:keys [key]}]
|
||||
(str "@" key))
|
||||
|
||||
(defmethod org-element "latex-fragment" [{:keys [value]}]
|
||||
[:span.latex-fragment value])
|
||||
(defmethod org-element "latex-fragment" [{:keys [contents value] :as e}]
|
||||
(let [display? (str/starts-with? value "\\[")]
|
||||
#_
|
||||
(render-pprint (assoc e :display? display?))
|
||||
[:span.latex-fragment
|
||||
(hiccup/raw (tex/render contents :display? display?))]))
|
||||
|
||||
(defmethod org-element "latex-environment" [{:keys [value]}]
|
||||
[:pre [:code value]])
|
||||
[:span.latex-fragment
|
||||
(hiccup/raw (tex/render value :display? true))])
|
||||
|
||||
(defmethod org-element "example-block" [{:keys [value]}]
|
||||
[:pre value])
|
||||
|
||||
49
doerg/src/net/deertopia/doerg/tex.clj
Normal file
49
doerg/src/net/deertopia/doerg/tex.clj
Normal file
@@ -0,0 +1,49 @@
|
||||
(ns net.deertopia.doerg.tex
|
||||
(:require [babashka.process :as p]
|
||||
[net.deertopia.doerg.common :as common]
|
||||
[clj-cbor.core :as cbor]
|
||||
[clojure.java.io :as io]))
|
||||
|
||||
(def ^:dynamic *tex-worker-timeout-duration*
|
||||
"Number of milliseconds to wait before killing the external Uniorg
|
||||
process."
|
||||
(* 10 1000))
|
||||
|
||||
(def ^:dynamic *worker*)
|
||||
|
||||
(defn tex-worker [& {:keys [preamble]}]
|
||||
(p/process
|
||||
{:shutdown p/destroy-tree
|
||||
:err :inherit}
|
||||
#_"doerg-tex"
|
||||
"./doerg-tex/index.js"
|
||||
"--preamble"
|
||||
"resources/net/deertopia/doerg/prelude.tex"))
|
||||
|
||||
(defn finish [tw]
|
||||
(.close (:in tw)))
|
||||
|
||||
(defmacro with-tex-worker [tw & body]
|
||||
`(let [~tw (tex-worker)]
|
||||
(try
|
||||
(do ~@body)
|
||||
(finally
|
||||
(finish ~tw)
|
||||
(p/destroy-tree ~tw)))))
|
||||
|
||||
(defmacro binding-tex-worker [& body]
|
||||
`(binding [*worker* (tex-worker)]
|
||||
(try
|
||||
~@body
|
||||
(finally
|
||||
(finish *worker*)))))
|
||||
|
||||
(defn command [x]
|
||||
(cbor/encode cbor/default-codec (:in *worker*) x)
|
||||
(.flush (:in *worker*))
|
||||
(cbor/decode cbor/default-codec (:out *worker*)))
|
||||
|
||||
(defn render [s & {:keys [display?]}]
|
||||
(if display?
|
||||
(command [s])
|
||||
(command s)))
|
||||
Reference in New Issue
Block a user