• Stars
    star
    513
  • Rank 86,178 (Top 2 %)
  • Language
    Clojure
  • Created almost 12 years ago
  • Updated over 2 years ago

Reviews

There are no reviews yet. Be the first to send feedback to the community and the maintainers!

Repository Details

Fast Idiomatic Pretty Printer for Clojure

Fast Idiomatic Pretty-Printer

Fipp is a better pretty printer for Clojure and ClojureScript.

Like clojure.pprint, this pretty printer has a linear runtime and uses bounded space. However, unlike clojure.pprint, Fipp's implementation is tuned for great performance and has a functional, data-driven API.

The data interface is agnostic to the source language. Printers are included for Edn data and Clojure code, but it is easy to create a pretty printer for your own language or documents: Even if they're not made out of Clojure data!

Fipp is great for printing large data files and debugging macros, but it is not suitable as a code reformatting tool. (explanation)

Installation

Fipp artifacts are published on Clojars.

To depend on this version with Lein, add the following to your project.clj:

[fipp "0.6.26"]

This version of Fipp works with Clojure 1.7 or newer.

See the v0.5 branch for a version of Fipp that works with Clojure 1.6.

ClojureScript is supported from build 3269 and up.

Colorization & REPL Integration

Puget uses Fipp's engine to provide an alternative, colorizing printer.

Whidbey integrates Puget in to nREPL via Leiningen, so that every evaluation pretty prints in color.

Printer Usage

;; Refer with a rename to avoid collision with your REPL's pprint.
(require '[fipp.edn :refer [pprint] :rename {pprint fipp}])

(fipp [1 2 3])
(fipp (range 50))
(fipp (range 20))
(fipp (range 20) {:width 10})

(require '[fipp.clojure])
(fipp.clojure/pprint '(let [foo "abc 123"
                            bar {:x 1 :y 2 :z 3}]
                        (do-stuff foo (assoc bar :w 4)))
                    {:width 40})

The available options are:

  • :width defaults to 70.
  • :writer defaults to clojure.core/*out* (Clojure only).
  • :print-fn defaults to cljs.core/*print-fn* (ClojureScript only).
  • :print-length behaves as and defaults to clojure.core/*print-length*.
  • :print-level behaves as and defaults to clojure.core/*print-level*.
  • :print-meta behaves as and defaults to clojure.core/*print-meta*.

Any other supported/hidden options are subject to change.

Conveniences

The dbg macro can be used for convenient "printf debugging" of source file, line, expression, and evaluation result to *err*.

(require '[fipp.edn :refer [dbg]])
(dbg (repeat 5 (range 10)))

This will print:

/path/to/that/file.clj:2
(repeat 5 (range 10))
=>
((0 1 2 3 4 5 6 7 8 9)
 (0 1 2 3 4 5 6 7 8 9)
 (0 1 2 3 4 5 6 7 8 9)
 (0 1 2 3 4 5 6 7 8 9)
 (0 1 2 3 4 5 6 7 8 9))

A Fipp-enabled version of clojure.repl/pst is also available:

user=> (require '[fipp.repl :refer [pst]])
user=> (throw (ex-info "whoops" {:xs (range 20) :ys (range 20)}))

ExceptionInfo whoops  clojure.core/ex-info (core.clj:4617)
user=> (fipp.repl/pst)
ExceptionInfo whoops
{:xs (0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19),
 :ys (0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19)}
      clojure.core/ex-info (core.clj:4617)
      clojure.core/ex-info (core.clj:4617)
      user/eval3185 (form-init1248204588518004004.clj:1)
      user/eval3185 (form-init1248204588518004004.clj:1)
      clojure.lang.Compiler.eval (Compiler.java:6927)
      clojure.lang.Compiler.eval (Compiler.java:6890)
      clojure.core/eval (core.clj:3105)
      clojure.core/eval (core.clj:3101)
      clojure.main/repl/read-eval-print--7408/fn--7411 (main.clj:240)
      clojure.main/repl/read-eval-print--7408 (main.clj:240)
      clojure.main/repl/fn--7417 (main.clj:258)
      clojure.main/repl (main.clj:258)

Fast!

In my non-scientific testing, it has proven to be at least five times as fast as clojure.pprint. It also has the nice property of printing no later than having consumed the bounded amount of memory, so you see your first few lines of output instantaneously.

The core algorithm is described by Swierstra and Chitil in Linear, Bounded, Functional Pretty-Printing.

Swierstra and Chitil's implementation uses lazy evaluation and requires tying the knot to interleave the measuring and printing phases to achieve the bounded space goal.

However, this implementation is instead a port of the strict evaluation strategy as described by Kiselyov, Peyton-Jones, and Sabry in Lazy v. Yield: Incremental, Linear Pretty-printing.

Clojure's transducers are used to simulate generators and their yield operator. Unlike lazy reduction, transducers interleave execution of multi-phase transformations by function composition. This enables preservation of the bounded-space requirement and eases reasoning about the program's behavior. Additionally, it avoids a lot of intermediate object allocation.

Idiomatic!

Clojure's included pretty printer supports pluggable dispatch tables and provides an API for controlling the printing process. The programming model is side-effectual. For example, to print a breaking newline, you execute (pprint-newline :linear). This means that it's a difficult and tricky process to write or compose new pretty printers.

Fipp, on the other hand, accepts a "pretty print document" as input. This document is similar to HTML markup using hiccup.

Here are some examples:

(require '[fipp.engine :refer (pprint-document)])

(defn ppd [doc]
  (pprint-document doc {:width 10}))

(ppd [:span "One" :line "Two" :line "Three"])

(ppd [:group "(do" [:nest 2 :line "(step-1)" :line "(step-2)"] ")"])

If you want to write your own printer, see doc/primitives.md for details.

License

Copyright © 2015-2021 Brandon Bloom

Distributed under the Eclipse Public License, the same as Clojure.

Acknowledgements

Fipp is fast in part thanks to YourKit's Java Profiler.

More Repositories

1

jseg

A super simple, in-memory, JS graph database.
JavaScript
467
star
2

backtick

Clojure's syntax-quote reader macro as a normal macro
Clojure
193
star
3

cljs-vdom

Yet another (but somewhat novel) virtual DOM library
Clojure
121
star
4

eclj

Extensible Clojure
Clojure
103
star
5

factjor

A Factor-inspired, concatenative DSL for Clojure
Clojure
95
star
6

metaclj

Staged compilation for Clojure through environment & special-form aware syntax-quoting.
Clojure
77
star
7

asyncx

Some push sequence operators built with Clojure's core.async
Clojure
53
star
8

cleff

Algebraic Effect Handlers for Clojure
Clojure
45
star
9

proact

Yet another ClojureScript UI framework
Clojure
32
star
10

qplan

Solver for multi-way, multi-output dataflow property models
Clojure
32
star
11

dispatch-map

Persistent map with Clojure's multimethod dispatch semantics
Clojure
29
star
12

html2coffeekup

Converts HTML to Coffeekup markup
CoffeeScript
26
star
13

ambiparse

Parsing with "disambiguation filters" in Clojure
Clojure
22
star
14

terra-java

Lua/Terra + Java Native Interface
Terra
21
star
15

transduce

map-state, mapcat-state, etc for state transducers in Clojure
Clojure
21
star
16

domscript

Clojure
19
star
17

libclj

Embeddable reader and printer for Clojure forms
C
17
star
18

retree

Functional combinators for strategy-based tree-rewriting in Clojure
Clojure
15
star
19

cljsd

slow work in progress towards better cljs tools
Clojure
13
star
20

csearch.vim

Similar to ack.vim, but for golang's http://code.google.com/p/codesearch/
Vim Script
10
star
21

rtlcat

more concatenative experiments
Scheme
7
star
22

vim-factor

Pathogen-friendly packaging of Factor's Vim support (BSD licensed). I have no plans of actively maintaining this, it's mainly for personal convenience.
Vim Script
7
star
23

waet

The WebAssembly Edn Toolkit
Clojure
7
star
24

ascribe

Attribute Grammars in Clojure
Clojure
5
star
25

cljs-cps

Continuation Passing Transform for ClojureScript
Clojure
5
star
26

exstate

Some crazy thing inspired by plan9 & datomic
Clojure
4
star
27

libclj-ruby

Ruby extension for libclj
Ruby
2
star
28

metaclj-js

Staged JavaScript Metaprogramming from Clojure
Clojure
2
star
29

glens

Clojure
2
star
30

try_jade_and_stylus

Simple Node.js app to experiment with Jade and Stylus in the spirit of http://haml-lang.com/try.html and http://sass-lang.com/try.html
JavaScript
2
star
31

kovasir

Experiments in IR, instruction scheduling, and code gen
Clojure
2
star
32

goog-edit

Build scripts for extracting a stand alone Google Closure Rich Text Editor
2
star
33

vim-proto

Google's proto.vim for Protocol Buffer syntax; pathogen friendly
Vim Script
2
star
34

petri

Clojure
1
star
35

bulletcombinators

Automatically exported from code.google.com/p/bulletcombinators
Python
1
star
36

nyhub

Hacked up little script to find interesting GitHub users to meet
Clojure
1
star
37

noast

experiment in compiling without an ast
Go
1
star
38

astexplorer-cue

astexplorer.net support for cuelang.org
JavaScript
1
star
39

class-scheduler

A jQuery experiment from my college days
JavaScript
1
star
40

thinkfuse-schedule

Adapts common reoccurring schedule rules form iCal to ActiveModel.
Ruby
1
star