{-# LANGUAGE CPP #-}

-- | Custom prelude.
--
-- @since 0.1
module Pythia.Prelude
  ( -- * Misc
    headMaybe,
    throwLeft,
    throwMaybe,
    showt,
    natToDouble,

    -- * Display Utils
    (<+>),
    hsep,
    vsep,
    punctuate,
    comma,
    line,
    displayMaybe,
    displayList,
    builderToText,

    -- * Base
    module X,
  )
where

import Control.Applicative as X
  ( Alternative (empty, (<|>)),
    Applicative (pure, (*>), (<*), (<*>)),
  )
import Control.DeepSeq as X (NFData)
import Control.Monad as X
  ( Monad ((>>=)),
    join,
    unless,
    void,
    when,
    (<=<),
    (=<<),
    (>=>),
  )
import Data.Bifunctor as X (Bifunctor (bimap, first, second))
import Data.Bool as X (Bool (False, True), not, otherwise, (&&), (||))
import Data.ByteString as X (ByteString)
import Data.Char as X (Char)
import Data.Either as X (Either (Left, Right), either)
import Data.Eq as X (Eq ((/=), (==)))
import Data.Foldable as X
  ( Foldable (foldMap, foldl', foldr, length, null),
    foldr1,
    for_,
  )
import Data.Function as X (const, id, ($), (.))
import Data.Functor as X (Functor (fmap), ($>), (<$>), (<&>))
import Data.Int as X (Int)
import Data.Kind as X (Type)
import Data.List as X (filter, replicate)
import Data.List.NonEmpty as X (NonEmpty ((:|)))
import Data.Maybe as X (Maybe (Just, Nothing), fromMaybe, maybe)
import Data.Monoid as X (Monoid (mconcat, mempty))
import Data.Ord as X (Ord ((<=)), (<), (>))
import Data.Proxy as X (Proxy (Proxy))
import Data.Semigroup as X (Semigroup ((<>)))
import Data.String as X (IsString (fromString), String)
import Data.Text as X (Text)
import Data.Text qualified as T
import Data.Text.Display as X (Display (displayBuilder), display)
import Data.Traversable as X (Traversable (traverse), for)
import Data.Tuple as X (uncurry)
#if MIN_VERSION_base(4, 17, 0)
import Data.Type.Equality as X (type (~))
#endif
import Data.Text.Lazy qualified as TL
import Data.Text.Lazy.Builder as X (Builder)
import Data.Text.Lazy.Builder qualified as TLB
import Data.Void as X (Void)
import Data.Word as X (Word8)
import Effects.Exception as X
  ( Exception (displayException),
    MonadCatch,
    MonadThrow,
    SomeException,
    addCS,
    throwCS,
    throwM,
    tryAny,
  )
import Effects.FileSystem.FileReader as X
  ( MonadFileReader,
    decodeUtf8Lenient,
    readFileUtf8Lenient,
  )
import Effects.FileSystem.PathReader as X (MonadPathReader)
import Effects.FileSystem.Utils as X (OsPath, decodeOsToFpShow, osp, (</>))
import Effects.Process.Typed as X (MonadTypedProcess)
import Effects.System.Terminal as X (MonadTerminal (putStrLn), print, putTextLn)
import Effects.Time as X (MonadTime)
import GHC.Enum as X (Bounded (maxBound, minBound), Enum (toEnum))
import GHC.Err as X (error, undefined)
import GHC.Float as X (Double, Float)
import GHC.Generics as X (Generic)
import GHC.Integer as X (Integer)
import GHC.Natural as X (Natural)
import GHC.Num as X (Num ((*), (+), (-)))
import GHC.Read as X (Read)
import GHC.Real as X (even, floor, fromIntegral, (/))
import GHC.Show as X (Show (show))
import Optics.Core as X
  ( A_Lens,
    A_Prism,
    An_Iso,
    Iso,
    Iso',
    LabelOptic (labelOptic),
    Lens',
    Prism',
    iso,
    lensVL,
    over,
    prism,
    re,
    view,
    (%),
    (%~),
    (.~),
    (^.),
    (^?),
    _1,
    _2,
    _Left,
    _Right,
  )
import System.IO as X (FilePath, IO)

-- $setup
-- >>> :set -XDeriveAnyClass
-- >>> data AnException = AnException deriving (Exception, Show)

-- | Total version of 'Prelude.head'.
--
-- ==== __Examples__
--
-- >>> headMaybe []
-- Nothing
--
-- >>> headMaybe [3, 4]
-- Just 3
--
-- @since 0.1
headMaybe :: [a] -> Maybe a
headMaybe :: forall a. [a] -> Maybe a
headMaybe [] = Maybe a
forall a. Maybe a
Nothing
headMaybe (a
x : [a]
_) = a -> Maybe a
forall a. a -> Maybe a
Just a
x
{-# INLINEABLE headMaybe #-}

-- | Throws 'Left'.
--
-- @since 0.1
throwLeft :: forall m e a. (Exception e, MonadThrow m) => Either e a -> m a
throwLeft :: forall (m :: Type -> Type) e a.
(Exception e, MonadThrow m) =>
Either e a -> m a
throwLeft = (e -> m a) -> (a -> m a) -> Either e a -> m a
forall a c b. (a -> c) -> (b -> c) -> Either a b -> c
either e -> m a
forall (m :: Type -> Type) e a.
(Exception e, HasCallStack, MonadThrow m) =>
e -> m a
throwCS a -> m a
forall a. a -> m a
forall (f :: Type -> Type) a. Applicative f => a -> f a
pure
{-# INLINEABLE throwLeft #-}

-- | @throwMaybe e x@ throws @e@ if @x@ is 'Nothing'.
--
-- @since 0.1
throwMaybe :: forall m e a. (Exception e, MonadThrow m) => e -> Maybe a -> m a
throwMaybe :: forall (m :: Type -> Type) e a.
(Exception e, MonadThrow m) =>
e -> Maybe a -> m a
throwMaybe e
e = m a -> (a -> m a) -> Maybe a -> m a
forall b a. b -> (a -> b) -> Maybe a -> b
maybe (e -> m a
forall (m :: Type -> Type) e a.
(Exception e, HasCallStack, MonadThrow m) =>
e -> m a
throwCS e
e) a -> m a
forall a. a -> m a
forall (f :: Type -> Type) a. Applicative f => a -> f a
pure
{-# INLINEABLE throwMaybe #-}

-- | 'Text' version of 'show'.
--
-- @since 0.1
showt :: (Show a) => a -> Text
showt :: forall a. Show a => a -> Text
showt = String -> Text
T.pack (String -> Text) -> (a -> String) -> a -> Text
forall b c a. (b -> c) -> (a -> b) -> a -> c
. a -> String
forall a. Show a => a -> String
show
{-# INLINEABLE showt #-}

-- | @since 0.1
natToDouble :: Natural -> Double
natToDouble :: Natural -> Double
natToDouble = Natural -> Double
forall a b. (Integral a, Num b) => a -> b
fromIntegral
{-# INLINE natToDouble #-}

hsep :: [Builder] -> Builder
hsep :: [Builder] -> Builder
hsep = (Builder -> Builder -> Builder) -> [Builder] -> Builder
forall (t :: Type -> Type).
Foldable t =>
(Builder -> Builder -> Builder) -> t Builder -> Builder
concatWith Builder -> Builder -> Builder
(<+>)

vsep :: [Builder] -> Builder
vsep :: [Builder] -> Builder
vsep = (Builder -> Builder -> Builder) -> [Builder] -> Builder
forall (t :: Type -> Type).
Foldable t =>
(Builder -> Builder -> Builder) -> t Builder -> Builder
concatWith (\Builder
x Builder
y -> Builder
x Builder -> Builder -> Builder
forall a. Semigroup a => a -> a -> a
<> Builder
line Builder -> Builder -> Builder
forall a. Semigroup a => a -> a -> a
<> Builder
y)

punctuate :: Builder -> [Builder] -> [Builder]
punctuate :: Builder -> [Builder] -> [Builder]
punctuate Builder
_ [] = []
punctuate Builder
_ [Builder
x] = [Builder
x]
punctuate Builder
p (Builder
x : [Builder]
xs) = Builder
x Builder -> Builder -> Builder
forall a. Semigroup a => a -> a -> a
<> Builder
p Builder -> [Builder] -> [Builder]
forall a. a -> [a] -> [a]
: Builder -> [Builder] -> [Builder]
punctuate Builder
p [Builder]
xs

(<+>) :: Builder -> Builder -> Builder
Builder
x <+> :: Builder -> Builder -> Builder
<+> Builder
y = Builder
x Builder -> Builder -> Builder
forall a. Semigroup a => a -> a -> a
<> Builder
" " Builder -> Builder -> Builder
forall a. Semigroup a => a -> a -> a
<> Builder
y

comma :: Builder
comma :: Builder
comma = Builder
","

line :: Builder
line :: Builder
line = Builder
"\n"

-- vendored from prettyprinter, for text's Builder
concatWith :: (Foldable t) => (Builder -> Builder -> Builder) -> t Builder -> Builder
concatWith :: forall (t :: Type -> Type).
Foldable t =>
(Builder -> Builder -> Builder) -> t Builder -> Builder
concatWith Builder -> Builder -> Builder
f t Builder
ds
  | t Builder -> Bool
forall a. t a -> Bool
forall (t :: Type -> Type) a. Foldable t => t a -> Bool
null t Builder
ds = Builder
forall a. Monoid a => a
mempty
  | Bool
otherwise = (Builder -> Builder -> Builder) -> t Builder -> Builder
forall a. (a -> a -> a) -> t a -> a
forall (t :: Type -> Type) a.
Foldable t =>
(a -> a -> a) -> t a -> a
foldr1 Builder -> Builder -> Builder
f t Builder
ds

displayMaybe :: (Display a) => Maybe a -> Builder
displayMaybe :: forall a. Display a => Maybe a -> Builder
displayMaybe (Just a
x) = a -> Builder
forall a. Display a => a -> Builder
displayBuilder a
x
displayMaybe Maybe a
Nothing = Builder
"<nothing>"

displayList :: (Display a) => [a] -> Builder
displayList :: forall a. Display a => [a] -> Builder
displayList [] = Builder
"<empty>"
displayList xs :: [a]
xs@(a
_ : [a]
_) =
  [Builder] -> Builder
hsep
    ([Builder] -> Builder) -> ([a] -> [Builder]) -> [a] -> Builder
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Builder -> [Builder] -> [Builder]
punctuate Builder
comma
    ([Builder] -> [Builder]) -> ([a] -> [Builder]) -> [a] -> [Builder]
forall b c a. (b -> c) -> (a -> b) -> a -> c
. (a -> Builder) -> [a] -> [Builder]
forall a b. (a -> b) -> [a] -> [b]
forall (f :: Type -> Type) a b. Functor f => (a -> b) -> f a -> f b
fmap a -> Builder
forall a. Display a => a -> Builder
displayBuilder
    ([a] -> Builder) -> [a] -> Builder
forall a b. (a -> b) -> a -> b
$ [a]
xs

-- | Intermediate function for Display a => a -> Text, for when we want to
-- use a custom builder, and not the type's built-in displayBuilder.
builderToText :: Builder -> Text
builderToText :: Builder -> Text
builderToText = Text -> Text
TL.toStrict (Text -> Text) -> (Builder -> Text) -> Builder -> Text
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Builder -> Text
TLB.toLazyText