I'm pleased to announce the release of *zprint*, a new Clojure(script) 
pretty print library and associated leiningen plugin to apply it to your source 
files.  The zprint library will pretty print the code in your source files 
when driven by* lein-zprint*, as well as pretty print structures (and code) 
when used directly at the repl in Clojure and Clojurescript.  


https://github.com/kkinnear/zprint

https://github.com/kkinnear/lein-zprint


What, really?  Another pretty printer?


Yes, I know.  We've already got clojure.pprint, fipp, puget, cljfmt. There 
is a full discussion of why zprint exists in the readme.  The short story 
is that zprint completely reformats Clojure source, totally ignoring all of 
the line breaks and whitespace inside of a function definition.  It also 
runs as a library at the repl (and in your code) to print structures very 
nicely, and is totally configurable.


In short, zprint and lein-zprint try to do it all, beautifully, out of the 
box. 


I have just now proposed an *unsession* at the upcoming conj.  If you are 
interested, register your interest and maybe we'll have a session!


A quick example of the basics:


Before:


(print (source-fn 'example))

(defn example

  "Do a diff of two maps, and update an existing doc-map with labels

  of everything that is different. Existing is before the update with

  new." [doc-string doc-map existing new] (let [[only-before only-after 
both]

  (d/diff existing new)] (merge-deep doc-map (map-leaves #(zipmap

  [:value :set-by] [% doc-string]) only-after))))


After:


(zprint-fn example)

(defn example
  "Do a diff of two maps, and update an existing doc-map with labels 

  of everything that is different. Existing is before the update with 

  new." 

  [doc-string doc-map existing new] 

  (let [[only-before only-after both] (d/diff existing new)] 

    (merge-deep doc-map 

                (map-leaves #(zipmap [:value :set-by] [% doc-string]) 

                            only-after))))


A list of features:


* Prints function definitions at the Clojure repl (including clojure.core 
functions)

* Prints s-expressions (EDN structures) at the repl

* Processes Clojure(script) source files through lein-zprint

* Supports Clojure and Clojurescript (self-hosted Clojurescript coming soon)

* Competitive performance formatting code

* Highly configurable, and it will explain to you how it got configured

* Many specific function classifications and knows a lot about Clojure

* Accepts formatting directives in comments in source files (lein-zprint)

* Respects the right margin specification

* Handles comments, will word wrap long ones

* Maximize screen utilization when formatting code

* Sort and order map keys

* Constant pairing (for keyword argument functions)

* Handles cond variants that include :let [...], etc

* Justify paired output (maps, binding forms, cond clauses, etc.) if desired

* Syntax coloring at the repl

* Has a :style feature that includes a :community style


A few highlights:


1. At the repl you can type (czprint-fn <fn-name>) and if zprint can find 
the source (as it can for the clojure.* functions and anything defined in 
your source files), you get the function pretty printed in the repl.  With 
colors (which you can change, of course).  Kind of like (doc ...), but you 
get to see the function too.  This is the best way to see what zprint will 
do for your functions.


2. When you use lein-zprint to format your source files, you can put a 
comment in the file ;!zprint {<options>}, where the options can apply only 
to the next defn in the file.  Generally this isn't needed, but sometimes 
you just want to turn off formatting or have it configured a particular way 
for just this one function. I used this maybe three time in all of the 
zprint source, but for those times, it made a big difference in the 
readability.


3. Something I call "*constant pairing*" makes the formatting of functions with 
keyword arguments come out looking good.  It also formats Clojure specs 
very effectively.


4. Some people "*justify*" their let bindings, where the expressions that 
set the values for the locals all start in the same column. zprint can be 
configured to do that (though it doesn't by default), and sometimes it is 
nice.  Sometimes, not.  However, I extended this capability to maps, and 
for some maps output to the repl, the justify approach makes them look 
great.  Try (czprint nil :explain-justified) and compare it to (czprint nil 
:explain) and see what you think!  Still a bit slow for big or deeply 
nested maps, as if it causes the output to be longer than *not* justifying the 
map, it falls back to unjustified.  Another example:


This:


(zprint x)

{:code "58601", 

 :connection "2795", 

 :detail {:alternate "64:c1:2f:34", 

          :ident "64:c1:2f:34", 

          :interface "3.13.168.35", 

          :string "datacenter"}, 

 :direction :received, 

 :reference 14873, 

 :time 1425704001, 

 :type "get"}

 

or this:


(zprint x {:style :justified})

{:code       "58601", 

 :connection "2795", 

 :detail     {:alternate "64:c1:2f:34", 

              :ident     "64:c1:2f:34", 

              :interface "3.13.168.35", 

              :string    "datacenter"}, 

 :direction  :received, 

 :reference  14873, 

 :time       1425704001, 

 :type       "get"}



5. The keys in maps are, by default, sorted (something that puget does that 
is great).  In zprint you can also specify a vector of keys that always 
sort to the top, in case the most important key in a map would be obscured 
by its normal lexical sort order.  In the above example the  :type key 
would like to be at the top.  If you specified {:map {:key-order [:type]}} 
it would be.


6. There are a lot of very specific function classifications, including 
things like the various forms of extend, that trigger zprint to follow the 
prevailing approach to formatting Clojure(script) source.


7. The cond variants that include :let [...] clauses are formatted correctly 
by zprint.


Enough words -- give it a try and see what you think.


Cheers -- Kim




-- 
You received this message because you are subscribed to the Google
Groups "Clojure" group.
To post to this group, send email to clojure@googlegroups.com
Note that posts from new members are moderated - please be patient with your 
first post.
To unsubscribe from this group, send email to
clojure+unsubscr...@googlegroups.com
For more options, visit this group at
http://groups.google.com/group/clojure?hl=en
--- 
You received this message because you are subscribed to the Google Groups 
"Clojure" group.
To unsubscribe from this group and stop receiving emails from it, send an email 
to clojure+unsubscr...@googlegroups.com.
For more options, visit https://groups.google.com/d/optout.

Reply via email to