packages feed

sandwich-hedgehog-0.1.3.1: src/Test/Sandwich/Hedgehog/Render.hs

{-# OPTIONS_GHC -fno-warn-missing-signatures #-}

module Test.Sandwich.Hedgehog.Render (
  renderHedgehogToImage
  , renderHedgehogToTokens

  -- * Util
  , dedent
  ) where

import Data.Function
import qualified Data.List as L
import qualified Data.Text as T
import Graphics.Vty.Attributes hiding (currentAttr)
import Graphics.Vty.Image
import Hedgehog.Internal.Report
import Text.PrettyPrint.Annotated.WL (Doc)
import qualified Text.PrettyPrint.Annotated.WL as WL


renderHedgehogToImage :: Doc Markup -> Image
renderHedgehogToImage doc = foldTokens emptyImage defaultAttr $ renderHedgehogToTokens doc

foldTokens imageSoFar currentAttr ((Str "\n"):xs) = (if imageSoFar == emptyImage then text defaultAttr " " else imageSoFar) <-> foldTokens emptyImage currentAttr xs
foldTokens imageSoFar currentAttr ((Str s):xs) = foldTokens (imageSoFar <|> text' currentAttr s) currentAttr xs
foldTokens imageSoFar _currentAttr ((NewAttr attr):xs) = foldTokens imageSoFar attr xs
foldTokens imageSoFar _currentAttr [] = imageSoFar

renderHedgehogToTokens :: Doc Markup -> [Token]
renderHedgehogToTokens doc =
  WL.indent 0 doc
  & WL.renderSmart 100
  & WL.displayDecorated (\x -> [NewAttr $ start x]) end (\x -> [Str (T.pack x)])
  & joinAdjacentStrings
  & splitNewlines
  where
    joinAdjacentStrings ((Str s1):(Str s2):xs) = joinAdjacentStrings (Str (s1 <> s2) : xs)
    joinAdjacentStrings (x:xs) = x : joinAdjacentStrings xs
    joinAdjacentStrings [] = []

    splitNewlines :: [Token] -> [Token]
    splitNewlines ((Str s):xs) = [Str s' | s' <- parts, s' /= ""] <> splitNewlines xs
      where parts = L.intersperse "\n" $ T.splitOn "\n" s
    splitNewlines (x:xs) = x : splitNewlines xs
    splitNewlines [] = []

data Token = Str T.Text
           | NewAttr Attr
  deriving (Show)

dedent :: Int -> String -> String
dedent n s
  | (replicate n ' ') `L.isPrefixOf` s = L.drop n s
  | otherwise = s

-- * This all is modeled after Hedgehog.Internal.Report

defaultAttr = Attr Default Default Default Default
redVivid = withForeColor defaultAttr brightRed
redDull = withForeColor defaultAttr red
redVividBold = flip withStyle bold $ withForeColor defaultAttr brightRed
yellowDull = withForeColor defaultAttr yellow
magentaDull = withForeColor defaultAttr magenta
greenDull = withForeColor defaultAttr green
blackVivid = withForeColor defaultAttr brightBlack

start = \case
  WaitingIcon -> defaultAttr
  WaitingHeader -> defaultAttr
  RunningIcon -> defaultAttr
  RunningHeader -> defaultAttr
  ShrinkingIcon -> redVivid
  ShrinkingHeader -> redVivid
  FailedIcon -> redVivid
  FailedText -> redVivid
  GaveUpIcon -> yellowDull
  GaveUpText -> yellowDull
  SuccessIcon -> greenDull
  SuccessText -> greenDull
  CoverageIcon -> yellowDull
  CoverageText -> yellowDull
  CoverageFill -> blackVivid

  DeclarationLocation -> defaultAttr

  StyledLineNo StyleDefault -> defaultAttr
  StyledSource StyleDefault -> defaultAttr
  StyledBorder StyleDefault -> defaultAttr

  StyledLineNo StyleAnnotation -> magentaDull
  StyledSource StyleAnnotation -> defaultAttr
  StyledBorder StyleAnnotation -> defaultAttr
  AnnotationGutter -> magentaDull
  AnnotationValue -> magentaDull

  StyledLineNo StyleFailure -> redVivid
  StyledSource StyleFailure -> redVividBold
  StyledBorder StyleFailure -> defaultAttr
  FailureArrows -> redVivid
  FailureMessage -> defaultAttr
  FailureGutter -> defaultAttr

  DiffPrefix -> defaultAttr
  DiffInfix -> defaultAttr
  DiffSuffix -> defaultAttr
  DiffSame -> defaultAttr
  DiffRemoved -> redDull
  DiffAdded -> greenDull

  ReproduceHeader -> defaultAttr
  ReproduceGutter -> defaultAttr
  ReproduceSource -> defaultAttr

end _ = [NewAttr defaultAttr]