Skip to content

Commit 0db8664

Browse files
committed
Abbreviate printing of AFunction and MultiFn objects
Instead of printing as #object[clojure.core$_PLUS_ 0x4e648e99 "clojure.core$_PLUS_@4e648e99"] they are now printed as #function[clojure.core/+] Instead of printing as #object[clojure.lang.MultiFn 0x4e648e99 "clojure.lang.MultiFn@0x4e648e99"] they are now printed as #multifn[print-method 0x3f0cd5b4] Disable this with (alter-var-root #'cider.nrepl.print-method/*pretty-objects* not)
1 parent 585b416 commit 0db8664

File tree

4 files changed

+88
-0
lines changed

4 files changed

+88
-0
lines changed

src/cider/nrepl.clj

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
(ns cider.nrepl
22
(:require [clojure.tools.nrepl.server :as nrepl-server]
3+
[cider.nrepl.print-method]
34
[cider.nrepl.middleware.apropos]
45
[cider.nrepl.middleware.classpath]
56
[cider.nrepl.middleware.complete]

src/cider/nrepl/middleware/out.clj

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@
99
guarantee that the channel that sent the clone message will properly
1010
handle output replies."
1111
(:require [cider.nrepl.middleware.util.cljs :as cljs]
12+
[clojure.string :as s]
1213
[clojure.tools.nrepl.middleware :refer [set-descriptor!]]
1314
[clojure.tools.nrepl.middleware.interruptible-eval :as ie]
1415
[clojure.tools.nrepl.middleware.session :as session])

src/cider/nrepl/print_method.clj

Lines changed: 62 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,62 @@
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)))
Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
(ns cider.nrepl.print-method-test
2+
(:require [cider.nrepl.print-method :refer :all]
3+
[clojure.test :refer :all])
4+
(:import java.util.regex.Pattern))
5+
6+
(defn dummy-fn [o])
7+
8+
(deftest print-functions
9+
(are [f s] (= (pr-str f) s)
10+
print-functions "#function[cider.nrepl.print-method-test/print-functions]"
11+
dummy-fn "#function[cider.nrepl.print-method-test/dummy-fn]"
12+
multifn-name "#function[cider.nrepl.print-method/multifn-name]"
13+
+ "#function[clojure.core/+]"
14+
* "#function[clojure.core/*]"
15+
/ "#function[clojure.core//]"
16+
map? "#function[clojure.core/map?--4138]"))
17+
18+
(deftest print-multimethods
19+
(require 'cider.nrepl.middleware.track-state)
20+
(doseq [it '(print-method cider.nrepl.middleware.track-state/ns-as-map)]
21+
(let [var (resolve it)]
22+
(is (re-find (Pattern/compile (format "#multifn\\[%s 0x[a-z0-9]+\\]"
23+
(:name (meta var))))
24+
(pr-str @var))))))

0 commit comments

Comments
 (0)