|
| 1 | +(ns clojure+.hashp |
| 2 | + (:require |
| 3 | + [clojure.string :as str] |
| 4 | + [clojure.pprint :as pprint] |
| 5 | + [clojure.walk :as walk] |
| 6 | + [clojure+.util :as util]) |
| 7 | + (:import |
| 8 | + [clojure.lang Compiler TaggedLiteral])) |
| 9 | + |
| 10 | +(defn- default-config [] |
| 11 | + {:symbol 'p |
| 12 | + :color? (util/color?)}) |
| 13 | + |
| 14 | +(def config |
| 15 | + (default-config)) |
| 16 | + |
| 17 | +(def ^:private lock |
| 18 | + (Object.)) |
| 19 | + |
| 20 | +(defn- pos [] |
| 21 | + (let [trace (->> (Thread/currentThread) |
| 22 | + (.getStackTrace) |
| 23 | + (seq)) |
| 24 | + el ^StackTraceElement (nth trace 7) |
| 25 | + cls (Compiler/demunge (.getClassName el)) |
| 26 | + file (.getFileName el) |
| 27 | + line (.getLineNumber el)] |
| 28 | + (str "[" |
| 29 | + cls |
| 30 | + (when file (str " " file)) |
| 31 | + (when line (str ":" line)) |
| 32 | + "]"))) |
| 33 | + |
| 34 | +(defn- ansi-blue [] |
| 35 | + (when (:color? config) |
| 36 | + "\033[34m")) |
| 37 | + |
| 38 | +(defn- ansi-grey [] |
| 39 | + (when (:color? config) |
| 40 | + "\033[37m")) |
| 41 | + |
| 42 | +(defn- ansi-reset [] |
| 43 | + (when (:color? config) |
| 44 | + "\033[0m")) |
| 45 | + |
| 46 | +(defn hashp-impl [form res] |
| 47 | + (let [position (pos) |
| 48 | + form (walk/postwalk |
| 49 | + (fn [form] |
| 50 | + (if (and (list? form) (::form (meta form))) |
| 51 | + (TaggedLiteral/create (:symbol config) (::form (meta form))) |
| 52 | + form)) |
| 53 | + form)] |
| 54 | + (locking lock |
| 55 | + (println (str (ansi-blue) "#" (:symbol config) " " form " " (ansi-grey) position (ansi-reset))) |
| 56 | + (pprint/pprint res)) |
| 57 | + res)) |
| 58 | + |
| 59 | +(defn- add-first [x form] |
| 60 | + (if (seq? form) |
| 61 | + (list* (first form) x (next form)) |
| 62 | + (list form x))) |
| 63 | + |
| 64 | +(defn- add-last [x form] |
| 65 | + (if (seq? form) |
| 66 | + (list* (concat form [x])) |
| 67 | + (list form x))) |
| 68 | + |
| 69 | +(defn hashp |
| 70 | + "Add #p before any form to quickly print its value to output next time |
| 71 | + it’s evaluated. Works inside -> ->> too!" |
| 72 | + [form] |
| 73 | + (let [x-sym (gensym "x") |
| 74 | + y-sym (gensym "y") |
| 75 | + form-first (add-first x-sym form) |
| 76 | + form-last (add-last y-sym form)] |
| 77 | + `^{::form ~form} |
| 78 | + ((fn |
| 79 | + ([_#] |
| 80 | + (hashp-impl '~form ~form)) |
| 81 | + ([~x-sym ~y-sym] |
| 82 | + (hashp-impl '~form |
| 83 | + (cond |
| 84 | + (= ::undef ~x-sym) ~form-last |
| 85 | + (= ::undef ~y-sym) ~form-first |
| 86 | + :else (throw (Exception. "Impossible!")))))) |
| 87 | + ::undef))) |
| 88 | + |
| 89 | +(defn install! |
| 90 | + ([] |
| 91 | + (install! {})) |
| 92 | + ([opts] |
| 93 | + (let [config (merge (default-config) opts) |
| 94 | + _ (.doReset #'config config) |
| 95 | + sym (:symbol config)] |
| 96 | + (alter-var-root #'*data-readers* assoc sym #'hashp) |
| 97 | + (when (thread-bound? #'*data-readers*) |
| 98 | + (set! *data-readers* (assoc *data-readers* sym #'hashp)))))) |
| 99 | + |
| 100 | +(defn uninstall! [] |
| 101 | + (let [sym (:symbol config)] |
| 102 | + (alter-var-root #'*data-readers* dissoc sym) |
| 103 | + (when (thread-bound? #'*data-readers*) |
| 104 | + (set! *data-readers* (dissoc *data-readers* sym))))) |
0 commit comments