module Printcess.PrettyPrinting (
  -- * Overview
  -- $overview

  -- * Example
  -- $example

  -- * Rendering
  pretty,
  prettyPrint,

  -- * Config
  Config,
  cMaxLineWidth, cIndentChar, cIndentDepth, cIndentAfterBreaks,
  cInitIndent, cInitPrecedence,
  defConfig,

  -- * Type Class
  Pretty(..),

  -- * Monad
  PrettyM,

  -- * Sequencing
  (+>), (~>), (\>),

  -- * Indentation
  indentedByChars, indentedBy, indented,
  block, block',

  -- * Associativity & Fixity
  assocL, assocR, assocN,
  left, right, inner, AssocAnn(..),

  -- * Folding @Pretty@ Things
  betweenEach, beforeEach, afterEach,
  ppList, ppListMap, ppMap,

  -- * Other combinators
  bar, titleBar,

  -- * Constants
  nl, sp,

  -- * Lifted Type Classes
  Pretty1(..), Pretty2(..),

  -- * Reexports
  State, (.=),
  ) where

import Control.Monad.State.Strict
import Control.Lens

import Printcess.Config
import Printcess.Core
import Printcess.Combinators

{- $overview
    The main features of the @printcess@ pretty printing library are

    *   /Indentation/. Printing-actions are relative to the indentation level
        of their context. Special actions can be used to control the indentation
        level. Indentation is automatically inserted after newlines.

    *   /Automatic parenthesizing of mixfix operators/.
        Special printing-actions can be used to specify the associativity
        and fixity of operators and to mark the positions of their arguments.
        This makes it easy to print for example @"λx. λy. x y (x y)"@
        instead of @"(λx. (λy. ((x y) (x y))))"@.

    *   /Automatic line breaks after exceeding a maximum line width/.
        A maximum line width can be specified, after which lines are
        automatically broken. If the break point is inside a word,
        it is moved to the left until a white space character is reached.
        This avoids splitting identifiers into two.
-}

{- $example
    In this section, a small example is presented, which pretty prints a
    lambda calculus expression.

    First we define an abstract syntax tree for lambda calculus expressions.

    > data Expr
    >   = EVar String
    >   | EAbs String Expr
    >   | EApp Expr Expr

    Then we make @Expr@ an instance of the 'Pretty' type class, which
    declares one method 'pp'. This method takes an @Expr@ and returns a
    'PrettyM' @()@ action, which describes how to 'pretty' print the @Expr@.

    > instance Pretty Expr where
    >   pp (EVar x)     = pp x
    >   pp (EApp e1 e2) = assocL 9 $ L e1 ~> R e2
    >   pp (EAbs x e)   = assocR 0 $ "λ" +> I x +> "." ~> R e

    We print

    *   a variable @EVar x@ by printing the identifier 'String' @x@.

    *   a function application @EApp e1 e2@ as a left-associative operator of
        fixity 9 ('assocL' @9@), where e1 is the left argument ('L') and @e2@ is
        the right argument ('R'). The ('~>') combinator separates its first
        argument with a space from its second argument.

    *   a function abstraction @EAbs x e@ as a right-associative operator of
        fixity 0 ('assocR' @0@), where @x@ is an inner
        argument ('I') and @e@ is the right argument ('R').
        The ('+>') combinator behaves as ('~>'), but without inserting a space.

    Then we define a simple test expression @e1@ representing @λx. λy. x y (x y)@

    > e1 :: Expr
    > e1 = EAbs "x" $ EAbs "y" $ EApp (EApp (EVar "x") (EVar "y"))
    >                                 (EApp (EVar "x") (EVar "y"))

    and pretty print it to 'String' using the 'pretty' function

    > s1, s2 :: String
    > s1 = pretty defConfig                  e1    -- evaluates to "λx. λy. x y (x y)"
    > s2 = pretty (cMaxLineWidth .= Just 12) e1    -- evaluates to "λx. λy. x y
    >                                              --                   (x y)"
-}