{-# LANGUAGE BangPatterns #-}
{-# LANGUAGE CPP #-}
{-# LANGUAGE GeneralizedNewtypeDeriving #-}
{-# LANGUAGE OverloadedStrings #-}
{-# LANGUAGE RecordWildCards #-}
{-# LANGUAGE TemplateHaskell #-}
module Language.Haskell.Homplexity.Message (
Log
, Message
, Severity (..)
, severityOptions
, critical
, warn
, info
, debug
, message
, extract
) where
import Control.Arrow
import Control.DeepSeq
import Data.Foldable as Foldable
import Data.Function (on)
#if __GLASGOW_HASKELL__ >= 800
import Data.Semigroup (Semigroup (..))
#else
import Data.Monoid
#endif
import Data.Sequence as Seq
import HFlags
import Language.Haskell.Exts hiding (style)
import Language.Haskell.TH.Syntax (Lift (..))
#ifdef HTML_OUTPUT
import Prelude hiding (div, head, id, span)
import Text.Blaze.Html4.Strict hiding (map, style)
import Text.Blaze.Html4.Strict.Attributes hiding (span, title)
#endif
newtype Log = Log { unLog :: Seq Message }
deriving(Monoid
#if __GLASGOW_HASKELL__ >= 800
,Semigroup
#endif
)
instance NFData Log where
rnf = rnf . unLog
data Message = Message { msgSeverity :: !Severity
, msgText :: !String
, msgSrc :: !SrcLoc
}
deriving (Eq)
instance NFData Message where
rnf Message {msgSrc=SrcLoc{..},..} =
rnf msgSeverity `seq` rnf msgText `seq`
rnf srcFilename `seq` rnf srcLine `seq` rnf srcColumn
instance Show Message where
showsPrec _ Message {msgSrc=loc@SrcLoc{..}, ..} = shows msgSeverity
. (':':)
. (srcFilename++)
. (':':)
. shows loc
. (": "++)
. (msgText++)
. ('\n':)
#ifdef HTML_OUTPUT
instance ToMarkup Message where
toMarkup Message {msgSrc=SrcLoc{..}, ..} =
p ! classId $
(toMarkup msgSeverity
<> string ": "
<> (a ! href (toValue srcFilename) $ (string srcFilename))
<> string ": "
<> string msgText)
where
classId = case msgSeverity of
Debug -> class_ "debug"
Info -> class_ "info"
Warning -> class_ "warning"
Critical -> class_ "critical"
instance ToMarkup Severity where
toMarkup Debug = span ! class_ "severity" $ string (show Debug)
toMarkup Info = span ! class_ "severity" $ string (show Info)
toMarkup Warning = strong ! class_ "severity" $ string (show Warning)
toMarkup Critical = strong ! class_ "severity" $ string (show Critical)
#endif
data Severity = Debug
| Info
| Warning
| Critical
deriving (Eq, Ord, Read, Show, Enum, Bounded)
instance NFData Severity where
rnf !_a = ()
severityOptions :: String
severityOptions = unwords $ map show [minBound..(maxBound::Severity)]
instance Lift Severity where
lift Debug = [| Debug |]
lift Info = [| Info |]
lift Warning = [| Warning |]
lift Critical = [| Critical |]
instance FlagType Severity where
defineFlag n v = defineEQFlag n [| v :: Severity |] "{Debug|Info|Warning|Critical}"
message :: Severity -> SrcLoc -> String -> Log
message msgSeverity msgSrc msgText = Log $ Seq.singleton Message {..}
critical :: SrcLoc -> String -> Log
critical = message Critical
warn :: SrcLoc -> String -> Log
warn = message Warning
info :: SrcLoc -> String -> Log
info = message Info
debug :: SrcLoc -> String -> Log
debug = message Debug
msgOrdering :: Message -> Message -> Ordering
msgOrdering = compare `on` ((srcFilename &&& srcLine) . msgSrc)
orderedMessages :: Severity -> Log -> Seq Message
orderedMessages severity Log {..} = Seq.unstableSortBy msgOrdering $
Seq.filter ((severity<=) . msgSeverity) unLog
extract :: Severity -> Log -> [Message]
extract severity = Foldable.toList
. orderedMessages severity
instance Show Log where
showsPrec _ l e = Foldable.foldr shows e $
orderedMessages Debug l