As you can see, the docstring has a newline in it, which pprint escapes (as edn) but I don’t want that because it is code. This code gets written out as a namespace and it looks wrong to have the docstrings contain escaped newlines. So as a workaround I then replace all escaped newlines with normal newlines. This is not perfect though, because functions could include strings in their body, and those should remain escaped.
It seems like a bit of a challenge to differentiate docstrings from other strings and treat them differently… I looked into cljfmt and rewrite-clj which handle this problem just fine, but I couldn’t figure out how they actually do it .
Does anyone have any suggestions on how to solve the issue with printing docstrings, or can point me to how cljfmt solves it?
@p-himik I think the issue was that the (str/replace "\\n" "\n") was not wanted in general—it was the desired behavior for docstrings, but not all the other strings.
Short answer: it appears that clojure.pprint/code-dispatch is built in a way that is not easily configurable.
Longer answer: clojure.pprint/code-dispatch uses clojure.pprint/*code-table*, a private dynamic var. *code-table* is a map from symbol to function printing that symbol. Its entry for 'defn is clojure.pprint/pprint-defn, also private.
Even longer, derailing answer: It appears that we can monkey-patch clojure.pprint/*code-table* with our own defn printer:
(ns scratch
(:require
[clojure.pprint :as pprint]
[clojure.pprint.dispatch]))
(def my-function-code
'(defn f "hi\nthere" [x] (inc x)))
(pprint/with-pprint-dispatch pprint/code-dispatch
(pprint/pprint my-function-code))
;; Prints like Tim showed.
(def original-code-table (deref #'clojure.pprint/*code-table*))
(defn teodor-defn-writer [_]
(println "(defn teodor-function [])"))
(binding [clojure.pprint/*code-table* (assoc original-code-table 'defn teodor-defn-writer)]
(pprint/with-pprint-dispatch pprint/code-dispatch
(pprint/pprint my-function-code)))
;; Prints "(defn teodor-function [])"
I tried reading the original implementation for printing code, but I couldn’t understand what was going on. Here it is:
I think it might be easier to print to a string first, then use rewrite-clj to traverse over the resulting string, changing only the docstring in defns to what you want.
Which is more in line with both what you imply and what @p-himik suggests