Liking cljdoc? Tell your friends :D

zprint

zprint is a library and command line tool providing a variety of pretty printing capabilities for both Clojure code and Clojure/EDN structures. It can meet almost anyone's needs. As such, it supports a number of major source code formattng approaches.

cljdoc badge

Overview

zprint does far more than just properly indent code. Before:

(defn change-start-column [new-start-column style-vec [inline-comment-index
  start-column spaces-before :as comment-vec]] (if (zero? inline-comment-index)
  style-vec (let [delta-spaces (- new-start-column start-column) new-spaces
  (+ spaces-before delta-spaces) previous-element-index (dec
  inline-comment-index) [s c e :as previous-element] (nth style-vec
  previous-element-index) new-previous-element (cond (= e :indent) [(str "\n"
  (blanks new-spaces)) c e] (= e :whitespace) [(str (blanks new-spaces))
  c e 26] :else nil)] (assoc style-vec previous-element-index
  new-previous-element))))

After:

(defn change-start-column
  [new-start-column style-vec
   [inline-comment-index start-column spaces-before :as comment-vec]]
  (if (zero? inline-comment-index)
    style-vec
    (let [delta-spaces (- new-start-column start-column)
          new-spaces (+ spaces-before delta-spaces)
          previous-element-index (dec inline-comment-index)
          [s c e :as previous-element] (nth style-vec previous-element-index)
          new-previous-element
            (cond (= e :indent) [(str "\n" (blanks new-spaces)) c e]
                  (= e :whitespace) [(str (blanks new-spaces)) c e 26]
                  :else nil)]
      (assoc style-vec previous-element-index new-previous-element))))

Recent Additions!

  • Made considerable improvements in multi-format-pass "stability". Thus, if you format the same file multiple times, it is considerably less likely to change the second time. The biggest issues were when using :repect-nl, though some affected every formatting approach. The only downside is that the tuning for "hangs" had to change a bit -- so now more things qualify to hang as opposed to flow. The change isn't dramatic, but if you prefer the previous behavior it is still available (without the new stability) by using: :style :original-tuning.
  • Inline comments (i.e., end of line comments) when aligned in a group flow left to end up one space beyond the widest code. Single inline comments did not, yielding odd inconsistencies. Now single line inline comments also flow left to end up one space beyond the code. You can turn all of the alignment support for inline comments off by using :comment {:inline-align-style :none} if you don't like this approach.
  • Pairs appear in many places -- bindings in let and other functions, maps, and functions like cond. Prior to 1.2.5, if the left hand side of a pair formatted on multiple lines, the right-hand-side of the pair would always flow onto a new line below the left-hand-side. That remains the default, but you can now allow the right-hand-side to format to the right of the last line of a multi-left-hand-side thing. Enable :style :multi-lhs-hang to allow this to happen.
  • Justification of pairs has been uplifted to do a better job when you enable :style :multi-lhs-hang, and now the tuning for justification is specific to :binding, :map, and :pair, and doesn't affect the formatting of the things in the pair themselves. If you haven't tried justification for a while, you might give it a try: :style [:justified :multi-lhs-hang].
  • You can alias function formatting in the :fn-map. If the value in the :fn-map is a string, then the formatting for that function is used. This makes having one function format like another much easier to configure.
  • Hiccup or HTML output now available! Library -str fns and prebuilt binaries support {:output {:format :hiccup}} and {:output {:format :html}}. EXPERIMENTAL for now -- as always, please let me know of any issues.
  • All changes

See zprint:

  • classic zprint -- ignores whitespace in function definitions and formats code with a variety of heuristics to look as good as hand-formatted code (see examples)
  • respect blank lines -- similar to classic zprint, but blank lines inside of function defintions are retained, while code is otherwise formatted to look beautiful (see examples)
  • indent only -- very different from classic zprint -- no code ever changes lines, it is only correctly indented on whatever line it was already on (see examples)

In addition, zprint is very handy to use at the REPL.

Use zprint:

Get zprint:

Get something other than the default formatting:

Without learning how to configure zprint:

Maybe one of the existing "styles" will meet your needs. All you have to do is put {:style ...} on the command line or as the third argument to a zprint call. For example, {:style :community} or {:style :respect-bl}.

Some commonly used styles:

Learn how to alter zprint's formatting behavior:

I want to change...

Usage

cljdoc badge

Clojure 1.9, 1.10, 1.10.3, 1.11.1:

Leiningen (via Clojars)

Clojars Project

Clojurescript:

zprint has been tested in each of the following environments:

  • figwheel-main 0.2.16 (Clojurescript 1.11.4)
  • shadow-cljs 2.18.0
  • planck 2.26.0 (Clojurescript 1.10.914)

It requires tools.reader at least 1.0.5, which all of the environments above contain.

Clojure 1.8:

The last zprint release built with Clojure 1.8 was [zprint "0.4.15"].

In addition to the zprint dependency, you also need to include the following library when using Clojure 1.8:

[clojure-future-spec "1.9.0-alpha17"]

The zprint Reference

Testing and Development

Information on testing and development can be found here.

Note: Changed the default branch to main.

Contributors

A number of folks have contributed to zprint, not all of whom show up on GitHub because I have integrated the code or suggestions manually. Thanks for all of the great contributions!

  • Tests running in babashka: @borkdude
  • Additional colors and color-map entries: @RingMan
  • Updated rewrite-cljs dependency to 0.4.5 @rundis/
  • Readme updates: @mathiasn, @Quezion, @vemv, @arichiardi, @bhurlow, @kommen.
  • --url and --url-only: @coltnz
  • Use UTF-8 locale to build the native image: @mynomoto
  • Suggestion/encouragement to implement :respect-bl: @griffis
  • Thread safety suggestions: @fazzone
  • :option-fn and :fn-format for enhanced vector formatting: @milankinen
  • Fixed missing require in spec.cljc: @Quezion
  • Corrected readme: @griffis
  • Fixed nested reader conditional: @rgould1
  • Clarified and added useful example for clj usage: @bherrmann7
  • Sublime text plugin instructions: @ekinnear
  • Use body indentation for the ns macro: @pesterhazy
  • Suggested fix for international chars and graalVM native image: @huahaiy

Thanks to everyone who has contributed fixes as well as everyone who has reported an issue. I really appreciate all of the help making zprint better for everybody!

Acknowledgements

At the core of zprint is the rewrite-clj library originally created by Yannick Scherer, ported to Clojurescript by Magnus Rundberget, and recently merged into a single, supported, documented, and updated library by Lee Read. This is a great library! I would not have attempted zprint if rewrite-clj didn't exist to build upon.

Additionally, allowing options maps containing functions to be read from files safely is made possible by sci, the Small Clojure Interpreter by Michael Borkent (@borkdude). This is a very well designed and implemented addition to Clojure that required almost no effort to integrate into zprint.

License

Copyright © 2016-2023 Kim Kinnear

Distributed under the MIT License. See the file LICENSE for details.

Can you improve this documentation? These fine people already did:
Kim Kinnear, Quest Yarbrough, vemv, Andrea Richiardi & Brian Hurlow
Edit on GitHub

cljdoc is a website building & hosting documentation for Clojure/Script libraries

× close