diff --git a/.gitignore b/.gitignore index 23fcc8ae..1eee9df3 100644 --- a/.gitignore +++ b/.gitignore @@ -6,4 +6,5 @@ target .cljs_node_repl out/ node_modules -public/js/ \ No newline at end of file +public/js/ +.nbb/.cache/ diff --git a/build.clj b/build.clj index 741fdada..b93cb1ec 100644 --- a/build.clj +++ b/build.clj @@ -86,8 +86,7 @@ 'com.cognitect/transit-clj {:mvn/version "1.0.333"} 'com.cognitect/transit-cljs {:mvn/version "0.8.280"} 'com.github.flow-storm/hansel {:mvn/version "0.1.83"} - 'org.clojure/data.int-map {:mvn/version "1.2.1"} - 'amalloy/ring-buffer {:mvn/version "1.3.1"}} + 'org.clojure/data.int-map {:mvn/version "1.2.1"}} :paths src-dirs}}) jar-file (format "%s/%s.jar" target-dir (name lib))] diff --git a/deps.edn b/deps.edn index 5bf09365..e6a2fea9 100644 --- a/deps.edn +++ b/deps.edn @@ -18,8 +18,7 @@ com.github.jpmonettas/j-system-theme-detector {:mvn/version "3.8.1"} nrepl/nrepl {:mvn/version "1.1.1"} org.clojure/data.int-map {:mvn/version "1.2.1"} - org.fxmisc.richtext/richtextfx {:mvn/version "0.11.1"} - amalloy/ring-buffer {:mvn/version "1.3.1"}} + org.fxmisc.richtext/richtextfx {:mvn/version "0.11.1"}} :aliases {:cljs-storm {:classpath-overrides {org.clojure/clojurescript nil} ;; disable the official compiler :extra-deps {thheller/shadow-cljs {:mvn/version "2.27.4" diff --git a/nbb.edn b/nbb.edn new file mode 100644 index 00000000..4c06e37a --- /dev/null +++ b/nbb.edn @@ -0,0 +1,66 @@ +{:paths ["src-inst" "src-dbg" "src-shared" "resources"] + :deps {;; IMPORTANT !! + ;; If adding any dependency for the `inst` part also add it on + ;; build.clj jar-inst + org.java-websocket/Java-WebSocket {:mvn/version "1.5.3"} + com.cognitect/transit-clj {:mvn/version "1.0.333"} + com.cognitect/transit-cljs {:mvn/version "0.8.280"} + com.github.flow-storm/hansel {:mvn/version "0.1.83"} + + org.openjfx/javafx-controls {:mvn/version "21.0.4-ea+1"} + org.openjfx/javafx-base {:mvn/version "21.0.4-ea+1"} + org.openjfx/javafx-graphics {:mvn/version "21.0.4-ea+1"} + org.openjfx/javafx-web {:mvn/version "21.0.4-ea+1"} + + org.kordamp.ikonli/ikonli-javafx {:mvn/version "12.3.1"} + org.kordamp.ikonli/ikonli-materialdesign-pack {:mvn/version "12.3.1"} + + com.github.jpmonettas/j-system-theme-detector {:mvn/version "3.8.1"} + nrepl/nrepl {:mvn/version "1.1.1"} + org.clojure/data.int-map {:mvn/version "1.2.1"} + org.fxmisc.richtext/richtextfx {:mvn/version "0.11.1"}} + + :aliases {:cljs-storm {:classpath-overrides {org.clojure/clojurescript nil} ;; disable the official compiler + :extra-deps {thheller/shadow-cljs {:mvn/version "2.27.4" + :exclusions [org.clojure/clojurescript]} + ;; bring ClojureScriptStorm + com.github.flow-storm/clojurescript {:mvn/version "1.11.132-2"} + ;; add FlowStorm runtime dep + com.github.flow-storm/flow-storm-inst {:local/root "." #_#_:mvn/version "RELEASE"} + cider/cider-nrepl {:mvn/version "0.28.3"} + refactor-nrepl/refactor-nrepl {:mvn/version "3.5.2"} + cider/piggieback {:mvn/version "0.5.2"}} + :jvm-opts ["-Dcljs.storm.instrumentOnlyPrefixes=dev" + "-Dcljs.storm.instrumentEnable=true"]} + + :storm {:classpath-overrides {org.clojure/clojure nil} + :extra-deps {com.github.flow-storm/clojure {:mvn/version "1.12.0-1"}} + :jvm-opts [;; "-Xmx20500m" + ;;"-Dflowstorm.startRecording=false" + "-Dflowstorm.theme=dark" + "-Dclojure.storm.instrumentEnable=true" + "-Dclojure.storm.instrumentOnlyPrefixes=dev-tester" + "-Dflowstorm.jarEditorCommand=emacsclient -n +<>:0 <>/<>" + "-Dflowstorm.fileEditorCommand=emacsclient -n +<>:0 <>"]} + + :dev {:extra-paths ["src-dev" "classes"] + + :extra-deps {;; org.clojure/clojurescript {:local/root "/home/jmonetta/my-projects/clojurescript"} + ;; org.clojure/core.async {:mvn/version "1.6.681"} + ;; dorothy/dorothy {:mvn/version "0.0.7"} + org.openjfx/javafx-swing {:mvn/version "21.0.4-ea+1"}} ;; for scenic view to run + + :jvm-opts ["-Dvisualvm.display.name=FlowStorm" + ;; for the profilers + "-Djdk.attach.allowAttachSelf" "-XX:+UnlockDiagnosticVMOptions" "-XX:+DebugNonSafepoints"]} + :jvm-debugger {:jvm-opts ["-Xdebug" "-Xrunjdwp:transport=dt_socket,server=y,suspend=n,address=1044"]} + + :build {:extra-deps {io.github.clojure/tools.build {:git/tag "v0.9.6" :git/sha "8e78bcc"}} + :ns-default build + :jvm-opts ["-Dcljfx.skip-javafx-initialization=true"]} + + :test {:extra-paths ["test"] + :extra-deps {lambdaisland/kaocha {:mvn/version "1.70.1086"} + org.clojure/clojurescript {:mvn/version "1.11.60"}} + :jvm-opts ["-Xmx10500m"] + :main-opts ["-m" "kaocha.runner"]}}} diff --git a/src-inst/flow_storm/remote_websocket_client.cljs b/src-inst/flow_storm/remote_websocket_client.cljs index f7e9aab8..06c7ac80 100644 --- a/src-inst/flow_storm/remote_websocket_client.cljs +++ b/src-inst/flow_storm/remote_websocket_client.cljs @@ -21,7 +21,8 @@ (= :open (websocket-state remote-websocket-client)))) (defn web-socket-client-object [uri-str] - (let [WebSocket (if (and (= *target* "nodejs") + (let [WebSocket (if (and #?(:org.babashka/nbb true + :cljs (= *target* "nodejs")) (exists? js/require)) (let [obj (try @@ -34,7 +35,6 @@ ws-client (WebSocket. uri-str)] ws-client)) - (defn send [ser-packet] (.send remote-websocket-client ser-packet)) diff --git a/src-inst/flow_storm/runtime/events.cljc b/src-inst/flow_storm/runtime/events.cljc index acdc5904..f69f6315 100644 --- a/src-inst/flow_storm/runtime/events.cljc +++ b/src-inst/flow_storm/runtime/events.cljc @@ -9,8 +9,12 @@ (defn clear-pending-events! [] (reset! pending-events [])) +#?(:org.babashka/nbb (defmacro locking + [x & forms] + `(do ~@forms))) + (defn set-dispatch-fn [dispatch-fn] - (reset! *dispatch dispatch-fn) + (reset! *dispatch dispatch-fn) (locking pending-events (doseq [pe @pending-events] (dispatch-fn pe)))) @@ -61,7 +65,7 @@ (make-task-finished-event task-id nil)) ([task-id result] [:task-finished (cond-> {:task-id task-id} - result (assoc :result result))])) + result (assoc :result result))])) (defn make-heap-info-update-event [heap-info] [:heap-info-update heap-info]) @@ -107,6 +111,6 @@ (dispatch ev) - (when-not (#{:heap-info-update} ev-key ) + (when-not (#{:heap-info-update} ev-key) (locking pending-events (swap! pending-events conj ev))))) diff --git a/src-inst/flow_storm/runtime/outputs.cljc b/src-inst/flow_storm/runtime/outputs.cljc index 56c91643..bc3d58bf 100644 --- a/src-inst/flow_storm/runtime/outputs.cljc +++ b/src-inst/flow_storm/runtime/outputs.cljc @@ -1,9 +1,8 @@ (ns flow-storm.runtime.outputs (:require [flow-storm.runtime.events :as rt-events] - [flow-storm.runtime.values :as rt-values] - [amalloy.ring-buffer :refer [ring-buffer]])) + [flow-storm.runtime.values :as rt-values])) -(defonce *last-evals-results (atom (ring-buffer 10))) +(defonce *last-evals-results []) (defonce *tap-fn (atom nil)) @@ -26,11 +25,11 @@ (rt-events/publish-event! (rt-events/make-last-evals-update-event last-evals-refs)))) (defn clear-outputs [] - (reset! *last-evals-results (ring-buffer 10)) + (reset! *last-evals-results []) (fire-update-last-evals-event)) (defn handle-eval-result [v] - (swap! *last-evals-results conj v) + (swap! *last-evals-results #((take-last 10 (conj % v)))) (fire-update-last-evals-event)) (defn handle-out-write [s] diff --git a/src-inst/flow_storm/runtime/values.cljc b/src-inst/flow_storm/runtime/values.cljc index 705e88e5..36ce677d 100644 --- a/src-inst/flow_storm/runtime/values.cljc +++ b/src-inst/flow_storm/runtime/values.cljc @@ -2,12 +2,19 @@ (:require [clojure.pprint :as pp] [flow-storm.utils :as utils] [flow-storm.types :as types] - [clojure.datafy :refer [datafy nav]] + ;; [clojure.datafy :refer [datafy nav]] #?(:clj [clojure.string :as str]))) (defprotocol PWrapped (unwrap [_])) +(comment + (deftype Greg [obj] + nil + (foo [_] "bar")) + + (foo)) + (deftype HashableObjWrap [obj] #?@(:clj [clojure.lang.IHashEq @@ -17,6 +24,8 @@ (if (instance? HashableObjWrap that) (identical? obj (unwrap that)) false))] + :org.babashka/nbb + [] :cljs [IEquiv @@ -28,7 +37,7 @@ IHash (-hash [_] (utils/object-id obj))]) - + PWrapped (unwrap [_] obj)) @@ -45,7 +54,7 @@ (get-value-ref [_ v])) ;; Fast way of going from -;; value-ref -> value +;; value-ref -> value ;; value -> value-ref ;; ;; every object gets wrapped into a HashableObjWrap that will have @@ -67,7 +76,7 @@ (assoc :max-vid next-vid) (update :vref->wv assoc vref wv) (update :wv->vref assoc wv vref)))))) - + (get-value [_ vref] (unwrap (get vref->wv vref))) @@ -91,20 +100,20 @@ (defn reference-value! [v] (try - + (swap! values-ref-registry add-val-ref v) (-> (get-value-ref @values-ref-registry v) (types/add-val-preview v)) - + ;; if for whatever reason we can't reference the value - ;; let's be explicit so at least the user knows that + ;; let's be explicit so at least the user knows that ;; something went wrong and the value can't be trusted. ;; I have seen a issues of hashing failing for a lazy sequence #?(:clj (catch Exception e - (utils/log-error "Error referencing value" e) + (utils/log-error "Error referencing value" e) (reference-value! :flow-storm/error-referencing-value)) :cljs (catch js/Error e - (utils/log-error "Error referencing value" e) + (utils/log-error "Error referencing value" e) (reference-value! :flow-storm/error-referencing-value))))) (defn clear-vals-ref-registry [] @@ -163,12 +172,12 @@ (pr-str (:ref/type v)) (pr-str (type v)))) -(defn val-pprint [val {:keys [print-length print-level print-meta? pprint? nth-elems]}] +(defn val-pprint [val {:keys [print-length print-level print-meta? pprint? nth-elems]}] (let [val-type (value-type val) - print-fn #?(:clj (if pprint? pp/pprint prn) + print-fn #?(:clj (if pprint? pp/pprint prn) :cljs (if (and pprint? (not print-meta?)) pp/pprint print)) ;; ClojureScript pprint doesn't support *print-meta* val-str (try - + (if (and (utils/blocking-derefable? val) (utils/pending? val)) @@ -199,7 +208,7 @@ {:val-str val-str :val-type val-type})) -(defn val-pprint-ref [vref opts] +(defn val-pprint-ref [vref opts] (let [val (deref-value vref)] (val-pprint val opts))) @@ -208,7 +217,7 @@ (tap> v))) #?(:clj - (defn def-value [var-ns var-name x] + (defn def-value [var-ns var-name x] (intern (symbol var-ns) (symbol var-name) (deref-value x)))) @@ -225,13 +234,13 @@ (defn interesting-nav-reference [coll k] (let [v (get coll k) - n (nav coll k v)] + n "unimplmemented" #_(nav coll k v)] (when (or (not= n v) - (not= (meta n) (meta v))) + (not= (meta n) (meta v))) (reference-value! n)))) (defn extract-data-aspects [o] - (let [dat-o (datafy o) + (let [dat-o "unimplemented" ;;(datafy o) o-meta (meta o)] (reduce (fn [aspects {:keys [id pred extractor]}] (if (pred dat-o) @@ -253,19 +262,18 @@ (register-data-aspect-extractor {:id :number :pred number? - :extractor (fn [n] + :extractor (fn [n] {:number/val n})}) (register-data-aspect-extractor {:id :int :pred int? - :extractor (fn [n] + :extractor (fn [n] {:int/decimal n :int/binary (utils/format-int n 2) :int/octal (utils/format-int n 8) :int/hex (utils/format-int n 16)})}) - (register-data-aspect-extractor {:id :previewable :pred any? @@ -309,22 +317,21 @@ :shallow-idx-coll/vals-refs (mapv reference-value! idx-coll) :shallow-idx-coll/navs-refs (mapv (partial interesting-nav-reference idx-coll) (range (count idx-coll)))})}) - #?(:clj (register-data-aspect-extractor {:id :byte-array :pred bytes? :extractor (fn [bs] (let [max-cnt 1000 - + format-and-pad (fn [b radix] (let [s (-> ^byte b Byte/toUnsignedInt (utils/format-int radix)) - s-padded (cond + s-padded (cond (= radix 2) (format "%8s" s) (= radix 16) (format "%2s" s))] - + (str/replace s-padded " " "0")))] (if (<= (count bs) max-cnt) {:bytes/hex (mapv #(format-and-pad % 16) bs) @@ -339,7 +346,6 @@ :bytes/tail-binary (mapv #(format-and-pad % 2) tail)}))))})) (comment - + (extract-data-aspects 120) - (extract-data-aspects {:a 20 :b 40}) - ) + (extract-data-aspects {:a 20 :b 40})) diff --git a/src-shared/flow_storm/types.cljc b/src-shared/flow_storm/types.cljc index 8064ad81..d364a602 100644 --- a/src-shared/flow_storm/types.cljc +++ b/src-shared/flow_storm/types.cljc @@ -31,7 +31,10 @@ #?(:clj (defmethod print-method ValueRef [vref ^java.io.Writer w] (.write w ^String (str "#flow-storm.types/value-ref " (:vid vref)))) - + :org.babashka/nbb (extend-protocol IPrintWithWriter + ValueRef + (-pr-writer [vref writer _] + (-write writer (str "#flow-storm.types/value-ref " (:vid vref))))) :cljs (extend-protocol IPrintWithWriter ValueRef (-pr-writer [vref writer _] diff --git a/src-shared/flow_storm/utils.cljc b/src-shared/flow_storm/utils.cljc index 5a22ecb8..d04f7748 100644 --- a/src-shared/flow_storm/utils.cljc +++ b/src-shared/flow_storm/utils.cljc @@ -1,11 +1,12 @@ (ns flow-storm.utils - #?(:cljs (:require [goog.string :as gstr] + #?(:org.babashka/nbb (:require [clojure.string :as str] + [goog.string :as gstr] + [goog.string.format]) + :cljs (:require [goog.string :as gstr] [clojure.string :as str] - [amalloy.ring-buffer :refer [ring-buffer]] [goog.string.format] [goog :as g]) :clj (:require [clojure.java.io :as io] - [amalloy.ring-buffer :refer [ring-buffer]] [clojure.string :as str])) (:refer-clojure :exclude [format update-values update-keys]) #?(:clj (:import [java.io File LineNumberReader InputStreamReader PushbackReader] @@ -86,7 +87,7 @@ (update :strings-and-numbers assoc o next-uuid))))))] (get-in uuids' [:strings-and-numbers o])) - (= "object" (g/typeOf o)) + (instance? js/Object o) (or (and (js/Object.prototype.hasOwnProperty.call o flow-storm-uuid-prop) (aget o flow-storm-uuid-prop)) (let [next-uid (-> (swap! uuids update :max-uuid inc) @@ -152,10 +153,11 @@ (Class/forName "clojure.storm.Tracer") true (catch Exception _ false)) + :org.babashka/nbb false :cljs (boolean (try (js* "cljs.storm.tracer.trace_fn_call") (catch js/Error _ false))))) (defn flow-storm-nrepl-middleware? [] - #?(:clj (boolean (find-ns 'flow-storm.nrepl.middleware)) + #?(:clj (boolean (find-ns 'flow-storm.nrepl.middleware)) :cljs false)) (defn ensure-vanilla [] @@ -195,11 +197,12 @@ false)) (defn pending? [x] - #?(:clj (instance? clojure.lang.IPending x) + #?(:org.babashka/nbb false ;;TODO + :clj (instance? clojure.lang.IPending x) :cljs (instance? cljs.core.IPending x))) #?(:clj - (defn source-fn [x] + (defn source-fn [x] (try (when-let [v (resolve x)] (when-let [filepath (:file (meta v))] @@ -217,44 +220,43 @@ (if (= :unknown *read-eval*) (throw (IllegalStateException. "Unable to read source while *read-eval* is :unknown.")) (read read-opts (PushbackReader. pbr))) - (str text)) - ))))) + (str text))))))) + (catch Exception _ nil)))) #?(:clj - (defmacro deftype+ - "Same as deftype, but: read mutable fields through ILookup: (:field instance)" - [name fields & body] - `(do - (deftype ~name ~fields - - clojure.lang.ILookup - (valAt [_# key# notFound#] - (case key# - ~@(mapcat #(vector (keyword %) %) fields) - notFound#)) - (valAt [this# key#] - (.valAt this# key# nil))) - - (defn ~(symbol (str '-> name)) ~fields - (new ~name ~@fields) - ~@body))) - ) + (defmacro deftype+ + "Same as deftype, but: read mutable fields through ILookup: (:field instance)" + [name fields & body] + `(do + (deftype ~name ~fields + + clojure.lang.ILookup + (valAt [_# key# notFound#] + (case key# + ~@(mapcat #(vector (keyword %) %) fields) + notFound#)) + (valAt [this# key#] + (.valAt this# key# nil))) + + (defn ~(symbol (str '-> name)) ~fields + (new ~name ~@fields) + ~@body)))) #?(:clj (defmacro lazy-binding "Like clojure.core/binding but instead of a vec of vars it accepts a vec of symbols, and will resolve the vars with requiring-resolve" - [bindings & body] - (let [vars-binds (mapcat (fn [[var-symb var-val]] - [`(clojure.core/requiring-resolve '~var-symb) var-val]) + [bindings & body] + (let [vars-binds (mapcat (fn [[var-symb var-val]]) + [`(clojure.core/requiring-resolve '~var-symb) var-val] (partition 2 bindings))] `(let [] (push-thread-bindings (hash-map ~@vars-binds)) - (try - ~@body - (finally - (pop-thread-bindings))))))) + (try + ~@body + (finally + (pop-thread-bindings))))))) #?(:clj (defn mk-tmp-dir! @@ -342,20 +344,37 @@ (/ (- n from) (- to from)))) +(comment + (into [] (take-last 2 (take-last 4 (range 13)))) + (take-last 23 [1]) + (apply goog.string.format "foo{}") + + (def foo #js {}) + (js/typeof foo) + (js/eval "foo") + (instance? js/Object foo) + (type foo) + + (require '[flow-storm.api :as fs-api]) + + (conj [1 2 3] 5) + + (foo)) + (defn grep-coll "Search over coll with pred, when it matches returns the A elements before and the B elements after" [coll A B pred] - (loop [elems-before (ring-buffer A) + (loop [elems-before [] [e & rcoll] coll] (when e (if (pred e) {:before (into [] elems-before) :match e :after (into [] (take B rcoll))} - (recur (conj elems-before e) + (recur (take-last A (conj elems-before e)) rcoll))))) #?(:clj