|
76 | 76 |
|
77 | 77 | #?(:clj |
78 | 78 | (defmethod print-method ViewerFn [v ^java.io.Writer w] |
79 | | - (.write w (str "#viewer-fn" (when (= :cherry (:evaluator v)) |
| 79 | + (.write w (str "#viewer-fn" (when (= :cherry (:render-evaluator v)) |
80 | 80 | "/cherry") |
81 | 81 | " " (pr-str (:form v)))))) |
82 | 82 |
|
83 | 83 | #?(:clj |
84 | 84 | (defmethod print-method ViewerEval [v ^java.io.Writer w] |
85 | | - (.write w (str "#viewer-eval" (when (= :cherry (:evaluator v)) |
| 85 | + (.write w (str "#viewer-eval" (when (= :cherry (:render-evaluator v)) |
86 | 86 | "/cherry") |
87 | 87 | " " (pr-str (:form v))))) |
88 | 88 | :cljs |
|
869 | 869 |
|
870 | 870 | (defn ->opts [wrapped-value] |
871 | 871 | (select-keys wrapped-value [:nextjournal/budget :nextjournal/css-class :nextjournal/width :nextjournal/opts |
| 872 | + :nextjournal/render-evaluator |
872 | 873 | :!budget :store!-wrapped-value :present-elision-fn :path :offset])) |
873 | 874 |
|
874 | 875 | (defn inherit-opts [{:as wrapped-value :nextjournal/keys [viewers]} value path-segment] |
|
1349 | 1350 |
|
1350 | 1351 | (declare assign-closing-parens) |
1351 | 1352 |
|
1352 | | -(defn process-render-fn [{:as viewer :keys [render-fn evaluator]}] |
| 1353 | +(defn process-render-fn [{:as viewer :keys [render-fn render-evaluator]}] |
1353 | 1354 | (cond-> viewer |
1354 | 1355 | (and render-fn (not (viewer-fn? render-fn))) |
1355 | 1356 | (update :render-fn (fn [rf] |
1356 | 1357 | (assoc (->viewer-fn rf) |
1357 | | - :evaluator (or evaluator :sci)))))) |
| 1358 | + :render-evaluator (or render-evaluator :sci)))))) |
1358 | 1359 |
|
1359 | 1360 | (defn hash-sha1 [x] |
1360 | 1361 | #?(:clj (analyzer/valuehash :sha1 x) |
1361 | 1362 | :cljs (let [hasher (goog.crypt.Sha1.)] |
1362 | 1363 | (.update hasher (goog.crypt/stringToUtf8ByteArray (pr-str x))) |
1363 | 1364 | (.digest hasher)))) |
1364 | 1365 |
|
1365 | | -(defn process-viewer [viewer] |
| 1366 | +(defn process-viewer [viewer {:nextjournal/keys [render-evaluator]}] |
| 1367 | + ;; TODO: drop wrapped-value arg here and handle this elsewhere by |
| 1368 | + ;; passing modified viewer stack |
| 1369 | + ;; `(clerk/update-viewers viewers {:render-fn #(assoc % :render-evaluator :cherry)})` |
1366 | 1370 | (if-not (map? viewer) |
1367 | 1371 | viewer |
1368 | 1372 | (-> viewer |
| 1373 | + (cond-> (and (not (:render-evaluator viewer)) render-evaluator) |
| 1374 | + (assoc :render-evaluator render-evaluator)) |
1369 | 1375 | (dissoc :pred :transform-fn :update-viewers-fn) |
1370 | 1376 | (as-> viewer (assoc viewer :hash (hash-sha1 viewer))) |
1371 | 1377 | (process-render-fn)))) |
|
1380 | 1386 | (cond-> (-> wrapped-value |
1381 | 1387 | (select-keys processed-keys) |
1382 | 1388 | (dissoc :nextjournal/budget) |
1383 | | - (update :nextjournal/viewer process-viewer)) |
| 1389 | + (update :nextjournal/viewer process-viewer wrapped-value)) |
1384 | 1390 | present-elision-fn (vary-meta assoc :present-elision-fn present-elision-fn))) |
1385 | 1391 |
|
1386 | 1392 | #_(process-wrapped-value (apply-viewers 42)) |
|
1699 | 1705 | ([x] (print-hide-result-deprecation-warning) (with-viewer hide-result-viewer {} x)) |
1700 | 1706 | ([viewer-opts x] (print-hide-result-deprecation-warning) (with-viewer hide-result-viewer viewer-opts x))) |
1701 | 1707 |
|
1702 | | - |
1703 | | -(defn eval-cljs [opts & forms] |
1704 | | - ;; because ViewerEval's are evaluated at read time we can no longer |
1705 | | - ;; check after read if there was any in the doc. Thus we set the |
1706 | | - ;; `:nextjournal.clerk/remount` attribute to a hash of the code (so |
1707 | | - ;; it changes when the code changes and shows up in the doc patch. |
1708 | | - ;; TODO: simplify, maybe by applying Clerk's analysis to the cljs |
1709 | | - ;; part as well |
1710 | | - (let [[opts forms] (if (map? opts) |
1711 | | - [opts forms] |
1712 | | - [nil (cons opts forms)])] |
1713 | | - (with-viewer (assoc viewer-eval-viewer :nextjournal.clerk/remount (hash-sha1 forms)) |
1714 | | - (if (= :cherry (:evaluator opts)) |
1715 | | - (assoc (->viewer-eval |
1716 | | - `(do ~@forms)) |
1717 | | - :evaluator (:evaluator opts)) |
1718 | | - (->viewer-eval |
1719 | | - `(binding [*ns* *ns*] |
1720 | | - ~@forms)))))) |
| 1708 | +(defn ^:private rewrite-for-cherry |
| 1709 | + "Takes a form as generated by `eval-cljs` or `eval-cljs-str` and rewrites it for cherry compatibility meaning: |
| 1710 | + * dropping the `(binding [*ns* *ns*] ,,,)` |
| 1711 | + * rewriting `load-string`" |
| 1712 | + [form] |
| 1713 | + (let [form-without-binding (last form)] |
| 1714 | + (if (and (list? form-without-binding) (= 'load-string (first form-without-binding))) |
| 1715 | + (list 'js/global_eval (list 'nextjournal.clerk.cherry-env/cherry-compile-string (second form-without-binding))) |
| 1716 | + form-without-binding))) |
| 1717 | + |
| 1718 | +#_(rewrite-for-cherry '(binding [*ns* *ns*] (prn :foo))) |
| 1719 | +#_(rewrite-for-cherry '(binding [*ns* *ns*] (load-string "(prn :foo)"))) |
| 1720 | + |
| 1721 | +(defn ^:private maybe-rewrite-cljs-form-for-cherry [{:as wrapped-value :nextjournal/keys [render-evaluator]}] |
| 1722 | + (cond-> wrapped-value |
| 1723 | + (= :cherry render-evaluator) |
| 1724 | + (update :nextjournal/value |
| 1725 | + (fn [{:as viewer-eval :keys [form]}] |
| 1726 | + (-> viewer-eval |
| 1727 | + (assoc :render-evaluator render-evaluator) |
| 1728 | + (update :form rewrite-for-cherry)))))) |
| 1729 | + |
| 1730 | +(defn eval-cljs |
| 1731 | + ([form] (eval-cljs {} form)) |
| 1732 | + ([viewer-opts form] |
| 1733 | + ;; because ViewerEval's are evaluated at read time we can no longer |
| 1734 | + ;; check after read if there was any in the doc. Thus we set the |
| 1735 | + ;; `:nextjournal.clerk/remount` attribute to a hash of the code (so |
| 1736 | + ;; it changes when the code changes and shows up in the doc patch. |
| 1737 | + ;; TODO: simplify, maybe by applying Clerk's analysis to the cljs |
| 1738 | + ;; part as well |
| 1739 | + (with-viewer (-> viewer-eval-viewer |
| 1740 | + (update :transform-fn comp maybe-rewrite-cljs-form-for-cherry) |
| 1741 | + (assoc :nextjournal.clerk/remount (hash-sha1 form))) |
| 1742 | + viewer-opts |
| 1743 | + (->viewer-eval (list 'binding '[*ns* *ns*] form))))) |
1721 | 1744 |
|
1722 | 1745 | (defn eval-cljs-str |
1723 | | - ([code-string] (eval-cljs-str nil code-string)) |
| 1746 | + ([code-string] (eval-cljs-str {} code-string)) |
1724 | 1747 | ([opts code-string] |
1725 | 1748 | ;; NOTE: this relies on implementation details on how SCI code is evaluated |
1726 | 1749 | ;; and will change in a future version of Clerk |
1727 | | - (if (= :cherry (:evaluator opts)) |
1728 | | - (assoc (->viewer-eval |
1729 | | - `(let [prog# (nextjournal.clerk.cherry-env/cherry-compile-string ~code-string)] |
1730 | | - (js/global_eval prog#))) |
1731 | | - :evaluator :cherry) |
1732 | | - (eval-cljs (list 'load-string code-string))))) |
| 1750 | + (eval-cljs opts (list 'load-string code-string)))) |
1733 | 1751 |
|
1734 | 1752 | ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; |
1735 | 1753 | ;; examples |
|
0 commit comments