homplexity-0.4.6.0: lib/Language/Haskell/Homplexity/Message.hs
{-# LANGUAGE BangPatterns #-}
{-# LANGUAGE CPP #-}
{-# LANGUAGE GeneralizedNewtypeDeriving #-}
{-# LANGUAGE OverloadedStrings #-}
{-# LANGUAGE RecordWildCards #-}
{-# LANGUAGE TemplateHaskell #-}
-- | Classifying messages by severity and filtering them.
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)
--import Text.Blaze.Renderer.Utf8 (renderMarkup)
#endif
-- | Keeps a set of messages
newtype Log = Log { unLog :: Seq Message }
deriving(Monoid
#if __GLASGOW_HASKELL__ >= 800
,Semigroup
#endif
)
instance NFData Log where
rnf = rnf . unLog
-- | Message from analysis
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
-- . shows srcLine
-- . shows srcColumn
. (": "++)
. (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
-- | Message severity
data Severity = Debug
| Info
| Warning
| Critical
deriving (Eq, Ord, Read, Show, Enum, Bounded)
instance NFData Severity where
rnf !_a = ()
-- | String showing all possible values for @Severity@.
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}"
-- | Helper for logging a message with given severity.
message :: Severity -> SrcLoc -> String -> Log
message msgSeverity msgSrc msgText = Log $ Seq.singleton Message {..}
-- | TODO: automatic inference of the srcLine
-- | Log a certain error
critical :: SrcLoc -> String -> Log
critical = message Critical
-- | Log a warning
warn :: SrcLoc -> String -> Log
warn = message Warning
-- | Log informational message
info :: SrcLoc -> String -> Log
info = message Info
-- | Log debugging message
debug :: SrcLoc -> String -> Log
debug = message Debug
-- TODO: check if this is not too slow
msgOrdering :: Message -> Message -> Ordering
msgOrdering = compare `on` ((srcFilename &&& srcLine) . msgSrc)
-- | Convert @Log@ into ordered sequence (@Seq@).
orderedMessages :: Severity -> Log -> Seq Message
orderedMessages severity Log {..} = Seq.unstableSortBy msgOrdering $
Seq.filter ((severity<=) . msgSeverity) unLog
-- | Extract an ordered sequence of messages from the @Log@.
extract :: Severity -> Log -> [Message]
extract severity = Foldable.toList
. orderedMessages severity
instance Show Log where
showsPrec _ l e = Foldable.foldr shows e $
orderedMessages Debug l