1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230
|
{-# LANGUAGE OverloadedStrings #-}
{-# LANGUAGE QuasiQuotes #-}
module Main (main) where
import Prelude hiding (words)
import qualified Data.List as L
import Data.Text (Text)
import qualified Data.Text as T
import qualified Data.Text.IO as T
import Prettyprinter
import Prettyprinter.Render.Text
import MultilineTh
main :: IO ()
main = (T.putStrLn . renderStrict . layoutPretty layoutOptions) readmeContents
where
layoutOptions = LayoutOptions { layoutPageWidth = AvailablePerLine 80 1 }
readmeContents :: Doc ann
readmeContents = (mconcat . L.intersperse vspace)
[ htmlComment "This file was auto-generated by the 'scripts/generate_readme' program."
, h1 "A modern Wadler/Leijen Prettyprinter"
, vcat
[ "[](https://travis-ci.org/quchen/prettyprinter)"
, "[](https://hackage.haskell.org/package/prettyprinter)"
, "[](https://www.stackage.org/package/prettyprinter)"
, "[](https://www.stackage.org/package/prettyprinter)" ]
, h2 "tl;dr"
, paragraph [multiline| 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. |]
, (pretty . T.unlines)
[ "```haskell"
, "let prettyType = align . sep . zipWith (<+>) (\"::\" : repeat \"->\")"
, " prettySig name ty = pretty name <+> prettyType ty"
, "in prettySig \"example\" [\"Int\", \"Bool\", \"Char\", \"IO ()\"]"
, "```"
, ""
, "```haskell"
, "-- Output for wide enough formats:"
, "example :: Int -> Bool -> Char -> IO ()"
, ""
, "-- Output for narrow formats:"
, "example :: Int"
, " -> Bool"
, " -> Char"
, " -> IO ()"
, "```" ]
, h2 "Longer; want to read"
, paragraph [multiline| 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`).* |]
, h2 "Why another prettyprinter?"
, paragraph [multiline| 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. |]
, h3 "`Text` instead of `String`"
, paragraph [multiline| `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. |]
, h3 "Extensive documentation"
, paragraph [multiline| 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. |]
, h3 "No name clashes"
, paragraph [multiline| 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. |]
, h3 "Annotation support"
, paragraph [multiline| 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. |]
, paragraph [multiline| 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](https://github.com/idris-lang/Idris-dev) is a project that makes
extensive use of such a feature. |]
, paragraph [multiline| 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. |]
, h3 "Extensible backends"
, paragraph [multiline| 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. |]
, paragraph [multiline| 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. |]
, h3 "Performance"
, paragraph [multiline| Rendering large documents should be done
efficiently, and the library should make it easy to optimize common use
cases for the programmer. |]
, h3 "Open implementation"
, paragraph [multiline| 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. |]
, h2 "The prettyprinter family"
, paragraph "The `prettyprinter` family of packages consists of:"
, (indent 2 . unorderedList . map paragraph)
[ [multiline| `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.|]
, [multiline| `prettyprinter-ansi-terminal` provides a renderer suitable
for ANSI terminal output including colors (at the cost of a
dependency more).|]
, [multiline| `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.|]
, [multiline| `prettyprinter-compat-ansi-wl-pprint` is the same, but for
previous users of `ansi-wl-pprint`.|]
, [multiline| `prettyprinter-compat-annotated-wl-pprint` is the same,
but for previous users of `annotated-wl-pprint`.|]
, [multiline| `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. |]
]
, h2 "Differences to the old Wadler/Leijen prettyprinters"
, paragraph [multiline| 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. |]
, paragraph "The most significant changes are:"
, (indent 2 . orderedList . map paragraph)
[ [multiline| `(<$>)` is removed as an operator, since it clashes with
the common alias for `fmap`. |]
, [multiline| All but the essential `<>` and `<+>` operators were
removed or replaced by ordinary names. |]
, [multiline| Everything extensively documented, with references to
other functions and runnable code examples. |]
, [multiline| Use of `Text` instead of `String`. |]
, [multiline| A `fuse` function to optimize often-used documents before
rendering for efficiency. |]
, [multiline| SimpleDoc was renamed `SimpleDocStream`, to contrast the
new `SimpleDocTree`. |]
, [multiline| 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. |]
]
, h2 "Historical notes"
, paragraph [multiline| 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«](https://homepages.inf.ed.ac.uk/wadler/papers/prettier/prettier.pdf),
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.|]
]
paragraph :: Text -> Doc ann
paragraph = align . fillSep . map pretty . T.words
vspace :: Doc ann
vspace = hardline <> hardline
h1 :: Doc ann -> Doc ann
h1 x = vspace <> underlineWith "=" x
h2 :: Doc ann -> Doc ann
h2 x = vspace <> underlineWith "-" x
h3 :: Doc ann -> Doc ann
h3 x = vspace <> "###" <+> x
underlineWith :: Text -> Doc ann -> Doc ann
underlineWith symbol x = align (width x (\w ->
hardline <> pretty (T.take w (T.replicate w symbol))))
orderedList :: [Doc ann] -> Doc ann
orderedList = align . vsep . zipWith (\i x -> pretty i <> dot <+> align x) [1::Int ..]
unorderedList :: [Doc ann] -> Doc ann
unorderedList = align . vsep . map ("-" <+>)
htmlComment :: Doc ann -> Doc ann
htmlComment = enclose "<!-- " " -->"
|