{-# options_haddock prune #-}
module Ribosome.Host.Handler.Command where
import Type.Errors.Pretty (type (%), type (<>))
import Ribosome.Host.Data.Args (ArgList, Args, JsonArgs, Options)
import Ribosome.Host.Data.Bang (Bang)
import Ribosome.Host.Data.Bar (Bar)
import Ribosome.Host.Data.CommandMods (CommandMods)
import Ribosome.Host.Data.CommandRegister (CommandRegister)
import Ribosome.Host.Data.Range (Range, RangeStyleOpt (rangeStyleArg, rangeStyleOpt))
import Data.MessagePack (Object)
import Ribosome.Host.Class.Msgpack.Encode (toMsgpack)
data ArgCount =
Zero
|
MinZero
|
MinOne
deriving stock (ArgCount -> ArgCount -> Bool
(ArgCount -> ArgCount -> Bool)
-> (ArgCount -> ArgCount -> Bool) -> Eq ArgCount
forall a. (a -> a -> Bool) -> (a -> a -> Bool) -> Eq a
/= :: ArgCount -> ArgCount -> Bool
$c/= :: ArgCount -> ArgCount -> Bool
== :: ArgCount -> ArgCount -> Bool
$c== :: ArgCount -> ArgCount -> Bool
Eq, Int -> ArgCount -> ShowS
[ArgCount] -> ShowS
ArgCount -> String
(Int -> ArgCount -> ShowS)
-> (ArgCount -> String) -> ([ArgCount] -> ShowS) -> Show ArgCount
forall a.
(Int -> a -> ShowS) -> (a -> String) -> ([a] -> ShowS) -> Show a
showList :: [ArgCount] -> ShowS
$cshowList :: [ArgCount] -> ShowS
show :: ArgCount -> String
$cshow :: ArgCount -> String
showsPrec :: Int -> ArgCount -> ShowS
$cshowsPrec :: Int -> ArgCount -> ShowS
Show)
type family Max (l :: ArgCount) (r :: ArgCount) :: ArgCount where
Max 'Zero r = r
Max 'MinZero 'MinOne = 'MinOne
Max l _ = l
data OptionState =
OptionState {
OptionState -> Bool
allowed :: Bool,
OptionState -> ArgCount
minArgs :: ArgCount,
OptionState -> Maybe (*)
argsConsumed :: Maybe Type
}
type OptionStateZero =
'OptionState 'True 'Zero 'Nothing
type family CommandSpecial (a :: Type) :: Bool where
CommandSpecial (Range _) = 'True
CommandSpecial Bang = 'True
CommandSpecial Bar = 'True
CommandSpecial CommandMods = 'True
CommandSpecial CommandRegister = 'True
CommandSpecial Args = 'True
CommandSpecial ArgList = 'True
CommandSpecial (JsonArgs _) = 'True
CommandSpecial (Options _) = 'True
CommandSpecial _ = 'False
class SpecialParam (state :: OptionState) (a :: Type) where
type TransSpecial state a :: OptionState
type TransSpecial s _ =
s
specialOpt :: Map Text Object
specialOpt =
Map Text Object
forall a. Monoid a => a
mempty
specialArg :: Maybe Text
specialArg =
Maybe Text
forall a. Maybe a
Nothing
type family BeforeRegular (allowed :: Bool) (a :: Type) :: Constraint where
BeforeRegular 'False a =
TypeError ("Command option type " <> a <> " may not come after non-option") ~ ()
BeforeRegular 'True _ =
()
instance (
BeforeRegular al (Range rs),
RangeStyleOpt rs
) => SpecialParam ('OptionState al c ac) (Range rs) where
specialOpt :: Map Text Object
specialOpt =
forall (s :: RangeStyle). RangeStyleOpt s => Map Text Object
rangeStyleOpt @rs
specialArg :: Maybe Text
specialArg =
Text -> Maybe Text
forall a. a -> Maybe a
Just (forall (s :: RangeStyle). RangeStyleOpt s => Text
rangeStyleArg @rs)
instance (
BeforeRegular al Bang
) => SpecialParam ('OptionState al c ac) Bang where
specialOpt :: Map Text Object
specialOpt =
[(Text
"bang", Bool -> Object
forall a. MsgpackEncode a => a -> Object
toMsgpack Bool
True)]
specialArg :: Maybe Text
specialArg =
Text -> Maybe Text
forall a. a -> Maybe a
Just Text
"'<bang>' == '!'"
instance (
BeforeRegular al Bar
) => SpecialParam ('OptionState al c ac) Bar where
specialOpt :: Map Text Object
specialOpt =
[(Text
"bar", Bool -> Object
forall a. MsgpackEncode a => a -> Object
toMsgpack Bool
True)]
specialArg :: Maybe Text
specialArg =
Maybe Text
forall a. Maybe a
Nothing
instance (
BeforeRegular al CommandMods
) => SpecialParam ('OptionState al c ac) CommandMods where
specialOpt :: Map Text Object
specialOpt =
Map Text Object
forall a. Monoid a => a
mempty
specialArg :: Maybe Text
specialArg =
Text -> Maybe Text
forall a. a -> Maybe a
Just Text
"<q-mods>"
instance (
BeforeRegular al CommandRegister
) => SpecialParam ('OptionState al c ac) CommandRegister where
specialOpt :: Map Text Object
specialOpt =
[(Text
"register", Bool -> Object
forall a. MsgpackEncode a => a -> Object
toMsgpack Bool
True)]
specialArg :: Maybe Text
specialArg =
Text -> Maybe Text
forall a. a -> Maybe a
Just Text
"<q-register>"
instance SpecialParam ('OptionState al count 'Nothing) Args where
type TransSpecial ('OptionState _ count _) _ =
'OptionState 'True (Max count 'MinZero) ('Just Args)
instance SpecialParam ('OptionState al count ac) (JsonArgs a) where
type TransSpecial ('OptionState _ count _) (JsonArgs a) =
'OptionState 'True (Max count 'MinZero) ('Just (JsonArgs a))
instance SpecialParam ('OptionState al count ac) ArgList where
type TransSpecial ('OptionState _ count _) _ =
'OptionState 'True (Max count 'MinZero) ('Just ArgList)
instance SpecialParam ('OptionState al count 'Nothing) (Options a) where
type TransSpecial ('OptionState _ count _) (Options a) =
'OptionState 'True (Max count 'MinZero) ('Just (Options a))
class RegularParam (state :: OptionState) (isMaybe :: Bool) a where
type TransRegular state isMaybe a :: OptionState
type family ArgsError consumer a where
ArgsError consumer a =
TypeError (
"Custom parameter types (here " <> a <> ") cannot be combined with " <> consumer
%
"since " <> consumer <> " consumes all arguments"
)
instance RegularParam ('OptionState al count ('Just consumer)) m a where
type TransRegular ('OptionState al count ('Just consumer)) m a =
ArgsError consumer a
instance RegularParam ('OptionState al count 'Nothing) 'True (Maybe a) where
type TransRegular ('OptionState al count 'Nothing) 'True (Maybe a) =
'OptionState 'False (Max count 'MinZero) 'Nothing
instance RegularParam ('OptionState al count 'Nothing) 'False a where
type TransRegular ('OptionState al count 'Nothing) 'False a =
'OptionState 'False 'MinOne 'Nothing
class CommandParam (special :: Bool) (state :: OptionState) (a :: Type) where
type TransState special state a :: OptionState
paramOpt :: Map Text Object
paramOpt =
Map Text Object
forall a. Monoid a => a
mempty
paramArg :: Maybe Text
paramArg =
Maybe Text
forall a. Maybe a
Nothing
instance (
SpecialParam state a
) => CommandParam 'True state a where
type TransState 'True state a =
TransSpecial state a
paramOpt :: Map Text Object
paramOpt =
forall (state :: OptionState) a.
SpecialParam state a =>
Map Text Object
specialOpt @state @a
paramArg :: Maybe Text
paramArg =
forall (state :: OptionState) a. SpecialParam state a => Maybe Text
specialArg @state @a
type family IsMaybe (a :: Type) :: Bool where
IsMaybe (Maybe _) = 'True
IsMaybe _ = 'False
instance (
RegularParam state (IsMaybe a) a
) => CommandParam 'False state a where
type TransState 'False state a =
TransRegular state (IsMaybe a) a
class CommandHandler (state :: OptionState) (h :: Type) where
commandOptions :: (Map Text Object, [Text])
instance CommandHandler ('OptionState _a 'Zero c) (Sem r a) where
commandOptions :: (Map Text Object, [Text])
commandOptions =
([(Text
"nargs", forall a. MsgpackEncode a => a -> Object
toMsgpack @Int Int
0)], [])
instance CommandHandler ('OptionState _a 'MinZero c) (Sem r a) where
commandOptions :: (Map Text Object, [Text])
commandOptions =
([(Text
"nargs", forall a. MsgpackEncode a => a -> Object
toMsgpack @Text Text
"*")], [Item [Text]
"<f-args>"])
instance CommandHandler ('OptionState _a 'MinOne c) (Sem r a) where
commandOptions :: (Map Text Object, [Text])
commandOptions =
([(Text
"nargs", forall a. MsgpackEncode a => a -> Object
toMsgpack @Text Text
"+")], [Item [Text]
"<f-args>"])
instance (
special ~ CommandSpecial a,
next ~ TransState special state a,
CommandParam special state a,
CommandHandler next b
) => CommandHandler state (a -> b) where
commandOptions :: (Map Text Object, [Text])
commandOptions =
(Map Text Object
opts, [Text]
args)
where
opts :: Map Text Object
opts =
forall (special :: Bool) (state :: OptionState) a.
CommandParam special state a =>
Map Text Object
paramOpt @special @state @a Map Text Object -> Map Text Object -> Map Text Object
forall a. Semigroup a => a -> a -> a
<> Map Text Object
optsAfter
args :: [Text]
args =
Maybe Text -> [Text]
forall a. Maybe a -> [a]
maybeToList (forall (special :: Bool) (state :: OptionState) a.
CommandParam special state a =>
Maybe Text
paramArg @special @state @a) [Text] -> [Text] -> [Text]
forall a. Semigroup a => a -> a -> a
<> [Text]
argsAfter
(Map Text Object
optsAfter, [Text]
argsAfter) =
forall (state :: OptionState) h.
CommandHandler state h =>
(Map Text Object, [Text])
commandOptions @next @b