It’s totally hacky but something like this could work:
(defn var-source
"This is almost an exact copy of `clojure.repl/source-fn` but
accepting var instead of symbol in current ns (*ns*)."
[v]
(when-let [filepath (:file (meta v))]
(when-let [strm (.getResourceAsStream (clojure.lang.RT/baseLoader) filepath)]
(with-open [rdr (java.io.LineNumberReader. (java.io.InputStreamReader. strm))]
(dotimes [_ (dec (:line (meta v)))] (.readLine rdr))
(let [text (StringBuilder.)
pbr (proxy [java.io.PushbackReader] [rdr]
(read [] (let [i (proxy-super read)]
(.append text (char i))
i)))
read-opts (if (.endsWith ^String filepath "cljc") {:read-cond :allow} {})]
(if (= :unknown *read-eval*)
(throw (IllegalStateException. "Unable to read source while *read-eval* is :unknown."))
(read read-opts (java.io.PushbackReader. pbr)))
(str text))))))
(defn fn-source
[f]
(let [[ns-name sym-name]
(-> (str f)
(clojure.repl/demunge)
(clojure.string/replace #"@.*$" "")
(clojure.string/split #"/"))
ns (the-ns (symbol ns-name))
fn-var (ns-resolve ns (symbol sym-name))]
(var-source fn-var)))
(comment
(fn-source tap>)
;; => "(defn tap>\n \"sends x to any taps. Will not block. Returns true if there was room in the queue,\n false if not (dropped).\"\n {:added \"1.10\"}\n [x]\n (force tap-loop)\n (.offer tapq (if (nil? x) ::tap-nil x)))"
)