{-# LANGUAGE UndecidableInstances #-}

-- | This module provides the `Log` type and associated functions.
module Shrun.Logging.Types
  ( -- * Basic Types
    Log (..),
    LogMessage (..),
    fromUnlined,
    unsafeMapLogMessage,
    LogMode (..),
    LogLevel (..),

    -- * Console Logs
    ConsoleLog,
    LogRegion (..),

    -- * File Logs
    FileLog,
  )
where

import Shrun.Command.Types (CommandP1)
import Shrun.Data.Text (UnlinedText)
import Shrun.Logging.Types.Internal
  ( ConsoleLog,
    FileLog,
    LogMode
      ( LogModeAppend,
        LogModeFinish,
        LogModeSet
      ),
  )
import Shrun.Prelude

-- | Determines the logging level.
data LogLevel
  = LevelDebug
  | LevelCommand
  | LevelFinished
  | LevelTimer
  | LevelSuccess
  | LevelWarn
  | LevelError
  | LevelFatal
  | LevelKilled
  deriving stock (LogLevel
LogLevel -> LogLevel -> Bounded LogLevel
forall a. a -> a -> Bounded a
$cminBound :: LogLevel
minBound :: LogLevel
$cmaxBound :: LogLevel
maxBound :: LogLevel
Bounded, Int -> LogLevel
LogLevel -> Int
LogLevel -> [LogLevel]
LogLevel -> LogLevel
LogLevel -> LogLevel -> [LogLevel]
LogLevel -> LogLevel -> LogLevel -> [LogLevel]
(LogLevel -> LogLevel)
-> (LogLevel -> LogLevel)
-> (Int -> LogLevel)
-> (LogLevel -> Int)
-> (LogLevel -> [LogLevel])
-> (LogLevel -> LogLevel -> [LogLevel])
-> (LogLevel -> LogLevel -> [LogLevel])
-> (LogLevel -> LogLevel -> LogLevel -> [LogLevel])
-> Enum LogLevel
forall a.
(a -> a)
-> (a -> a)
-> (Int -> a)
-> (a -> Int)
-> (a -> [a])
-> (a -> a -> [a])
-> (a -> a -> [a])
-> (a -> a -> a -> [a])
-> Enum a
$csucc :: LogLevel -> LogLevel
succ :: LogLevel -> LogLevel
$cpred :: LogLevel -> LogLevel
pred :: LogLevel -> LogLevel
$ctoEnum :: Int -> LogLevel
toEnum :: Int -> LogLevel
$cfromEnum :: LogLevel -> Int
fromEnum :: LogLevel -> Int
$cenumFrom :: LogLevel -> [LogLevel]
enumFrom :: LogLevel -> [LogLevel]
$cenumFromThen :: LogLevel -> LogLevel -> [LogLevel]
enumFromThen :: LogLevel -> LogLevel -> [LogLevel]
$cenumFromTo :: LogLevel -> LogLevel -> [LogLevel]
enumFromTo :: LogLevel -> LogLevel -> [LogLevel]
$cenumFromThenTo :: LogLevel -> LogLevel -> LogLevel -> [LogLevel]
enumFromThenTo :: LogLevel -> LogLevel -> LogLevel -> [LogLevel]
Enum, LogLevel -> LogLevel -> Bool
(LogLevel -> LogLevel -> Bool)
-> (LogLevel -> LogLevel -> Bool) -> Eq LogLevel
forall a. (a -> a -> Bool) -> (a -> a -> Bool) -> Eq a
$c== :: LogLevel -> LogLevel -> Bool
== :: LogLevel -> LogLevel -> Bool
$c/= :: LogLevel -> LogLevel -> Bool
/= :: LogLevel -> LogLevel -> Bool
Eq, Int -> LogLevel -> ShowS
[LogLevel] -> ShowS
LogLevel -> String
(Int -> LogLevel -> ShowS)
-> (LogLevel -> String) -> ([LogLevel] -> ShowS) -> Show LogLevel
forall a.
(Int -> a -> ShowS) -> (a -> String) -> ([a] -> ShowS) -> Show a
$cshowsPrec :: Int -> LogLevel -> ShowS
showsPrec :: Int -> LogLevel -> ShowS
$cshow :: LogLevel -> String
show :: LogLevel -> String
$cshowList :: [LogLevel] -> ShowS
showList :: [LogLevel] -> ShowS
Show)

-- | 'ConsoleLog' with possible region.
data LogRegion r
  = -- | Log with region.
    LogRegion LogMode r ConsoleLog
  | -- | Log without region.
    LogNoRegion ConsoleLog

newtype LogMessage = UnsafeLogMessage Text
  deriving stock (LogMessage -> LogMessage -> Bool
(LogMessage -> LogMessage -> Bool)
-> (LogMessage -> LogMessage -> Bool) -> Eq LogMessage
forall a. (a -> a -> Bool) -> (a -> a -> Bool) -> Eq a
$c== :: LogMessage -> LogMessage -> Bool
== :: LogMessage -> LogMessage -> Bool
$c/= :: LogMessage -> LogMessage -> Bool
/= :: LogMessage -> LogMessage -> Bool
Eq, Int -> LogMessage -> ShowS
[LogMessage] -> ShowS
LogMessage -> String
(Int -> LogMessage -> ShowS)
-> (LogMessage -> String)
-> ([LogMessage] -> ShowS)
-> Show LogMessage
forall a.
(Int -> a -> ShowS) -> (a -> String) -> ([a] -> ShowS) -> Show a
$cshowsPrec :: Int -> LogMessage -> ShowS
showsPrec :: Int -> LogMessage -> ShowS
$cshow :: LogMessage -> String
show :: LogMessage -> String
$cshowList :: [LogMessage] -> ShowS
showList :: [LogMessage] -> ShowS
Show)
  deriving newtype (String -> LogMessage
(String -> LogMessage) -> IsString LogMessage
forall a. (String -> a) -> IsString a
$cfromString :: String -> LogMessage
fromString :: String -> LogMessage
IsString)

instance
  ( k ~ A_Getter,
    a ~ Text,
    b ~ Text
  ) =>
  LabelOptic "unLogMessage" k LogMessage LogMessage a b
  where
  labelOptic :: Optic k NoIx LogMessage LogMessage a b
labelOptic = (LogMessage -> a) -> Getter LogMessage a
forall s a. (s -> a) -> Getter s a
to (\(UnsafeLogMessage Text
t) -> a
Text
t)
  {-# INLINE labelOptic #-}

fromUnlined :: UnlinedText -> LogMessage
fromUnlined :: UnlinedText -> LogMessage
fromUnlined = Text -> LogMessage
UnsafeLogMessage (Text -> LogMessage)
-> (UnlinedText -> Text) -> UnlinedText -> LogMessage
forall b c a. (b -> c) -> (a -> b) -> a -> c
forall {k} (cat :: k -> k -> Type) (b :: k) (c :: k) (a :: k).
Category cat =>
cat b c -> cat a b -> cat a c
. Optic' A_Getter NoIx UnlinedText Text -> UnlinedText -> Text
forall k (is :: IxList) s a.
Is k A_Getter =>
Optic' k is s a -> s -> a
view Optic' A_Getter NoIx UnlinedText Text
#unUnlinedText

unsafeMapLogMessage :: (Text -> Text) -> LogMessage -> LogMessage
unsafeMapLogMessage :: (Text -> Text) -> LogMessage -> LogMessage
unsafeMapLogMessage Text -> Text
f (UnsafeLogMessage Text
m) = Text -> LogMessage
UnsafeLogMessage (Text -> Text
f Text
m)

-- | Captures the relevant information concerning a specific log
-- (i.e. command, text, level, and mode).
data Log = MkLog
  { -- | Optional command that produced this log.
    Log -> Maybe CommandP1
cmd :: Maybe CommandP1,
    -- | The 'Text' for a given log.
    Log -> LogMessage
msg :: LogMessage,
    -- | The 'LogLevel' for a given log.
    Log -> LogLevel
lvl :: LogLevel,
    -- | The 'LogMode' for a given log.
    Log -> LogMode
mode :: LogMode
  }
  deriving stock (Int -> Log -> ShowS
[Log] -> ShowS
Log -> String
(Int -> Log -> ShowS)
-> (Log -> String) -> ([Log] -> ShowS) -> Show Log
forall a.
(Int -> a -> ShowS) -> (a -> String) -> ([a] -> ShowS) -> Show a
$cshowsPrec :: Int -> Log -> ShowS
showsPrec :: Int -> Log -> ShowS
$cshow :: Log -> String
show :: Log -> String
$cshowList :: [Log] -> ShowS
showList :: [Log] -> ShowS
Show)

instance
  ( k ~ A_Lens,
    a ~ Maybe CommandP1,
    b ~ Maybe CommandP1
  ) =>
  LabelOptic "cmd" k Log Log a b
  where
  labelOptic :: Optic k NoIx Log Log a b
labelOptic =
    LensVL Log Log a b -> Lens Log Log a b
forall s t a b. LensVL s t a b -> Lens s t a b
lensVL
      (LensVL Log Log a b -> Lens Log Log a b)
-> LensVL Log Log a b -> Lens Log Log a b
forall a b. (a -> b) -> a -> b
$ \a -> f b
f (MkLog Maybe CommandP1
a1 LogMessage
a2 LogLevel
a3 LogMode
a4) ->
        (Maybe CommandP1 -> Log) -> f (Maybe CommandP1) -> f Log
forall a b. (a -> b) -> f a -> f b
forall (f :: Type -> Type) a b. Functor f => (a -> b) -> f a -> f b
fmap
          (\Maybe CommandP1
b -> Maybe CommandP1 -> LogMessage -> LogLevel -> LogMode -> Log
MkLog Maybe CommandP1
b LogMessage
a2 LogLevel
a3 LogMode
a4)
          (a -> f b
f a
Maybe CommandP1
a1)
  {-# INLINE labelOptic #-}

instance
  ( k ~ A_Lens,
    a ~ LogMessage,
    b ~ LogMessage
  ) =>
  LabelOptic "msg" k Log Log a b
  where
  labelOptic :: Optic k NoIx Log Log a b
labelOptic =
    LensVL Log Log a b -> Lens Log Log a b
forall s t a b. LensVL s t a b -> Lens s t a b
lensVL
      (LensVL Log Log a b -> Lens Log Log a b)
-> LensVL Log Log a b -> Lens Log Log a b
forall a b. (a -> b) -> a -> b
$ \a -> f b
f (MkLog Maybe CommandP1
a1 LogMessage
a2 LogLevel
a3 LogMode
a4) ->
        (LogMessage -> Log) -> f LogMessage -> f Log
forall a b. (a -> b) -> f a -> f b
forall (f :: Type -> Type) a b. Functor f => (a -> b) -> f a -> f b
fmap
          (\LogMessage
b -> Maybe CommandP1 -> LogMessage -> LogLevel -> LogMode -> Log
MkLog Maybe CommandP1
a1 LogMessage
b LogLevel
a3 LogMode
a4)
          (a -> f b
f a
LogMessage
a2)
  {-# INLINE labelOptic #-}

instance
  ( k ~ A_Lens,
    a ~ LogLevel,
    b ~ LogLevel
  ) =>
  LabelOptic "lvl" k Log Log a b
  where
  labelOptic :: Optic k NoIx Log Log a b
labelOptic =
    LensVL Log Log a b -> Lens Log Log a b
forall s t a b. LensVL s t a b -> Lens s t a b
lensVL
      (LensVL Log Log a b -> Lens Log Log a b)
-> LensVL Log Log a b -> Lens Log Log a b
forall a b. (a -> b) -> a -> b
$ \a -> f b
f (MkLog Maybe CommandP1
a1 LogMessage
a2 LogLevel
a3 LogMode
a4) ->
        (LogLevel -> Log) -> f LogLevel -> f Log
forall a b. (a -> b) -> f a -> f b
forall (f :: Type -> Type) a b. Functor f => (a -> b) -> f a -> f b
fmap
          (\LogLevel
b -> Maybe CommandP1 -> LogMessage -> LogLevel -> LogMode -> Log
MkLog Maybe CommandP1
a1 LogMessage
a2 LogLevel
b LogMode
a4)
          (a -> f b
f a
LogLevel
a3)
  {-# INLINE labelOptic #-}

instance
  ( k ~ A_Lens,
    a ~ LogMode,
    b ~ LogMode
  ) =>
  LabelOptic "mode" k Log Log a b
  where
  labelOptic :: Optic k NoIx Log Log a b
labelOptic =
    LensVL Log Log a b -> Lens Log Log a b
forall s t a b. LensVL s t a b -> Lens s t a b
lensVL
      (LensVL Log Log a b -> Lens Log Log a b)
-> LensVL Log Log a b -> Lens Log Log a b
forall a b. (a -> b) -> a -> b
$ \a -> f b
f (MkLog Maybe CommandP1
a1 LogMessage
a2 LogLevel
a3 LogMode
a4) ->
        (LogMode -> Log) -> f LogMode -> f Log
forall a b. (a -> b) -> f a -> f b
forall (f :: Type -> Type) a b. Functor f => (a -> b) -> f a -> f b
fmap
          (\LogMode
b -> Maybe CommandP1 -> LogMessage -> LogLevel -> LogMode -> Log
MkLog Maybe CommandP1
a1 LogMessage
a2 LogLevel
a3 LogMode
b)
          (a -> f b
f a
LogMode
a4)
  {-# INLINE labelOptic #-}