Last active
May 28, 2018 04:49
-
-
Save benzap/55cd4766c34bc266323a37df54beda68 to your computer and use it in GitHub Desktop.
Fif Interactive Repl Used in blog posts
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
(ns website.fif-repl | |
(:require | |
[clojure.string :as str] | |
[rum.core :as rum] | |
[fif.core :as fif] | |
[fif.stack-machine :as stack] | |
[fif.stack-machine.error-handling :refer [set-error system-error]] | |
;; Nothing to see here | |
[website.repl-imports :refer [import-super-secret-words]])) | |
(defn stack-error-handler | |
"Custom fif error handler for stack errors" | |
[sm errobj] | |
(set-error sm errobj)) | |
(defn system-error-handler | |
"Custom fif error handler for system errors" | |
[sm ex] | |
(println ex) ;; This will also be captured and placed in standard out of prepl | |
(set-error sm (system-error sm ex "System Error"))) | |
(def website-sm | |
(-> fif/*default-stack* | |
stack/enable-debug | |
import-super-secret-words | |
(stack/set-system-error-handler system-error-handler) | |
(stack/set-stack-error-handler stack-error-handler) | |
(stack/set-step-max 10000))) ;; Prevents infinite loops from going on forever | |
(defn format-inner-html | |
"Correctly format newlines within <div>'s placed in markdown. Super | |
Hacky." | |
[s] | |
(-> (.-innerHTML s) | |
(subs 1) | |
(str/replace #"<p>" "") | |
(str/replace #"</p>" "\n") | |
(str/replace #"_ " "\n"))) | |
(defn prepl-output-fn | |
"Main Prepl Output Function." | |
[fif-state {:keys [tag value]}] | |
(swap! fif-state update :output-string #(reduce str %1 %2) value)) | |
(defn evaluate-sm-fcn | |
"Stack Machine Evaluation" | |
[fif-state] | |
(swap! fif-state assoc :output-string "") | |
(let [sm (fif/prepl-eval website-sm (:input-string @fif-state) (partial prepl-output-fn fif-state)) | |
main-stack (-> sm fif/get-stack reverse)] | |
(swap! fif-state assoc :output-stack main-stack))) | |
(def mixin-evaluate-fif-repl | |
"Rum Mixin for stack-machine evaluation after mount. | |
Also includes textarea 'input' event to re-evaluate after change." | |
{:did-mount | |
(fn [state] | |
(let [comp (:rum/react-component state) | |
dom-node (js/ReactDOM.findDOMNode comp) | |
fif-state (-> state :rum/args first)] | |
(evaluate-sm-fcn fif-state) | |
(when-let [textarea (.querySelector dom-node "textarea")] | |
(.addEventListener | |
textarea "input" | |
(fn [e] | |
(swap! fif-state assoc :input-string (.-value textarea)) | |
(evaluate-sm-fcn fif-state)))) | |
state))}) | |
(rum/defcs c-fif-repl | |
< | |
rum/reactive | |
mixin-evaluate-fif-repl | |
[state app-state] | |
(let [{:keys [input-string output-string output-stack]} | |
(rum/react app-state)] | |
[:.fif-repl-component | |
[:textarea {:spellCheck false | |
:default-value input-string}] | |
[:.output-stack (str output-stack)] | |
[:.output-string output-string]])) | |
(defn mount-fif-repl | |
"Turns the given element into a fif-repl. element is assumed to have | |
<p></p> separated paragraphs as fif script. This is a little hacky, | |
since i'm placing the <div> elements in a markdown parser. Would | |
probably be less hacky outside of a markdown parser." | |
[elem] | |
(let [fif-state (atom {:elem elem | |
:input-string (format-inner-html elem) | |
:output-string "" | |
:output-stack '(2 2 +)})] | |
(rum/mount (c-fif-repl fif-state) elem))) | |
(defn enable-fif-repls | |
"Turns all elements with 'selector' into a fif-repl." | |
[selector] | |
(let [elems (.querySelectorAll js/document selector)] | |
(doseq [elem-idx (range (.-length elems))] | |
(let [elem (aget elems elem-idx)] | |
(mount-fif-repl elem))))) |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment