|
| 1 | +(ns cider.nrepl.print-method |
| 2 | + (:require [clojure.string :as s]) |
| 3 | + (:import [clojure.lang AFunction MultiFn] |
| 4 | + java.io.Writer)) |
| 5 | + |
| 6 | +;; Extending `print-method` defined in clojure.core, to provide |
| 7 | +;; prettier versions of some objects. This applies to anything that |
| 8 | +;; calls `print-method`, which includes return values, `pr`, `print` |
| 9 | +;; and the likes. |
| 10 | + |
| 11 | +(def ^:dynamic *pretty-objects* |
| 12 | + "If true, cider prettifies some object descriptions. |
| 13 | + For instance, instead of printing functions as |
| 14 | + #object[clojure.core$_PLUS_ 0x4e648e99 \"clojure.core$_PLUS_@4e648e99\"] |
| 15 | + they are printed as |
| 16 | + #function[clojure.core/+] |
| 17 | +
|
| 18 | + To disable this feature, do |
| 19 | + (alter-var-root #'cider.nrepl.print-method/*pretty-objects* not)" |
| 20 | + true) |
| 21 | + |
| 22 | +(defmacro def-print-method [dispatch-val arg & strings] |
| 23 | + `(defmethod print-method ~dispatch-val [~arg ~'^Writer w] |
| 24 | + (if *pretty-objects* |
| 25 | + (do ~@(map #(list '.write 'w %) strings)) |
| 26 | + (#'clojure.core/print-object ~arg ~'w)))) |
| 27 | + |
| 28 | +;;; Function objects |
| 29 | +;; Ex: #function[cider.nrepl.print-method/multifn-name] |
| 30 | +(def-print-method AFunction c |
| 31 | + "#function[" |
| 32 | + (-> (.getName (class c)) |
| 33 | + (s/replace-first "$" "/") |
| 34 | + (s/replace "_QMARK_" "?") |
| 35 | + (s/replace "_PLUS_" "+") |
| 36 | + (s/replace "_BANG_" "!") |
| 37 | + (s/replace "_EQ_" "=") |
| 38 | + (s/replace "_SLASH_" "/") |
| 39 | + (s/replace "_STAR_" "*") |
| 40 | + (s/replace "_" "-")) |
| 41 | + "]") |
| 42 | + |
| 43 | +;;; Multimethods |
| 44 | +;; Ex: #multifn[print-method 0x3f0cd5b4] |
| 45 | +(defn multifn-name [^MultiFn mfn] |
| 46 | + (let [field (.getDeclaredField MultiFn "name") |
| 47 | + private (not (.isAccessible field))] |
| 48 | + (when private |
| 49 | + (.setAccessible field true)) |
| 50 | + (let [name (.get field mfn)] |
| 51 | + (when private |
| 52 | + (.setAccessible field false)) |
| 53 | + name))) |
| 54 | + |
| 55 | +(def-print-method MultiFn c |
| 56 | + "#multifn[" |
| 57 | + (try (multifn-name c) |
| 58 | + (catch SecurityException _ |
| 59 | + (class c))) |
| 60 | + ;; MultiFn names are not unique so we keep the identity HashCode to |
| 61 | + ;; make sure it's unique. |
| 62 | + (format " 0x%x]" (System/identityHashCode c))) |
0 commit comments