packages feed

sr-extra-1.64: Extra/Debug2.hs

-- | Generate debug messages - verbosity controls, indentation.

{-# LANGUAGE CPP #-}
{-# LANGUAGE DeriveDataTypeable #-}
{-# LANGUAGE FlexibleInstances #-}
{-# LANGUAGE MultiParamTypeClasses #-}
{-# LANGUAGE RankNTypes #-}
{-# LANGUAGE StandaloneDeriving #-}
{-# LANGUAGE TemplateHaskell #-}
{-# LANGUAGE UndecidableInstances #-}
{-# OPTIONS -Wall -Wredundant-constraints #-}

module Extra.Debug2
    ( HasTraceInfo(verbosityLens, prefixLens)
    , message
    , trace
    , indented
    , verbosity
    ) where

import Control.Lens ((%=), (.=), Lens', use)
import Control.Monad (when)
import Control.Monad.RWS
import Data.List (intercalate)
import qualified Debug.Trace
import Language.Haskell.TH.Instances ()
import System.Log.Logger (Priority(..))

-- Perform an action with modified state.
bracketState :: MonadState s m => Lens' s a -> (a -> a) -> m r -> m r
bracketState lns f action = do
  a0 <- use lns
  lns %= f
  r <- action
  lns .= a0
  return r

class HasTraceInfo a where
    verbosityLens :: Lens' a Priority
    prefixLens :: Lens' a String

-- | If the verbosity argument monad's verbosity level exceeds the verbosity argument,
-- prepend the current indentation string to the lines of a message
-- and output it.
message :: (HasTraceInfo s, MonadState s m) => (String -> m ()) -> Priority -> String -> m ()
message f p s = do
  v <- use verbosityLens
  when (p >= v) $ do
    i <- use prefixLens
    f (intercalate "\n" $ fmap (i ++) (lines s))

trace :: (HasTraceInfo s, MonadState s m) => String -> m ()
trace = message (\s -> Debug.Trace.trace s (return ())) DEBUG

-- | Perform an action with added indentation
indented :: (HasTraceInfo s, MonadState s m) => String -> m r -> m r
indented s action = bracketState prefixLens (<> s) action

-- | Perform an action with modified verbosity
verbosity :: (HasTraceInfo s, MonadState s m) => Priority -> m r -> m r
verbosity v action = bracketState verbosityLens (const v) action