• Stars
    star
    293
  • Rank 141,748 (Top 3 %)
  • Language
    Haskell
  • License
    BSD 2-Clause "Sim...
  • Created over 7 years ago
  • Updated 7 months ago

Reviews

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

Repository Details

A modern, extensible and well-documented prettyprinter.

A modern Wadler/Leijen Prettyprinter

tl;dr

A prettyprinter/text rendering engine. Easy to use, well-documented, ANSI terminal backend exists, HTML backend is trivial to implement, no name clashes, Text-based, extensible.

let prettyType = align . sep . zipWith (<+>) ("::" : repeat "->")
    prettySig name ty = pretty name <+> prettyType ty
in  prettySig "example" ["Int", "Bool", "Char", "IO ()"]
-- Output for wide enough formats:
example :: Int -> Bool -> Char -> IO ()

-- Output for narrow formats:
example :: Int
        -> Bool
        -> Char
        -> IO ()

Longer; want to read

This package defines a prettyprinter to format text in a flexible and convenient way. The idea is to combine a document out of many small components, then using a layouter to convert it to an easily renderable simple document, which can then be rendered to a variety of formats, for example plain Text, or Markdown. What you are reading right now was generated by this library (see GenerateReadme.hs).

Why another prettyprinter?

Haskell, more specifically Hackage, has a zoo of Wadler/Leijen based prettyprinters already. Each of them addresses a different concern with the classic wl-pprint package. This package solves all these issues, and then some.

Text instead of String

String has exactly one use, and that’s showing Hello World in tutorials. For all other uses, Text is what people should be using. The prettyprinter uses no String definitions anywhere; using a String means an immediate conversion to the internal Text-based format.

Extensive documentation

The library is stuffed with runnable examples, showing use cases for the vast majority of exported values. Many things reference related definitions, everything comes with at least a sentence explaining its purpose.

No name clashes

Many prettyprinters use the legacy API of the first Wadler/Leijen prettyprinter, which used e.g. (<$>) to separate lines, which clashes with the ubiquitous synonym for fmap that’s been in Base for ages. These definitions were either removed or renamed, so there are no name clashes with standard libraries anymore.

Annotation support

Text is not all letters and newlines. Often, we want to add more information, the simplest kind being some form of styling. An ANSI terminal supports coloring, a web browser a plethora of different formattings.

More complex uses of annotations include e.g. adding type annotations for mouse-over hovers when printing a syntax tree, adding URLs to documentation, or adding source locations to show where a certain piece of output comes from. Idris is a project that makes extensive use of such a feature.

Special care has been applied to make annotations unobtrusive, so that if you don’t need or care about them there is no overhead, neither in terms of usability nor performance.

Extensible backends

A document can be rendered in many different ways, for many different clients. There is plain text, there is the ANSI terminal, there is the browser. Each of these speak different languages, and the backend is responsible for the translation to those languages. Backends should be readily available, or easy to implement if a custom solution is desired.

As a result, each backend requires only minimal dependencies; if you don’t want to print to an ANSI terminal for example, there is no need to have a dependency on a terminal library.

Performance

Rendering large documents should be done efficiently, and the library should make it easy to optimize common use cases for the programmer.

Open implementation

The type of documents is abstract in most of the other Wadler/Leijen prettyprinters, making it hard to impossible to write adaptors from one library to another. The type should be exposed for such purposes so it is possible to write adaptors from library to library, or each of them is doomed to live on its own small island of incompatibility. For this reason, the Doc type is fully exposed in a semi-internal module for this specific use case.

The prettyprinter family

The prettyprinter family of packages consists of:

  • prettyprinter is the core package. It defines the language to generate nicely laid out documents, which can then be given to renderers to display them in various ways, e.g. HTML, or plain text.
  • prettyprinter-ansi-terminal provides a renderer suitable for ANSI terminal output including colors (at the cost of a dependency more).
  • prettyprinter-compat-wl-pprint provides a drop-in compatibility layer for previous users of the wl-pprint package. Use it for easy adaption of the new prettyprinter, but don't develop anything new with it.
  • prettyprinter-compat-ansi-wl-pprint is the same, but for previous users of ansi-wl-pprint.
  • prettyprinter-compat-annotated-wl-pprint is the same, but for previous users of annotated-wl-pprint.
  • prettyprinter-convert-ansi-wl-pprint is a converter, not a drop-in replacement, for documents generated by ansi-wl-pprint. Useful for interfacing with other libraries that use the other format, like Trifecta and Optparse-Applicative.

Differences to the old Wadler/Leijen prettyprinters

The library originally started as a fork of ansi-wl-pprint until every line had been touched. The result is still in the same spirit as its predecessors, but modernized to match the current ecosystem and needs.

The most significant changes are:

  1. (<$>) is removed as an operator, since it clashes with the common alias for fmap.
  2. All but the essential <> and <+> operators were removed or replaced by ordinary names.
  3. Everything extensively documented, with references to other functions and runnable code examples.
  4. Use of Text instead of String.
  5. A fuse function to optimize often-used documents before rendering for efficiency.
  6. SimpleDoc was renamed SimpleDocStream, to contrast the new SimpleDocTree.
  7. In the ANSI backend, instead of providing an own colorization function for each color/intensity/layer combination, they have been combined in color, colorDull, bgColor, and bgColorDull functions, which can be found in the ANSI terminal specific prettyprinter-ansi-terminal package.

Historical notes

This module is based on previous work by Daan Leijen and Max Bolingbroke, who implemented and significantly extended the prettyprinter given by a paper by Phil Wadler in his 1997 paper »A Prettier Printer«, by adding lots of convenience functions, styling, and new functionality. Their package, ansi-wl-pprint is widely used in the Haskell ecosystem, and is at the time of writing maintained by Edward Kmett.

More Repositories

1

articles

Miscellaneous articles. The readme is the table of contents.
Haskell
1,249
star
2

stgi

A user-centric visual STG implementation to help understand GHC/Haskell's execution model.
Haskell
526
star
3

generative-art

I wanted to make a nicer sticker for Munihac, then things got out of hand.
Haskell
148
star
4

stackage-everything

»I want Stackage on an airplane and I have only 3 minutes until takeoff«
Haskell
83
star
5

acme-everything

Install everything.
Haskell
20
star
6

amoeba

Amœba is a distributed network.
Haskell
18
star
7

show-prettyprint

Robust prettyprinter for output of auto-generated Show instances
Haskell
18
star
8

hackage-graph

A graph of the interdependencies of the packages of hackage.haskell.org.
Haskell
16
star
9

cabal-install-bin

Install binary packages in a temporary Cabal sandbox
Shell
16
star
10

unmaintainable_haskell

How to write unmaintainable Haskell code
12
star
11

talks

A collection of the talks I’ve given in the past.
JavaScript
11
star
12

stackalone

Building self-contained (offline-only) Haskell program tarballs; only Stack+GHC needed
Haskell
10
star
13

agda-learning

Stuff I’m writing to learn Agda.
Agda
9
star
14

quchen.github.io

My online ID card.
7
star
15

binary-typed

Thin type-safe layer for the Haskell Binary library.
Haskell
5
star
16

ErgoDox

Fire-and-forget build system for configuring my Infinity Ergodox
Haskell
5
star
17

HaskellEuler

Project Euler using Haskell
Haskell
5
star
18

pgp-wordlist

Translate between binary data and a human-readable collection of words.
Haskell
5
star
19

lambda-ski

A lambda and SKI calculus playground
Haskell
4
star
20

geb-miu-puzzle

Visualize the GEB MIU puzzle using Haskell and GraphViz
Graphviz (DOT)
4
star
21

shack

An experimental library for writing quick-and-dirty shell scripts using Haskell.
Haskell
4
star
22

client-server-example

Simple IO-heavy application for demonstration purposes
Haskell
3
star
23

wr21

TNG Winterretreat 2021
C++
3
star
24

penrose

Generating penrose tilings with Haskell and Cairo
Haskell
3
star
25

voron

G-code
3
star
26

factorio

Shell
3
star
27

qa-playground

Full QA example in Haskell: Various testsuites, test coverage, benchmarks.
Haskell
2
star
28

workshop-2020-01-tum

Haskell
2
star
29

crypto-test

Basic cryptography APIs
Haskell
2
star
30

hpio

GPIO library for Haskell
Haskell
2
star
31

frp-workshop

Files for a workshop on FRP, using the Reactive Banana library.
Haskell
2
star
32

acme-language-extensions

Library that checks whether certain Haskell language extensions are enabled. Use in production immediately.
Haskell
2
star
33

factorio-blueprints

View and modify blueprints from the »Factorio« computer game.
Haskell
1
star
34

generustive

Implementing parts of my generative-art project using Rust as a learning project.
Rust
1
star
35

hscheme

Scheme (R5RS) interpreter in Haskell
Haskell
1
star
36

rustfuck

A Brainfuck interpreter written in Rust.
Rust
1
star
37

vsafe

vsafe - Very Simple Asymmetric File Exchange
Shell
1
star
38

munihac-2018-beginner

JavaScript
1
star