packages feed

alms-0.4.11: src/Message/Render.hs

{-# LANGUAGE
      FlexibleInstances,
      GADTs,
      ParallelListComp,
      QuasiQuotes
      #-}
module Message.Render (
  module PprClass
) where

import PprClass
import Message.AST

-- | Context for message rendering
data RenderContext
  = RenderContext {
      rcDetail  :: Int,
      rcQtLevel :: Int,
      rcLeft    :: Doc,
      rcRight   :: Doc
    }

rc0 :: RenderContext
rc0  = RenderContext (-1) 0 empty empty

getQuotes :: RenderContext -> (String, String)
getQuotes cxt =
  if even (rcQtLevel cxt)
    then ("‘", "’")
    else ("“", "”")

incQuotes :: RenderContext -> RenderContext
incQuotes cxt = cxt { rcQtLevel = rcQtLevel cxt + 1 }

clearLeft, clearRight :: RenderContext -> RenderContext
clearLeft cxt  = cxt { rcLeft = empty }
clearRight cxt = cxt { rcRight = empty }

addQuotes :: RenderContext -> Doc -> Doc
addQuotes cxt doc = rcLeft cxt <> doc <> rcRight cxt

renderAntiMsg     :: String -> String -> Doc
renderAntiMsg  t a = text "${" <> text t <> colon <> text a <> char '}'

renderMessageH :: RenderContext -> Message H -> [Doc]
renderMessageH cxt msg0 = case msg0 of
  Words s     -> renderMessageH cxt (Flow (map Exact (words s)))
  Exact s     -> [addQuotes cxt (text s)]
  Flow []     -> [addQuotes cxt empty]
  Flow [msg'] -> renderMessageH cxt msg'
  Flow (m:ms) -> renderMessageH (clearRight cxt) m ++
                 concatMap (renderMessageH cxt') (init ms) ++
                 renderMessageH (clearLeft cxt) (last ms)
     where cxt' = clearRight (clearLeft cxt)
  Surround s e msg'
              -> renderMessageH cxt' {
                   rcLeft  = rcLeft cxt <> text s,
                   rcRight = text e <> rcRight cxt
                 } msg'
    where cxt'   = clearRight (clearLeft cxt)
  Quote msg'  -> renderMessageH cxt' (Surround s e msg')
    where (s, e) = getQuotes cxt
          cxt'   = incQuotes cxt
  Printable d a -> [addQuotes cxt (pprDepth d' a)]
    where d' = if d == 0 then rcDetail cxt else d
  Showable a  -> [addQuotes cxt (text (show a))]
  AntiMsg t a -> [addQuotes cxt (renderAntiMsg t a)]

renderMessage :: RenderContext -> Message d -> Doc
renderMessage cxt msg0 = case msg0 of
  Words s     -> fsep $ renderMessageH cxt (Words s)
  Flow s      -> fsep $ renderMessageH cxt (Flow s)
  Exact s     -> text s
  Surround s e msg'
              -> text s <> renderMessage cxt msg' <> text e
  Quote msg'  -> renderMessage cxt' (Surround s e msg')
    where (s, e) = getQuotes cxt
          cxt'   = incQuotes cxt
  Stack sty msgs -> case sty of
    Numbered  -> vcat [ integer i <> char '.' <+>
                        text (replicate (dent - length (show i)) ' ') <>
                        nest (dent + 2) (renderMessage cxt msg')
                      | msg' <- msgs
                      | i    <- [ 1 .. ] ]
      where len  = length msgs
            dent = length (show len)
    Bulleted  -> vcat [ text " •" <+> nest 3 (renderMessage cxt msg')
                      | msg' <- msgs ]
    Separated -> vcat (punctuate (char '\n')
                                 (map (renderMessage cxt) msgs))
    Broken    -> vcat (map (renderMessage cxt) msgs)
  Table rows  -> vcat [ text label <+>
                        text (replicate (dent - length label) ' ') <>
                        nest (dent + 1) (renderMessage cxt msg')
                      | (label, msg') <- rows ]
    where dent = maximum (map (length . fst) rows)
  Indent msg' -> text "    " <>
                 nest 4 (renderMessage cxt msg')
  Printable d a -> pprDepth d' a
    where d' = if d == 0 then rcDetail cxt else d
  Showable a  -> text (show a)
  AntiMsg t a -> renderAntiMsg t a

instance Ppr (Message d)  where ppr = renderMessage rc0
instance Show (Message d) where showsPrec = showFromPpr