{-# LANGUAGE GADTs, Rank2Types #-}
module Options.Applicative.Types (
ParseError(..),
ParserInfo(..),
ParserPrefs(..),
Option(..),
OptName(..),
OptReader(..),
OptProperties(..),
OptVisibility(..),
ReadM(..),
readerAbort,
readerError,
CReader(..),
Parser(..),
ParserM(..),
Completer(..),
mkCompleter,
CompletionResult(..),
ParserFailure(..),
ParserResult(..),
Args,
ArgPolicy(..),
OptHelpInfo(..),
OptTree(..),
fromM,
oneM,
manyM,
someM,
optVisibility,
optMetaVar,
optHelp,
optShowDefault
) where
import Control.Applicative
(Applicative(..), Alternative(..), (<$>), optional)
import Control.Monad (ap, liftM, MonadPlus, mzero, mplus)
import Data.Monoid (Monoid(..))
import System.Exit (ExitCode(..))
import Options.Applicative.Help.Pretty
import Options.Applicative.Help.Chunk
data ParseError
= ErrorMsg String
| InfoMsg String
| ShowHelpText
| UnknownError
deriving Show
instance Monoid ParseError where
mempty = UnknownError
mappend UnknownError m = m
mappend m _ = m
data ParserInfo a = ParserInfo
{ infoParser :: Parser a
, infoFullDesc :: Bool
, infoProgDesc :: Chunk Doc
, infoHeader :: Chunk Doc
, infoFooter :: Chunk Doc
, infoFailureCode :: Int
, infoIntersperse :: Bool
}
instance Functor ParserInfo where
fmap f i = i { infoParser = fmap f (infoParser i) }
data ParserPrefs = ParserPrefs
{ prefMultiSuffix :: String
, prefDisambiguate :: Bool
, prefShowHelpOnError :: Bool
, prefBacktrack :: Bool
, prefColumns :: Int
}
data OptName = OptShort !Char
| OptLong !String
deriving (Eq, Ord)
data OptVisibility
= Internal
| Hidden
| Visible
deriving (Eq, Ord)
data OptProperties = OptProperties
{ propVisibility :: OptVisibility
, propHelp :: Chunk Doc
, propMetaVar :: String
, propShowDefault :: Maybe String
}
data Option a = Option
{ optMain :: OptReader a
, optProps :: OptProperties
}
instance Functor Option where
fmap f (Option m p) = Option (fmap f m) p
data CReader m a = CReader
{ crCompleter :: Completer
, crReader :: String -> m a }
instance Functor m => Functor (CReader m) where
fmap f (CReader c r) = CReader c (fmap f . r)
newtype ReadM a = ReadM
{ runReadM :: Either ParseError a }
instance Functor ReadM where
fmap f (ReadM m) = ReadM (fmap f m)
instance Applicative ReadM where
pure = ReadM . Right
ReadM b <*> ReadM a = ReadM (b <*> a)
instance Monad ReadM where
return = ReadM . Right
ReadM m >>= f = ReadM $ m >>= runReadM . f
fail = ReadM . Left . ErrorMsg
instance MonadPlus ReadM where
mzero = ReadM $ Left UnknownError
mplus m1 m2 = case runReadM m1 of
Left _ -> m2
Right r -> return r
readerAbort :: ParseError -> ReadM a
readerAbort = ReadM . Left
readerError :: String -> ReadM a
readerError = readerAbort . ErrorMsg
type OptCReader = CReader ReadM
type ArgCReader = CReader Maybe
data OptReader a
= OptReader [OptName] (OptCReader a) ParseError
| FlagReader [OptName] !a
| ArgReader (ArgCReader a)
| CmdReader [String] (String -> Maybe (ParserInfo a))
instance Functor OptReader where
fmap f (OptReader ns cr e) = OptReader ns (fmap f cr) e
fmap f (FlagReader ns x) = FlagReader ns (f x)
fmap f (ArgReader cr) = ArgReader (fmap f cr)
fmap f (CmdReader cs g) = CmdReader cs ((fmap . fmap) f . g)
data Parser a where
NilP :: Maybe a -> Parser a
OptP :: Option a -> Parser a
MultP :: Parser (a -> b) -> Parser a -> Parser b
AltP :: Parser a -> Parser a -> Parser a
BindP :: Parser a -> (a -> Parser b) -> Parser b
instance Functor Parser where
fmap f (NilP x) = NilP (fmap f x)
fmap f (OptP opt) = OptP (fmap f opt)
fmap f (MultP p1 p2) = MultP (fmap (f.) p1) p2
fmap f (AltP p1 p2) = AltP (fmap f p1) (fmap f p2)
fmap f (BindP p k) = BindP p (fmap f . k)
instance Applicative Parser where
pure = NilP . Just
(<*>) = MultP
newtype ParserM r = ParserM
{ runParserM :: forall x . (r -> Parser x) -> Parser x }
instance Monad ParserM where
return x = ParserM $ \k -> k x
ParserM f >>= g = ParserM $ \k -> f (\x -> runParserM (g x) k)
instance Functor ParserM where
fmap = liftM
instance Applicative ParserM where
pure = return
(<*>) = ap
fromM :: ParserM a -> Parser a
fromM (ParserM f) = f pure
oneM :: Parser a -> ParserM a
oneM p = ParserM (BindP p)
manyM :: Parser a -> ParserM [a]
manyM p = do
mx <- oneM (optional p)
case mx of
Nothing -> return []
Just x -> (x:) <$> manyM p
someM :: Parser a -> ParserM [a]
someM p = (:) <$> oneM p <*> manyM p
instance Alternative Parser where
empty = NilP Nothing
(<|>) = AltP
many p = fromM $ manyM p
some p = fromM $ (:) <$> oneM p <*> manyM p
newtype Completer = Completer
{ runCompleter :: String -> IO [String] }
mkCompleter :: (String -> IO [String]) -> Completer
mkCompleter = Completer
instance Monoid Completer where
mempty = Completer $ \_ -> return []
mappend (Completer c1) (Completer c2) =
Completer $ \s -> (++) <$> c1 s <*> c2 s
newtype CompletionResult = CompletionResult
{ execCompletion :: String -> IO String }
newtype ParserFailure = ParserFailure
{ execFailure :: String -> (String, ExitCode) }
data ParserResult a
= Success a
| Failure ParserFailure
| CompletionInvoked CompletionResult
type Args = [String]
data ArgPolicy
= SkipOpts
| AllowOpts
deriving Eq
data OptHelpInfo = OptHelpInfo
{ hinfoMulti :: Bool
, hinfoDefault :: Bool }
data OptTree a
= Leaf a
| MultNode [OptTree a]
| AltNode [OptTree a]
deriving Show
optVisibility :: Option a -> OptVisibility
optVisibility = propVisibility . optProps
optHelp :: Option a -> Chunk Doc
optHelp = propHelp . optProps
optMetaVar :: Option a -> String
optMetaVar = propMetaVar . optProps
optShowDefault :: Option a -> Maybe String
optShowDefault = propShowDefault . optProps