content: {-# LANGUAGE TypeFamilies #-}
  {-# LANGUAGE ConstraintKinds #-}
  {-# LANGUAGE ScopedTypeVariables #-}
  {-# LANGUAGE FlexibleContexts #-}
  {-# LANGUAGE DeriveDataTypeable #-}
  {-# LANGUAGE FlexibleInstances #-}
  {-# LANGUAGE GeneralizedNewtypeDeriving #-}
  {-# LANGUAGE MultiParamTypeClasses #-}
  {-# LANGUAGE UndecidableInstances #-}
  {-# LANGUAGE StandaloneDeriving #-}
  {-# LANGUAGE CPP #-}
  
  -- | All types.
  module Data.Conduit.Shell.Types where
  
  import Control.Applicative
  import UnliftIO.Exception
  import Control.Monad
  import Control.Monad.IO.Class
  import Control.Monad.Trans.Class
  import Control.Monad.Trans.Resource
  import Data.Conduit
  import Data.Typeable
  
  -- | Shell transformer.
  newtype ShellT m a = ShellT
    { runShellT :: ResourceT m a
    } deriving (Applicative, Monad, Functor, MonadThrow, MonadIO, MonadTrans)
  
  deriving instance (MonadUnliftIO m) => MonadResource (ShellT m)
  
  -- | Intentionally only handles 'ShellException'. Use normal exception
  -- handling to handle usual exceptions.
  instance (MonadUnliftIO (ShellT m), Applicative m, MonadThrow m) =>
           Alternative (ConduitT i o (ShellT m)) where
    empty = throwIO ShellEmpty
    x <|> y = do
      r <- tryC x
      case r of
        Left (_ :: ShellException) -> y
        Right rr -> return rr
  
  -- | An exception resulting from a shell command.
  data ShellException
    = ShellEmpty -- ^ For 'mempty'.
    | ShellExitFailure !Int -- ^ Process exited with failure.
    deriving (Typeable, Show)
  
  instance Exception ShellException
  