-- | Provides various exception types.
--
-- @since 0.1
module Pythia.Control.Exception
  ( -- * Miscellaneous Exceptions
    CommandException (..),
    SomeExceptions (..),
    NotSupportedException (..),
    NoActionsRunException (..),
  )
where

import Data.Text qualified as T
import Pythia.Data.Command (Command)
import Pythia.Prelude

-- $setup
-- >>> import Data.List.NonEmpty (NonEmpty ((:|)))
-- >>> import Pythia.Prelude

-- | Exceptions encountered while running a shell command.
--
-- ==== __Examples__
-- >>> putStrLn $ displayException $ MkCommandException "some command" "an error message"
-- Command exception. Command: <some command>. Error: <an error message>
--
-- @since 0.1
type CommandException :: Type
data CommandException = MkCommandException Command Text
  deriving stock
    ( -- | @since 0.1
      CommandException -> CommandException -> Bool
(CommandException -> CommandException -> Bool)
-> (CommandException -> CommandException -> Bool)
-> Eq CommandException
forall a. (a -> a -> Bool) -> (a -> a -> Bool) -> Eq a
$c== :: CommandException -> CommandException -> Bool
== :: CommandException -> CommandException -> Bool
$c/= :: CommandException -> CommandException -> Bool
/= :: CommandException -> CommandException -> Bool
Eq,
      -- | @since 0.1
      Int -> CommandException -> ShowS
[CommandException] -> ShowS
CommandException -> String
(Int -> CommandException -> ShowS)
-> (CommandException -> String)
-> ([CommandException] -> ShowS)
-> Show CommandException
forall a.
(Int -> a -> ShowS) -> (a -> String) -> ([a] -> ShowS) -> Show a
$cshowsPrec :: Int -> CommandException -> ShowS
showsPrec :: Int -> CommandException -> ShowS
$cshow :: CommandException -> String
show :: CommandException -> String
$cshowList :: [CommandException] -> ShowS
showList :: [CommandException] -> ShowS
Show
    )

-- | @since 0.1
instance Exception CommandException where
  displayException :: CommandException -> String
displayException (MkCommandException Command
c Text
t) =
    [String] -> String
forall a. Monoid a => [a] -> a
mconcat
      [ String
"Command exception. Command: <",
        Text -> String
T.unpack (Text -> String) -> Text -> String
forall a b. (a -> b) -> a -> b
$ Command
c Command -> Optic' An_Iso NoIx Command Text -> Text
forall k s (is :: IxList) a.
Is k A_Getter =>
s -> Optic' k is s a -> a
^. Optic' An_Iso NoIx Command Text
#unCommand,
        String
">. Error: <",
        Text -> String
T.unpack Text
t,
        String
">"
      ]

-- | Collects 1 or more exceptions.
--
-- ==== __Examples__
-- >>> let ex1 = toException $ MkCommandException "some command" "an error message"
-- >>> let ex2 = toException $ MkNotSupportedException "app1"
-- >>> displayException $ MkSomeExceptions $ ex1 :| [ex2]
-- "Encountered 2 exception(s):\n\n- App not supported: <app1>\n\n- Command exception. Command: <some command>. Error: <an error message>"
--
-- @since 0.1
type SomeExceptions :: Type
newtype SomeExceptions = MkSomeExceptions (NonEmpty SomeException)
  deriving stock
    ( -- | @since 0.1
      Int -> SomeExceptions -> ShowS
[SomeExceptions] -> ShowS
SomeExceptions -> String
(Int -> SomeExceptions -> ShowS)
-> (SomeExceptions -> String)
-> ([SomeExceptions] -> ShowS)
-> Show SomeExceptions
forall a.
(Int -> a -> ShowS) -> (a -> String) -> ([a] -> ShowS) -> Show a
$cshowsPrec :: Int -> SomeExceptions -> ShowS
showsPrec :: Int -> SomeExceptions -> ShowS
$cshow :: SomeExceptions -> String
show :: SomeExceptions -> String
$cshowList :: [SomeExceptions] -> ShowS
showList :: [SomeExceptions] -> ShowS
Show
    )

-- | @since 0.1
instance Exception SomeExceptions where
  displayException :: SomeExceptions -> String
displayException (MkSomeExceptions NonEmpty SomeException
xs) =
    [String] -> String
forall a. Monoid a => [a] -> a
mconcat
      [ String
"Encountered ",
        Int -> String
forall a. Show a => a -> String
show (Int -> String) -> Int -> String
forall a b. (a -> b) -> a -> b
$ NonEmpty SomeException -> Int
forall a. NonEmpty a -> Int
forall (t :: Type -> Type) a. Foldable t => t a -> Int
length NonEmpty SomeException
xs,
        String
" exception(s):",
        (String -> SomeException -> String)
-> String -> NonEmpty SomeException -> String
forall b a. (b -> a -> b) -> b -> NonEmpty a -> b
forall (t :: Type -> Type) b a.
Foldable t =>
(b -> a -> b) -> b -> t a -> b
foldl' String -> SomeException -> String
forall {e}. Exception e => String -> e -> String
foldExs String
"" NonEmpty SomeException
xs
      ]
    where
      foldExs :: String -> e -> String
foldExs String
acc e
ex = (String
"\n\n- " String -> ShowS
forall a. Semigroup a => a -> a -> a
<> e -> String
forall e. Exception e => e -> String
displayException e
ex) String -> ShowS
forall a. Semigroup a => a -> a -> a
<> String
acc

-- | @since 0.1
instance Semigroup SomeExceptions where
  MkSomeExceptions NonEmpty SomeException
l <> :: SomeExceptions -> SomeExceptions -> SomeExceptions
<> MkSomeExceptions NonEmpty SomeException
r = NonEmpty SomeException -> SomeExceptions
MkSomeExceptions (NonEmpty SomeException -> SomeExceptions)
-> NonEmpty SomeException -> SomeExceptions
forall a b. (a -> b) -> a -> b
$ NonEmpty SomeException
l NonEmpty SomeException
-> NonEmpty SomeException -> NonEmpty SomeException
forall a. Semigroup a => a -> a -> a
<> NonEmpty SomeException
r

-- | Error for when the current app is not supported.
--
-- ==== __Examples__
-- >>> putStrLn $ displayException $ MkNotSupportedException "app1"
-- App not supported: <app1>
--
-- @since 0.1
type NotSupportedException :: Type
newtype NotSupportedException = MkNotSupportedException Text
  deriving stock
    ( -- | @since 0.1
      NotSupportedException -> NotSupportedException -> Bool
(NotSupportedException -> NotSupportedException -> Bool)
-> (NotSupportedException -> NotSupportedException -> Bool)
-> Eq NotSupportedException
forall a. (a -> a -> Bool) -> (a -> a -> Bool) -> Eq a
$c== :: NotSupportedException -> NotSupportedException -> Bool
== :: NotSupportedException -> NotSupportedException -> Bool
$c/= :: NotSupportedException -> NotSupportedException -> Bool
/= :: NotSupportedException -> NotSupportedException -> Bool
Eq,
      -- | @since 0.1
      Int -> NotSupportedException -> ShowS
[NotSupportedException] -> ShowS
NotSupportedException -> String
(Int -> NotSupportedException -> ShowS)
-> (NotSupportedException -> String)
-> ([NotSupportedException] -> ShowS)
-> Show NotSupportedException
forall a.
(Int -> a -> ShowS) -> (a -> String) -> ([a] -> ShowS) -> Show a
$cshowsPrec :: Int -> NotSupportedException -> ShowS
showsPrec :: Int -> NotSupportedException -> ShowS
$cshow :: NotSupportedException -> String
show :: NotSupportedException -> String
$cshowList :: [NotSupportedException] -> ShowS
showList :: [NotSupportedException] -> ShowS
Show
    )

-- | @since 0.1
instance Exception NotSupportedException where
  displayException :: NotSupportedException -> String
displayException (MkNotSupportedException Text
e) =
    [String] -> String
forall a. Monoid a => [a] -> a
mconcat
      [ String
"App not supported: <",
        Text -> String
T.unpack Text
e,
        String
">"
      ]

-- | Error for when no actions are run.
--
-- ==== __Examples__
-- >>> putStrLn $ displayException MkNoActionsRunException
-- No actions run
--
-- @since 0.1
type NoActionsRunException :: Type
data NoActionsRunException = MkNoActionsRunException
  deriving stock
    ( -- | @since 0.1
      NoActionsRunException -> NoActionsRunException -> Bool
(NoActionsRunException -> NoActionsRunException -> Bool)
-> (NoActionsRunException -> NoActionsRunException -> Bool)
-> Eq NoActionsRunException
forall a. (a -> a -> Bool) -> (a -> a -> Bool) -> Eq a
$c== :: NoActionsRunException -> NoActionsRunException -> Bool
== :: NoActionsRunException -> NoActionsRunException -> Bool
$c/= :: NoActionsRunException -> NoActionsRunException -> Bool
/= :: NoActionsRunException -> NoActionsRunException -> Bool
Eq,
      -- | @since 0.1
      Int -> NoActionsRunException -> ShowS
[NoActionsRunException] -> ShowS
NoActionsRunException -> String
(Int -> NoActionsRunException -> ShowS)
-> (NoActionsRunException -> String)
-> ([NoActionsRunException] -> ShowS)
-> Show NoActionsRunException
forall a.
(Int -> a -> ShowS) -> (a -> String) -> ([a] -> ShowS) -> Show a
$cshowsPrec :: Int -> NoActionsRunException -> ShowS
showsPrec :: Int -> NoActionsRunException -> ShowS
$cshow :: NoActionsRunException -> String
show :: NoActionsRunException -> String
$cshowList :: [NoActionsRunException] -> ShowS
showList :: [NoActionsRunException] -> ShowS
Show
    )

-- | @since 0.1
instance Exception NoActionsRunException where
  displayException :: NoActionsRunException -> String
displayException NoActionsRunException
_ = String
"No actions run"