Skip to content

Commit 4ca0f7e

Browse files
tomfaulhaberstuarthalloway
authored andcommitted
Added support for pretty-printing namespace declarations
Signed-off-by: Stuart Halloway <[email protected]>
1 parent 75352eb commit 4ca0f7e

File tree

2 files changed

+124
-41
lines changed

2 files changed

+124
-41
lines changed

src/clj/clojure/pprint/dispatch.clj

Lines changed: 74 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -165,6 +165,79 @@
165165

166166
(declare pprint-simple-code-list)
167167

168+
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
169+
;;; Format the namespace ("ns") macro. This is quite complicated because of all the
170+
;;; different forms supported and because programmers can choose lists or vectors
171+
;;; in various places.
172+
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
173+
174+
(defn- brackets
175+
"Figure out which kind of brackets to use"
176+
[form]
177+
(if (vector? form)
178+
["[" "]"]
179+
["(" ")"]))
180+
181+
(defn- pprint-ns-reference
182+
"Pretty print a single reference (import, use, etc.) from a namespace decl"
183+
[reference]
184+
(if (sequential? reference)
185+
(let [[start end] (brackets reference)
186+
[keyw & args] reference]
187+
(pprint-logical-block :prefix start :suffix end
188+
((formatter-out "~w~:i") keyw)
189+
(loop [args args]
190+
(when (seq args)
191+
((formatter-out " "))
192+
(let [arg (first args)]
193+
(if (sequential? arg)
194+
(let [[start end] (brackets arg)]
195+
(pprint-logical-block :prefix start :suffix end
196+
(if (and (= (count arg) 3) (keyword? (second arg)))
197+
(let [[ns kw lis] arg]
198+
((formatter-out "~w ~w ") ns kw)
199+
(if (sequential? lis)
200+
((formatter-out (if (vector? lis)
201+
"~<[~;~@{~w~^ ~:_~}~;]~:>"
202+
"~<(~;~@{~w~^ ~:_~}~;)~:>"))
203+
lis)
204+
(write-out lis)))
205+
(apply (formatter-out "~w ~:i~@{~w~^ ~:_~}") arg)))
206+
(when (next args)
207+
((formatter-out "~_"))))
208+
(do
209+
(write-out arg)
210+
(when (next args)
211+
((formatter-out "~:_"))))))
212+
(recur (next args))))))
213+
(write-out reference)))
214+
215+
(defn- pprint-ns
216+
"The pretty print dispatch chunk for the ns macro"
217+
[alis]
218+
(if (next alis)
219+
(let [[ns-sym ns-name & stuff] alis
220+
[doc-str stuff] (if (string? (first stuff))
221+
[(first stuff) (next stuff)]
222+
[nil stuff])
223+
[attr-map references] (if (map? (first stuff))
224+
[(first stuff) (next stuff)]
225+
[nil stuff])]
226+
(pprint-logical-block :prefix "(" :suffix ")"
227+
((formatter-out "~w ~1I~@_~w") ns-sym ns-name)
228+
(when (or doc-str attr-map (seq references))
229+
((formatter-out "~@:_")))
230+
(when doc-str
231+
(cl-format true "\"~a\"~:[~;~:@_~]" doc-str (or attr-map (seq references))))
232+
(when attr-map
233+
((formatter-out "~w~:[~;~:@_~]") attr-map (seq references)))
234+
(loop [references references]
235+
(pprint-ns-reference (first references))
236+
(when-let [references (next references)]
237+
(pprint-newline :linear)
238+
(recur references)))))
239+
(write-out alis)))
240+
168241
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
169242
;;; Format something that looks like a simple def (sans metadata, since the reader
170243
;;; won't give it to us now).
@@ -356,7 +429,7 @@
356429
'fn* pprint-anon-func,
357430
'. pprint-hold-first, '.. pprint-hold-first, '-> pprint-hold-first,
358431
'locking pprint-hold-first, 'struct pprint-hold-first,
359-
'struct-map pprint-hold-first,
432+
'struct-map pprint-hold-first, 'ns pprint-ns
360433
})))
361434

362435
(defn- pprint-code-list [alis]

test/clojure/test_clojure/pprint/test_pretty.clj

Lines changed: 50 additions & 40 deletions
Original file line numberDiff line numberDiff line change
@@ -124,49 +124,27 @@ Usage: *hello*
124124
"'foo"
125125
)
126126

127-
(simple-tests code-block-tests
128-
(with-out-str
129-
(with-pprint-dispatch code-dispatch
130-
(pprint
131-
'(defn cl-format
132-
"An implementation of a Common Lisp compatible format function"
133-
[stream format-in & args]
134-
(let [compiled-format (if (string? format-in) (compile-format format-in) format-in)
135-
navigator (init-navigator args)]
136-
(execute-format stream compiled-format navigator))))))
137-
"(defn cl-format
127+
(defmacro code-block
128+
"Read a string then print it with code-dispatch and succeed if it comes out the same"
129+
[test-name & blocks]
130+
`(simple-tests ~test-name
131+
~@(apply concat
132+
(for [block blocks]
133+
`[(with-out-str
134+
(with-pprint-dispatch code-dispatch
135+
(pprint (read-string ~block))))
136+
(str ~block "\n")]))))
137+
138+
(code-block code-block-tests
139+
"(defn cl-format
138140
\"An implementation of a Common Lisp compatible format function\"
139141
[stream format-in & args]
140142
(let [compiled-format (if (string? format-in)
141143
(compile-format format-in)
142144
format-in)
143145
navigator (init-navigator args)]
144-
(execute-format stream compiled-format navigator)))
145-
"
146-
147-
(with-out-str
148-
(with-pprint-dispatch code-dispatch
149-
(pprint
150-
'(defn pprint-defn [writer alis]
151-
(if (next alis)
152-
(let [[defn-sym defn-name & stuff] alis
153-
[doc-str stuff] (if (string? (first stuff))
154-
[(first stuff) (next stuff)]
155-
[nil stuff])
156-
[attr-map stuff] (if (map? (first stuff))
157-
[(first stuff) (next stuff)]
158-
[nil stuff])]
159-
(pprint-logical-block writer :prefix "(" :suffix ")"
160-
(cl-format true "~w ~1I~@_~w" defn-sym defn-name)
161-
(if doc-str
162-
(cl-format true " ~_~w" doc-str))
163-
(if attr-map
164-
(cl-format true " ~_~w" attr-map))
165-
;; Note: the multi-defn case will work OK for malformed defns too
166-
(cond
167-
(vector? (first stuff)) (single-defn stuff (or doc-str attr-map))
168-
:else (multi-defn stuff (or doc-str attr-map)))))
169-
(pprint-simple-code-list writer alis))))))
146+
(execute-format stream compiled-format navigator)))"
147+
170148
"(defn pprint-defn [writer alis]
171149
(if (next alis)
172150
(let [[defn-sym defn-name & stuff] alis
@@ -190,9 +168,41 @@ Usage: *hello*
190168
stuff
191169
(or doc-str attr-map))
192170
:else (multi-defn stuff (or doc-str attr-map)))))
193-
(pprint-simple-code-list writer alis)))
194-
")
195-
171+
(pprint-simple-code-list writer alis)))")
172+
173+
(code-block ns-macro-test
174+
"(ns slam.hound.stitch
175+
(:use [slam.hound.prettify :only [prettify]]))"
176+
177+
"(ns slam.hound.prettify
178+
\"Format a namespace declaration using pretty print with custom dispatch.\"
179+
(:use [clojure.pprint :only [cl-format code-dispatch formatter-out
180+
pprint pprint-logical-block
181+
pprint-newline with-pprint-dispatch
182+
write-out]]))"
183+
184+
"(ns autodoc.build-html
185+
\"This is the namespace that builds the HTML pages themselves.
186+
It is implemented with a number of custom enlive templates.\"
187+
{:skip-wiki true, :author \"Tom Faulhaber\"}
188+
(:refer-clojure :exclude [empty complement])
189+
(:import [java.util.jar JarFile]
190+
[java.io File FileWriter BufferedWriter StringReader
191+
BufferedInputStream BufferedOutputStream
192+
ByteArrayOutputStream FileReader FileInputStream]
193+
[java.util.regex Pattern])
194+
(:require [clojure.string :as str])
195+
(:use [net.cgrand.enlive-html :exclude (deftemplate)]
196+
[clojure.java.io :only (as-file file writer)]
197+
[clojure.java.shell :only (sh)]
198+
[clojure.pprint :only (pprint cl-format pprint-ident
199+
pprint-logical-block set-pprint-dispatch
200+
get-pretty-writer fresh-line)]
201+
[clojure.data.json :only (pprint-json)]
202+
[autodoc.collect-info :only (contrib-info)]
203+
[autodoc.params :only (params expand-classpath)])
204+
(:use clojure.set clojure.java.io clojure.data clojure.java.browse
205+
clojure.inspector clojure.zip clojure.stacktrace))")
196206

197207
(defn tst-pprint
198208
"A helper function to pprint to a string with a restricted right margin"

0 commit comments

Comments
 (0)