packages feed

calamity 0.1.14.3 → 0.1.14.4

raw patch · 12 files changed

+251/−82 lines, 12 filesPVP: major bump suggested

API removals or changes: PVP suggests a major version bump

API changes (from Hackage documentation)

- Calamity.Commands.Command: [$sel:name:Command] :: Command -> Text
- Calamity.Commands.Group: [$sel:name:Group] :: Group -> Text
+ Calamity.Commands.AliasType: Alias :: AliasType
+ Calamity.Commands.AliasType: Original :: AliasType
+ Calamity.Commands.AliasType: data AliasType
+ Calamity.Commands.AliasType: instance GHC.Classes.Eq Calamity.Commands.AliasType.AliasType
+ Calamity.Commands.AliasType: instance GHC.Enum.Enum Calamity.Commands.AliasType.AliasType
+ Calamity.Commands.AliasType: instance GHC.Generics.Generic Calamity.Commands.AliasType.AliasType
+ Calamity.Commands.AliasType: instance GHC.Show.Show Calamity.Commands.AliasType.AliasType
+ Calamity.Commands.AliasType: instance TextShow.Classes.TextShow Calamity.Commands.AliasType.AliasType
+ Calamity.Commands.Command: [$sel:names:Command] :: Command -> NonEmpty Text
+ Calamity.Commands.Dsl: commandA :: forall ps r. (Member (Final IO) r, TypedCommandC ps r) => Text -> [Text] -> (Context -> CommandForParsers ps r) -> Sem (DSLState r) Command
+ Calamity.Commands.Dsl: commandA' :: Member (Final IO) r => Text -> [Text] -> [Text] -> (Context -> Sem r (Either CommandError a)) -> ((Context, a) -> Sem (Fail : r) ()) -> Sem (DSLState r) Command
+ Calamity.Commands.Dsl: groupA :: Member (Final IO) r => Text -> [Text] -> Sem (DSLState r) a -> Sem (DSLState r) a
+ Calamity.Commands.Dsl: groupA' :: Member (Final IO) r => Text -> [Text] -> Sem (DSLState r) a -> Sem (DSLState r) a
+ Calamity.Commands.Group: [$sel:names:Group] :: Group -> NonEmpty Text
+ Calamity.Types.Model.Presence.Activity: activity :: Text -> ActivityType -> Activity
- Calamity.Cache.Eff: delDM :: forall r_a9wjX. MemberWithError CacheEff r_a9wjX => Snowflake DMChannel -> Sem r_a9wjX ()
+ Calamity.Cache.Eff: delDM :: forall r_a9wBm. MemberWithError CacheEff r_a9wBm => Snowflake DMChannel -> Sem r_a9wBm ()
- Calamity.Cache.Eff: delGuild :: forall r_a9wjQ. MemberWithError CacheEff r_a9wjQ => Snowflake Guild -> Sem r_a9wjQ ()
+ Calamity.Cache.Eff: delGuild :: forall r_a9wBf. MemberWithError CacheEff r_a9wBf => Snowflake Guild -> Sem r_a9wBf ()
- Calamity.Cache.Eff: delMessage :: forall r_a9wki. MemberWithError CacheEff r_a9wki => Snowflake Message -> Sem r_a9wki ()
+ Calamity.Cache.Eff: delMessage :: forall r_a9wBH. MemberWithError CacheEff r_a9wBH => Snowflake Message -> Sem r_a9wBH ()
- Calamity.Cache.Eff: delUnavailableGuild :: forall r_a9wkb. MemberWithError CacheEff r_a9wkb => Snowflake Guild -> Sem r_a9wkb ()
+ Calamity.Cache.Eff: delUnavailableGuild :: forall r_a9wBA. MemberWithError CacheEff r_a9wBA => Snowflake Guild -> Sem r_a9wBA ()
- Calamity.Cache.Eff: delUser :: forall r_a9wk4. MemberWithError CacheEff r_a9wk4 => Snowflake User -> Sem r_a9wk4 ()
+ Calamity.Cache.Eff: delUser :: forall r_a9wBt. MemberWithError CacheEff r_a9wBt => Snowflake User -> Sem r_a9wBt ()
- Calamity.Cache.Eff: getBotUser :: forall r_a9wjI. MemberWithError CacheEff r_a9wjI => Sem r_a9wjI (Maybe User)
+ Calamity.Cache.Eff: getBotUser :: forall r_a9wB7. MemberWithError CacheEff r_a9wB7 => Sem r_a9wB7 (Maybe User)
- Calamity.Cache.Eff: getDM :: forall r_a9wjU. MemberWithError CacheEff r_a9wjU => Snowflake DMChannel -> Sem r_a9wjU (Maybe DMChannel)
+ Calamity.Cache.Eff: getDM :: forall r_a9wBj. MemberWithError CacheEff r_a9wBj => Snowflake DMChannel -> Sem r_a9wBj (Maybe DMChannel)
- Calamity.Cache.Eff: getDMs :: forall r_a9wjW. MemberWithError CacheEff r_a9wjW => Sem r_a9wjW [DMChannel]
+ Calamity.Cache.Eff: getDMs :: forall r_a9wBl. MemberWithError CacheEff r_a9wBl => Sem r_a9wBl [DMChannel]
- Calamity.Cache.Eff: getGuild :: forall r_a9wjL. MemberWithError CacheEff r_a9wjL => Snowflake Guild -> Sem r_a9wjL (Maybe Guild)
+ Calamity.Cache.Eff: getGuild :: forall r_a9wBa. MemberWithError CacheEff r_a9wBa => Snowflake Guild -> Sem r_a9wBa (Maybe Guild)
- Calamity.Cache.Eff: getGuildChannel :: forall r_a9wjN. MemberWithError CacheEff r_a9wjN => Snowflake GuildChannel -> Sem r_a9wjN (Maybe GuildChannel)
+ Calamity.Cache.Eff: getGuildChannel :: forall r_a9wBc. MemberWithError CacheEff r_a9wBc => Snowflake GuildChannel -> Sem r_a9wBc (Maybe GuildChannel)
- Calamity.Cache.Eff: getGuilds :: forall r_a9wjP. MemberWithError CacheEff r_a9wjP => Sem r_a9wjP [Guild]
+ Calamity.Cache.Eff: getGuilds :: forall r_a9wBe. MemberWithError CacheEff r_a9wBe => Sem r_a9wBe [Guild]
- Calamity.Cache.Eff: getMessage :: forall r_a9wkf. MemberWithError CacheEff r_a9wkf => Snowflake Message -> Sem r_a9wkf (Maybe Message)
+ Calamity.Cache.Eff: getMessage :: forall r_a9wBE. MemberWithError CacheEff r_a9wBE => Snowflake Message -> Sem r_a9wBE (Maybe Message)
- Calamity.Cache.Eff: getMessages :: forall r_a9wkh. MemberWithError CacheEff r_a9wkh => Sem r_a9wkh [Message]
+ Calamity.Cache.Eff: getMessages :: forall r_a9wBG. MemberWithError CacheEff r_a9wBG => Sem r_a9wBG [Message]
- Calamity.Cache.Eff: getUnavailableGuilds :: forall r_a9wka. MemberWithError CacheEff r_a9wka => Sem r_a9wka [Snowflake Guild]
+ Calamity.Cache.Eff: getUnavailableGuilds :: forall r_a9wBz. MemberWithError CacheEff r_a9wBz => Sem r_a9wBz [Snowflake Guild]
- Calamity.Cache.Eff: getUser :: forall r_a9wk1. MemberWithError CacheEff r_a9wk1 => Snowflake User -> Sem r_a9wk1 (Maybe User)
+ Calamity.Cache.Eff: getUser :: forall r_a9wBq. MemberWithError CacheEff r_a9wBq => Snowflake User -> Sem r_a9wBq (Maybe User)
- Calamity.Cache.Eff: getUsers :: forall r_a9wk3. MemberWithError CacheEff r_a9wk3 => Sem r_a9wk3 [User]
+ Calamity.Cache.Eff: getUsers :: forall r_a9wBs. MemberWithError CacheEff r_a9wBs => Sem r_a9wBs [User]
- Calamity.Cache.Eff: isUnavailableGuild :: forall r_a9wk8. MemberWithError CacheEff r_a9wk8 => Snowflake Guild -> Sem r_a9wk8 Bool
+ Calamity.Cache.Eff: isUnavailableGuild :: forall r_a9wBx. MemberWithError CacheEff r_a9wBx => Snowflake Guild -> Sem r_a9wBx Bool
- Calamity.Cache.Eff: setBotUser :: forall r_a9wjG. MemberWithError CacheEff r_a9wjG => User -> Sem r_a9wjG ()
+ Calamity.Cache.Eff: setBotUser :: forall r_a9wB5. MemberWithError CacheEff r_a9wB5 => User -> Sem r_a9wB5 ()
- Calamity.Cache.Eff: setDM :: forall r_a9wjS. MemberWithError CacheEff r_a9wjS => DMChannel -> Sem r_a9wjS ()
+ Calamity.Cache.Eff: setDM :: forall r_a9wBh. MemberWithError CacheEff r_a9wBh => DMChannel -> Sem r_a9wBh ()
- Calamity.Cache.Eff: setGuild :: forall r_a9wjJ. MemberWithError CacheEff r_a9wjJ => Guild -> Sem r_a9wjJ ()
+ Calamity.Cache.Eff: setGuild :: forall r_a9wB8. MemberWithError CacheEff r_a9wB8 => Guild -> Sem r_a9wB8 ()
- Calamity.Cache.Eff: setMessage :: forall r_a9wkd. MemberWithError CacheEff r_a9wkd => Message -> Sem r_a9wkd ()
+ Calamity.Cache.Eff: setMessage :: forall r_a9wBC. MemberWithError CacheEff r_a9wBC => Message -> Sem r_a9wBC ()
- Calamity.Cache.Eff: setUnavailableGuild :: forall r_a9wk6. MemberWithError CacheEff r_a9wk6 => Snowflake Guild -> Sem r_a9wk6 ()
+ Calamity.Cache.Eff: setUnavailableGuild :: forall r_a9wBv. MemberWithError CacheEff r_a9wBv => Snowflake Guild -> Sem r_a9wBv ()
- Calamity.Cache.Eff: setUser :: forall r_a9wjZ. MemberWithError CacheEff r_a9wjZ => User -> Sem r_a9wjZ ()
+ Calamity.Cache.Eff: setUser :: forall r_a9wBo. MemberWithError CacheEff r_a9wBo => User -> Sem r_a9wBo ()
- Calamity.Commands.Command: Command :: Text -> Maybe Group -> [Check] -> [Text] -> (Context -> Text) -> (Context -> IO (Either CommandError a)) -> ((Context, a) -> IO (Maybe Text)) -> Command
+ Calamity.Commands.Command: Command :: NonEmpty Text -> Maybe Group -> [Check] -> [Text] -> (Context -> Text) -> (Context -> IO (Either CommandError a)) -> ((Context, a) -> IO (Maybe Text)) -> Command
- Calamity.Commands.CommandUtils: buildCommand :: forall ps r. (Member (Final IO) r, TypedCommandC ps r) => Text -> Maybe Group -> [Check] -> (Context -> Text) -> (Context -> CommandForParsers ps r) -> Sem r Command
+ Calamity.Commands.CommandUtils: buildCommand :: forall ps r. (Member (Final IO) r, TypedCommandC ps r) => NonEmpty Text -> Maybe Group -> [Check] -> (Context -> Text) -> (Context -> CommandForParsers ps r) -> Sem r Command
- Calamity.Commands.CommandUtils: buildCommand' :: Member (Final IO) r => Text -> Maybe Group -> [Check] -> [Text] -> (Context -> Text) -> (Context -> Sem r (Either CommandError a)) -> ((Context, a) -> Sem (Fail : r) ()) -> Sem r Command
+ Calamity.Commands.CommandUtils: buildCommand' :: Member (Final IO) r => NonEmpty Text -> Maybe Group -> [Check] -> [Text] -> (Context -> Text) -> (Context -> Sem r (Either CommandError a)) -> ((Context, a) -> Sem (Fail : r) ()) -> Sem r Command
- Calamity.Commands.Dsl: type DSLState r = (LocalWriter (HashMap Text Command) : LocalWriter (HashMap Text Group) : Reader (Maybe Group) : Reader (Context -> Text) : Tagged "original-help" (Reader (Context -> Text)) : Reader [Check] : Reader CommandHandler : Fixpoint : r)
+ Calamity.Commands.Dsl: type DSLState r = (LocalWriter (HashMap Text (Command, AliasType)) : LocalWriter (HashMap Text (Group, AliasType)) : Reader (Maybe Group) : Reader (Context -> Text) : Tagged "original-help" (Reader (Context -> Text)) : Reader [Check] : Reader CommandHandler : Fixpoint : r)
- Calamity.Commands.Group: Group :: Text -> Maybe Group -> HashMap Text Command -> HashMap Text Group -> (Context -> Text) -> [Check] -> Group
+ Calamity.Commands.Group: Group :: NonEmpty Text -> Maybe Group -> HashMap Text (Command, AliasType) -> HashMap Text (Group, AliasType) -> (Context -> Text) -> [Check] -> Group
- Calamity.Commands.Group: [$sel:children:Group] :: Group -> HashMap Text Group
+ Calamity.Commands.Group: [$sel:children:Group] :: Group -> HashMap Text (Group, AliasType)
- Calamity.Commands.Group: [$sel:commands:Group] :: Group -> HashMap Text Command
+ Calamity.Commands.Group: [$sel:commands:Group] :: Group -> HashMap Text (Command, AliasType)
- Calamity.Commands.Handler: CommandHandler :: HashMap Text Group -> HashMap Text Command -> CommandHandler
+ Calamity.Commands.Handler: CommandHandler :: HashMap Text (Group, AliasType) -> HashMap Text (Command, AliasType) -> CommandHandler
- Calamity.Commands.Handler: [$sel:commands:CommandHandler] :: CommandHandler -> HashMap Text Command
+ Calamity.Commands.Handler: [$sel:commands:CommandHandler] :: CommandHandler -> HashMap Text (Command, AliasType)
- Calamity.Commands.Handler: [$sel:groups:CommandHandler] :: CommandHandler -> HashMap Text Group
+ Calamity.Commands.Handler: [$sel:groups:CommandHandler] :: CommandHandler -> HashMap Text (Group, AliasType)
- Calamity.Commands.ParsePrefix: parsePrefix :: forall r_a79xk. MemberWithError ParsePrefix r_a79xk => Message -> Sem r_a79xk (Maybe (Text, Text))
+ Calamity.Commands.ParsePrefix: parsePrefix :: forall r_a79Nd. MemberWithError ParsePrefix r_a79Nd => Message -> Sem r_a79Nd (Maybe (Text, Text))
- Calamity.Gateway.Types: StatusUpdateData :: Maybe Integer -> Maybe Value -> Text -> Bool -> StatusUpdateData
+ Calamity.Gateway.Types: StatusUpdateData :: Maybe Integer -> Maybe Activity -> Text -> Bool -> StatusUpdateData
- Calamity.Gateway.Types: [$sel:game:StatusUpdateData] :: StatusUpdateData -> Maybe Value
+ Calamity.Gateway.Types: [$sel:game:StatusUpdateData] :: StatusUpdateData -> Maybe Activity
- Calamity.Internal.LocalWriter: llisten :: forall o_aEhH r_aExH a_XEhH. MemberWithError (LocalWriter o_aEhH) r_aExH => Sem r_aExH a_XEhH -> Sem r_aExH (o_aEhH, a_XEhH)
+ Calamity.Internal.LocalWriter: llisten :: forall o_aEF8 r_aEV8 a_XEF8. MemberWithError (LocalWriter o_aEF8) r_aEV8 => Sem r_aEV8 a_XEF8 -> Sem r_aEV8 (o_aEF8, a_XEF8)
- Calamity.Internal.LocalWriter: ltell :: forall o_aEhD r_aExF. MemberWithError (LocalWriter o_aEhD) r_aExF => o_aEhD -> Sem r_aExF ()
+ Calamity.Internal.LocalWriter: ltell :: forall o_aEF4 r_aEV6. MemberWithError (LocalWriter o_aEF4) r_aEV6 => o_aEF4 -> Sem r_aEV6 ()
- Calamity.Internal.RunIntoIO: intoIO :: forall p_aFBg r_aFBi r_aFGn. MemberWithError (IntoIO p_aFBg r_aFBi) r_aFGn => (p_aFBg -> Sem r_aFGn r_aFBi) -> Sem r_aFGn (p_aFBg -> IO (Maybe r_aFBi))
+ Calamity.Internal.RunIntoIO: intoIO :: forall p_aFYH r_aFYJ r_aG3O. MemberWithError (IntoIO p_aFYH r_aFYJ) r_aG3O => (p_aFYH -> Sem r_aG3O r_aFYJ) -> Sem r_aG3O (p_aFYH -> IO (Maybe r_aFYJ))
- Calamity.Metrics.Eff: addCounter :: forall r_aIny. MemberWithError MetricEff r_aIny => Int -> Counter -> Sem r_aIny Int
+ Calamity.Metrics.Eff: addCounter :: forall r_aIKY. MemberWithError MetricEff r_aIKY => Int -> Counter -> Sem r_aIKY Int
- Calamity.Metrics.Eff: modifyGauge :: forall r_aInB. MemberWithError MetricEff r_aInB => (Double -> Double) -> Gauge -> Sem r_aInB Double
+ Calamity.Metrics.Eff: modifyGauge :: forall r_aIL1. MemberWithError MetricEff r_aIL1 => (Double -> Double) -> Gauge -> Sem r_aIL1 Double
- Calamity.Metrics.Eff: observeHistogram :: forall r_aInE. MemberWithError MetricEff r_aInE => Double -> Histogram -> Sem r_aInE HistogramSample
+ Calamity.Metrics.Eff: observeHistogram :: forall r_aIL4. MemberWithError MetricEff r_aIL4 => Double -> Histogram -> Sem r_aIL4 HistogramSample
- Calamity.Metrics.Eff: registerCounter :: forall r_aIno. MemberWithError MetricEff r_aIno => Text -> [(Text, Text)] -> Sem r_aIno Counter
+ Calamity.Metrics.Eff: registerCounter :: forall r_aIKO. MemberWithError MetricEff r_aIKO => Text -> [(Text, Text)] -> Sem r_aIKO Counter
- Calamity.Metrics.Eff: registerGauge :: forall r_aInr. MemberWithError MetricEff r_aInr => Text -> [(Text, Text)] -> Sem r_aInr Gauge
+ Calamity.Metrics.Eff: registerGauge :: forall r_aIKR. MemberWithError MetricEff r_aIKR => Text -> [(Text, Text)] -> Sem r_aIKR Gauge
- Calamity.Metrics.Eff: registerHistogram :: forall r_aInu. MemberWithError MetricEff r_aInu => Text -> [(Text, Text)] -> [Double] -> Sem r_aInu Histogram
+ Calamity.Metrics.Eff: registerHistogram :: forall r_aIKU. MemberWithError MetricEff r_aIKU => Text -> [(Text, Text)] -> [Double] -> Sem r_aIKU Histogram

Files

ChangeLog.md view
@@ -1,5 +1,16 @@ # Changelog for Calamity +## 0.1.14.4++*2020-06-11*++* Added `activity` to construct Activities++* Added aliases for commands and groups, with new functions to create them+  (`commandA`, `groupA`, ...).++* The built in help command now shows aliases and checks.+ ## 0.1.14.3  *2020-06-10*
calamity.cabal view
@@ -4,10 +4,10 @@ -- -- see: https://github.com/sol/hpack ----- hash: 9dad5aee926a8bb786caf940edbfef86c22f29c508eefff636e965a4d10a01af+-- hash: f4c6fde3ae6f429b22eea33179e85d448bc6d821e6d0e78fdfa8bd664dc74dc5  name:           calamity-version:        0.1.14.3+version:        0.1.14.4 synopsis:       A library for writing discord bots description:    Please see the README on GitHub at <https://github.com/nitros12/calamity#readme> category:       Network, Web@@ -41,6 +41,7 @@       Calamity.Client.ShardManager       Calamity.Client.Types       Calamity.Commands+      Calamity.Commands.AliasType       Calamity.Commands.Check       Calamity.Commands.Command       Calamity.Commands.CommandUtils
+ src/Calamity/Commands/AliasType.hs view
@@ -0,0 +1,15 @@+-- | Named boolean for determining if something is an alias or not+module Calamity.Commands.AliasType+  ( AliasType (..),+  )+where++import GHC.Generics (Generic)+import TextShow (TextShow)+import qualified TextShow.Generic as TSG++data AliasType+  = Alias+  | Original+  deriving (Eq, Enum, Show, Generic)+  deriving (TextShow) via TSG.FromGeneric AliasType
src/Calamity/Commands/Command.hs view
@@ -9,6 +9,7 @@  import           Control.Lens              hiding ( (<.>), Context ) +import           Data.List.NonEmpty        ( NonEmpty ) import           Data.Text                 as S import           Data.Text.Lazy            as L @@ -16,10 +17,11 @@  import           TextShow import qualified TextShow.Generic          as TSG+import qualified Data.List.NonEmpty as NE  -- | A command data Command = forall a. Command-  { name     :: S.Text+  { names    :: NonEmpty S.Text   , parent   :: Maybe Group   , checks   :: [Check] -- TODO check checks on default help     -- ^ A list of checks that must pass for this command to be invoked@@ -37,7 +39,7 @@   }  data CommandS = CommandS-  { name   :: S.Text+  { names  :: NonEmpty S.Text   , params :: [S.Text]   , parent :: Maybe S.Text   , checks :: [S.Text]@@ -46,9 +48,9 @@   deriving ( TextShow ) via TSG.FromGeneric CommandS  instance Show Command where-  showsPrec d Command { name, params, parent, checks } = showsPrec d $ CommandS name params (parent ^? _Just . #name)+  showsPrec d Command { names, params, parent, checks } = showsPrec d $ CommandS names params (NE.head <$> parent ^? _Just . #names)     (checks ^.. traverse . #name)  instance TextShow Command where-  showbPrec d Command { name, params, parent, checks } = showbPrec d $ CommandS name params (parent ^? _Just . #name)+  showbPrec d Command { names, params, parent, checks } = showbPrec d $ CommandS names params (NE.head <$> parent ^? _Just . #names)     (checks ^.. traverse . #name)
src/Calamity/Commands/CommandUtils.hs view
@@ -26,6 +26,8 @@  import           Data.Foldable import           Data.Kind+import           Data.List.NonEmpty          ( NonEmpty(..) )+import qualified Data.List.NonEmpty          as NE import           Data.Maybe import           Data.Text                   as S import           Data.Text.Lazy              as L@@ -35,10 +37,10 @@ import qualified Polysemy.Fail               as P  groupPath :: Group -> [S.Text]-groupPath grp = maybe [] groupPath (grp ^. #parent) ++ [grp ^. #name]+groupPath Group { names, parent } = maybe [] groupPath parent ++ [NE.head names]  commandPath :: Command -> [S.Text]-commandPath Command { name, parent } = maybe [] groupPath parent ++ [name]+commandPath Command { names, parent } = maybe [] groupPath parent ++ [NE.head names]  commandParams :: Command -> L.Text commandParams Command { params } = L.fromStrict $ S.unwords params@@ -47,7 +49,7 @@ -- 'P.Sem' monad, build a command by transforming the Polysemy actions into IO -- actions. buildCommand' :: P.Member (P.Final IO) r-              => S.Text+              => NonEmpty S.Text               -> Maybe Group               -> [Check]               -> [S.Text]@@ -55,10 +57,10 @@               -> (Context -> P.Sem r (Either CommandError a))               -> ((Context, a) -> P.Sem (P.Fail ': r) ())               -> P.Sem r Command-buildCommand' name parent checks params help parser cb = do+buildCommand' names@(name :| _) parent checks params help parser cb = do   cb' <- buildCallback cb   parser' <- buildParser name parser-  pure $ Command name parent checks params help parser' cb'+  pure $ Command names parent checks params help parser' cb'  -- | Given the properties of a 'Command', a callback, and a type level list of -- the parameters, build a command by constructing a parser and wiring it up to@@ -78,14 +80,15 @@ -- @ buildCommand :: forall ps r.              (P.Member (P.Final IO) r, TypedCommandC ps r)-             => S.Text+             => NonEmpty S.Text              -> Maybe Group              -> [Check]              -> (Context -> L.Text)              -> (Context -> CommandForParsers ps r)              -> P.Sem r Command-buildCommand name parent checks help command = let (parser, cb) = buildTypedCommand @ps command-                                               in buildCommand' name parent checks (paramNames @ps @r) help parser cb+buildCommand names parent checks help command =+  let (parser, cb) = buildTypedCommand @ps command+  in buildCommand' names parent checks (paramNames @ps @r) help parser cb  -- | Given the name of the command the parser is for and a parser function in -- the 'P.Sem' monad, build a parser by transforming the Polysemy action into an@@ -112,7 +115,7 @@  -- | Given an invokation 'Context', run a command. This does not perform the command's checks. runCommand :: P.Member (P.Embed IO) r => Context -> Command -> P.Sem r (Either CommandError ())-runCommand ctx Command { name, parser, callback } = P.embed (parser ctx) >>= \case+runCommand ctx Command { names = name :| _, parser, callback } = P.embed (parser ctx) >>= \case   Left e   -> pure $ Left e   Right p' -> P.embed (callback (ctx, p')) <&> justToEither . (InvokeError name <$>) 
src/Calamity/Commands/Dsl.hs view
@@ -2,17 +2,22 @@  -- | A DSL for generating commands and groups module Calamity.Commands.Dsl-    ( command'-    , command+    ( command+    , command'+    , commandA+    , commandA'     , help     , requires     , requires'     , requiresPure     , group     , group'+    , groupA+    , groupA'     , DSLState     , raiseDSL ) where +import           Calamity.Commands.AliasType import           Calamity.Commands.Check import           Calamity.Commands.Command     hiding ( help ) import           Calamity.Commands.CommandUtils@@ -31,15 +36,19 @@ import qualified Polysemy.Tagged               as P import qualified Polysemy.Fixpoint             as P import qualified Polysemy.Reader               as P+import Data.List.NonEmpty (NonEmpty(..)) -type DSLState r = (LocalWriter (LH.HashMap S.Text Command) ':-                       LocalWriter (LH.HashMap S.Text Group) ':-                       P.Reader (Maybe Group) ':-                       P.Reader (Context -> L.Text) ':-                       P.Tagged "original-help" (P.Reader (Context -> L.Text)) ':-                       P.Reader [Check] ':-                       P.Reader CommandHandler ':-                       P.Fixpoint ': r)+type DSLState r =+  ( LocalWriter (LH.HashMap S.Text (Command, AliasType))+      ': LocalWriter (LH.HashMap S.Text (Group, AliasType))+      ': P.Reader (Maybe Group)+      ': P.Reader (Context -> L.Text)+      ': P.Tagged "original-help" (P.Reader (Context -> L.Text))+      ': P.Reader [Check]+      ': P.Reader CommandHandler+      ': P.Fixpoint+      ': r+  )  raiseDSL :: P.Sem r a -> P.Sem (DSLState r) a raiseDSL = P.raise . P.raise . P.raise . P.raise . P.raise . P.raise . P.raise . P.raise@@ -56,12 +65,28 @@   -> (Context -> P.Sem r (Either CommandError a))   -> ((Context, a) -> P.Sem (P.Fail ': r) ())   -> P.Sem (DSLState r) Command-command' name params parser cb = do+command' name params parser cb = commandA' name [] params parser cb++-- | Given the command name, aliases, and parameter names, @parser@ and @callback@ for a+-- command in the 'P.Sem' monad, build a command by transforming the Polysemy+-- actions into IO actions. Then register the command.+--+-- The parent group, checks, and command help are drawn from the reader context.+commandA'+  :: P.Member (P.Final IO) r+  => S.Text -- ^ name+  -> [S.Text] -- ^ aliases+  -> [S.Text] -- ^ parameter names+  -> (Context -> P.Sem r (Either CommandError a))+  -> ((Context, a) -> P.Sem (P.Fail ': r) ())+  -> P.Sem (DSLState r) Command+commandA' name aliases params parser cb = do   parent <- P.ask @(Maybe Group)   checks <- P.ask @[Check]   help' <- P.ask @(Context -> L.Text)-  cmd <- raiseDSL $ buildCommand' name parent checks params help' parser cb-  ltell $ LH.singleton name cmd+  cmd <- raiseDSL $ buildCommand' (name :| aliases) parent checks params help' parser cb+  ltell $ LH.singleton name (cmd, Original)+  ltell $ LH.fromList [(name, (cmd, Alias)) | name <- aliases]   pure cmd  -- | Given the name of a command and a callback, and a type level list of@@ -86,12 +111,38 @@         => S.Text         -> (Context -> CommandForParsers ps r)         -> P.Sem (DSLState r) Command-command name cmd = do+command name cmd = commandA @ps name [] cmd++-- | Given the name and aliases of a command and a callback, and a type level list of+-- the parameters, build and register a command.+--+-- ==== Examples+--+-- Building a command that bans a user by id.+--+-- @+-- 'commandA' \@\'['Calamity.Commands.Parser.Named' "user" ('Calamity.Types.Snowflake' 'Calamity.Types.Model.User'),+--                'Calamity.Commands.Parser.Named' "reason" ('Calamity.Commands.Parser.KleeneStarConcat' 'S.Text')]+--    "ban" [] $ \ctx uid r -> case (ctx 'Control.Lens.^.' #guild) of+--      'Just' guild -> do+--        'Control.Monad.void' . 'Calamity.HTTP.invoke' . 'Calamity.HTTP.reason' r $ 'Calamity.HTTP.Guild.CreateGuildBan' guild uid+--        'Control.Monad.void' $ 'Calamity.Types.Tellable.tell' ctx ("Banned user `" '<>' 'TextShow.showt' uid '<>' "` with reason: " '<>' r)+--      'Nothing' -> 'void' $ 'Calamity.Types.Tellable.tell' @'L.Text' ctx "Can only ban users from guilds."+-- @+commandA :: forall ps r.+        ( P.Member (P.Final IO) r,+          TypedCommandC ps r)+        => S.Text -- ^ name+        -> [S.Text] -- ^ aliases+        -> (Context -> CommandForParsers ps r)+        -> P.Sem (DSLState r) Command+commandA name aliases cmd = do   parent <- P.ask @(Maybe Group)   checks <- P.ask @[Check]   help' <- P.ask @(Context -> L.Text)-  cmd' <- raiseDSL $ buildCommand @ps name parent checks help' cmd-  ltell $ LH.singleton name cmd'+  cmd' <- raiseDSL $ buildCommand @ps (name :| aliases) parent checks help' cmd+  ltell $ LH.singleton name (cmd', Original)+  ltell $ LH.fromList [(name, (cmd', Alias)) | name <- aliases]   pure cmd'  -- | Set the help for any groups or commands registered inside the given action.@@ -135,17 +186,30 @@          => S.Text          -> P.Sem (DSLState r) a          -> P.Sem (DSLState r) a-group name m = mdo+group name m = groupA name [] m++-- | Construct a group with aliases and place any commands registered in the given action+-- into the new group.+--+-- This also resets the @help@ function back to it's original value, use+-- 'group'' if you don't want that (i.e. your help function is context aware).+groupA :: P.Member (P.Final IO) r+         => S.Text -- ^ name+         -> [S.Text] -- ^ aliases+         -> P.Sem (DSLState r) a+         -> P.Sem (DSLState r) a+groupA name aliases m = mdo   parent <- P.ask @(Maybe Group)   checks <- P.ask @[Check]   help'  <- P.ask @(Context -> L.Text)   origHelp <- fetchOrigHelp-  let group' = Group name parent commands children help' checks-  (children, (commands, res)) <- llisten @(LH.HashMap S.Text Group) $-                                 llisten @(LH.HashMap S.Text Command) $+  let group' = Group (name :| aliases) parent commands children help' checks+  (children, (commands, res)) <- llisten @(LH.HashMap S.Text (Group, AliasType)) $+                                 llisten @(LH.HashMap S.Text (Command, AliasType)) $                                  P.local @(Maybe Group) (const $ Just group') $                                  P.local @(Context -> L.Text) (const origHelp) m-  ltell $ LH.singleton name group'+  ltell $ LH.singleton name (group', Original)+  ltell $ LH.fromList [(name, (group', Alias)) | name <- aliases]   pure res  fetchOrigHelp :: P.Member (P.Tagged "original-help" (P.Reader (Context -> L.Text))) r => P.Sem r (Context -> L.Text)@@ -157,16 +221,29 @@ -- Unlike 'help' this doesn't reset the @help@ function back to it's original -- value. group' :: P.Member (P.Final IO) r-         => S.Text+         => S.Text -- ^ name          -> P.Sem (DSLState r) a          -> P.Sem (DSLState r) a-group' name m = mdo+group' name m = groupA' name [] m++-- | Construct a group with aliases and place any commands registered in the given action+-- into the new group.+--+-- Unlike 'help' this doesn't reset the @help@ function back to it's original+-- value.+groupA' :: P.Member (P.Final IO) r+         => S.Text -- ^ name+         -> [S.Text] -- ^ aliases+         -> P.Sem (DSLState r) a+         -> P.Sem (DSLState r) a+groupA' name aliases m = mdo   parent <- P.ask @(Maybe Group)   checks <- P.ask @[Check]   help'  <- P.ask @(Context -> L.Text)-  let group' = Group name parent commands children help' checks-  (children, (commands, res)) <- llisten @(LH.HashMap S.Text Group) $-                                 llisten @(LH.HashMap S.Text Command) $+  let group' = Group (name :| aliases) parent commands children help' checks+  (children, (commands, res)) <- llisten @(LH.HashMap S.Text (Group, AliasType)) $+                                 llisten @(LH.HashMap S.Text (Command, AliasType)) $                                  P.local @(Maybe Group) (const $ Just group') m-  ltell $ LH.singleton name group'+  ltell $ LH.singleton name (group', Original)+  ltell $ LH.fromList [(name, (group', Alias)) | name <- aliases]   pure res
src/Calamity/Commands/Group.hs view
@@ -2,6 +2,7 @@ module Calamity.Commands.Group     ( Group(..) ) where +import           Calamity.Commands.AliasType import           Calamity.Commands.Check import {-# SOURCE #-} Calamity.Commands.Command import {-# SOURCE #-} Calamity.Commands.Context@@ -16,14 +17,16 @@  import           TextShow import qualified TextShow.Generic          as TSG+import Data.List.NonEmpty (NonEmpty)+import qualified Data.List.NonEmpty as NE  -- | A group of commands data Group = Group-  { name     :: S.Text+  { names    :: NonEmpty S.Text   , parent   :: Maybe Group-  , commands :: LH.HashMap S.Text Command+  , commands :: LH.HashMap S.Text (Command, AliasType)     -- ^ Any child commands of this group-  , children :: LH.HashMap S.Text Group+  , children :: LH.HashMap S.Text (Group, AliasType)     -- ^ Any child groups of this group   , help     :: Context -> L.Text     -- ^ A function producing the \'help' for the group@@ -33,16 +36,16 @@   deriving ( Generic )  data GroupS = GroupS-  { name     :: S.Text+  { names    :: NonEmpty S.Text   , parent   :: Maybe S.Text-  , commands :: LH.HashMap S.Text Command-  , children :: LH.HashMap S.Text Group+  , commands :: LH.HashMap S.Text (Command, AliasType)+  , children :: LH.HashMap S.Text (Group, AliasType)   }   deriving ( Generic, Show )   deriving ( TextShow ) via TSG.FromGeneric GroupS  instance Show Group where-  showsPrec d Group { name, parent, commands, children } = showsPrec d $ GroupS name (parent ^? _Just . #name) commands children+  showsPrec d Group { names, parent, commands, children } = showsPrec d $ GroupS names (NE.head <$> parent ^? _Just . #names) commands children  instance TextShow Group where-  showbPrec d Group { name, parent, commands, children } = showbPrec d $ GroupS name (parent ^? _Just . #name) commands children+  showbPrec d Group { names, parent, commands, children } = showbPrec d $ GroupS names (NE.head <$> parent ^? _Just . #names) commands children
src/Calamity/Commands/Handler.hs view
@@ -2,6 +2,7 @@ module Calamity.Commands.Handler     ( CommandHandler(..) ) where +import           Calamity.Commands.AliasType import           Calamity.Commands.Command import           Calamity.Commands.Group @@ -14,9 +15,9 @@ import qualified TextShow.Generic          as TSG  data CommandHandler = CommandHandler-  { groups   :: LH.HashMap S.Text Group+  { groups   :: LH.HashMap S.Text (Group, AliasType)     -- ^ Top level groups-  , commands :: LH.HashMap S.Text Command+  , commands :: LH.HashMap S.Text (Command, AliasType)     -- ^ Top level commands   }   deriving ( Show, Generic )
src/Calamity/Commands/Help.hs view
@@ -4,6 +4,7 @@     , helpCommand ) where  import           Calamity.Client.Types+import           Calamity.Commands.AliasType import           Calamity.Commands.Check import           Calamity.Commands.Command import           Calamity.Commands.CommandUtils@@ -19,12 +20,15 @@ import           Control.Monad  import qualified Data.HashMap.Lazy              as LH+import           Data.List.NonEmpty             ( NonEmpty(..) )+import qualified Data.List.NonEmpty             as NE import qualified Data.Text                      as S import qualified Data.Text.Lazy                 as L  import qualified Polysemy                       as P import qualified Polysemy.Fail                  as P import qualified Polysemy.Reader                as P+import Data.Maybe (mapMaybe)  data CommandOrGroup   = Command' Command@@ -34,41 +38,68 @@ helpCommandHelp _ = "Show help for a command or group."  helpForCommand :: Context -> Command -> L.Text-helpForCommand ctx (cmd@Command { help }) = "```\nUsage: " <> prefix' <> path' <> " " <> params' <> "\n\n" <> help ctx <> "\n```"+helpForCommand ctx (cmd@Command { names, checks, help }) = "```\nUsage: " <> prefix' <> path' <> " " <> params' <> "\n" <>+                                                           aliasesFmt <>+                                                           checksFmt <>+                                                           help ctx <> "\n```"   where prefix' = ctx ^. #prefix-        path'   = L.fromStrict . S.unwords $ commandPath cmd+        path'   = L.unwords . map L.fromStrict $ commandPath cmd         params' = commandParams cmd+        aliases = map L.fromStrict $ NE.tail names+        checks' = map L.fromStrict . map (^. #name) $ checks+        aliasesFmt = if null aliases then "" else  "Aliases: " <> L.unwords aliases <> "\n"+        checksFmt = if null checks' then "" else "Checks: " <> L.unwords checks' <> "\n\n"  fmtCommandWithParams :: Command -> L.Text-fmtCommandWithParams cmd@Command { name } = L.fromStrict name <> " " <> commandParams cmd+fmtCommandWithParams cmd@Command { names } = formatWithAliases names <> " " <> commandParams cmd +formatWithAliases :: NonEmpty S.Text -> L.Text+formatWithAliases (name :| aliases) = L.fromStrict name <> aliasesFmt+  where+    aliasesFmt = case aliases of+      [] -> ""+      aliases' -> "[" <> L.intercalate "|" (map L.fromStrict aliases') <> "]"++onlyOriginals :: [(a, AliasType)] -> [a]+onlyOriginals = mapMaybe inner+  where inner (_, Alias) = Nothing+        inner (a, Original) = Just a+ helpForGroup :: Context -> Group -> L.Text-helpForGroup ctx grp = "```\nGroup: " <> path' <> "\n\n" <> (grp ^. #help) ctx <> "\n" <> groupsMsg <> commandsMsg <> "\n```"+helpForGroup ctx grp = "```\nGroup: " <> path' <> "\n" <>+                       aliasesFmt <>+                       checksFmt <>+                       (grp ^. #help) ctx <> "\n" <>+                       groupsMsg <> commandsMsg <> "\n```"   where path' = L.fromStrict . S.unwords $ groupPath grp-        groups = LH.keys $ grp ^. #children-        commands = LH.elems $ grp ^. #commands-        groupsMsg = if null groups then "" else "The following child groups exist:\n" <> L.fromStrict (S.unlines . map ("- " <>) $ groups)+        groups =  onlyOriginals . LH.elems $ grp ^. #children+        commands = onlyOriginals . LH.elems $ grp ^. #commands+        groupsFmt = map formatWithAliases (groups ^.. traverse . #names)+        groupsMsg = if null groups then "" else "The following child groups exist:\n" <> (L.unlines . map ("- " <>) $ groupsFmt)         commandsMsg = if null commands then "" else "\nThe following child commands exist:\n" <> (L.unlines . map ("- " <>) . map fmtCommandWithParams $ commands)+        aliases = map L.fromStrict . NE.tail $ grp ^. #names+        checks' = map L.fromStrict . map (^. #name) $ grp ^. #checks+        aliasesFmt = if null aliases then "" else  "Aliases: " <> L.unwords aliases <> "\n"+        checksFmt = if null checks' then "" else "Checks: " <> L.unwords checks' <> "\n\n"  rootHelp :: CommandHandler -> L.Text rootHelp handler = "```\n" <> groupsMsg <> commandsMsg <> "\n```"-  where groups = LH.keys $ handler ^. #groups-        commands = LH.elems $ handler ^. #commands-        groupsMsg = if null groups then "" else "The following groups exist:\n" <> L.fromStrict (S.unlines . map ("- " <>) $ groups)+  where groups =  onlyOriginals . LH.elems $ handler ^. #groups+        commands = onlyOriginals . LH.elems $ handler ^. #commands+        groupsFmt = map formatWithAliases (groups ^.. traverse . #names)+        groupsMsg = if null groups then "" else "The following groups exist:\n" <> (L.unlines . map ("- " <>) $ groupsFmt)         commandsMsg = if null commands then "" else "\nThe following commands exist:\n" <> (L.unlines . map ("- " <>) . map fmtCommandWithParams $ commands) --- TODO: process checks- helpCommandCallback :: BotC r => CommandHandler -> Context -> [S.Text] -> P.Sem (P.Fail ': r) () helpCommandCallback handler ctx path = do   case findCommandOrGroup handler path of-    Just (Command' cmd@Command { name }) ->-      void $ tell @L.Text ctx $ "Help for command `" <> L.fromStrict name <> "`: \n" <> helpForCommand ctx cmd-    Just (Group' grp@Group { name } remainingPath) ->+    Just (Command' cmd@Command { names }) ->+      void $ tell @L.Text ctx $ "Help for command `" <> L.fromStrict (NE.head names) <> "`: \n" <> helpForCommand ctx cmd+    Just (Group' grp@Group { names } remainingPath) ->       let failedMsg = if null remainingPath             then ""-            else "No command or group with the path: `" <> L.fromStrict (S.unwords path) <> "` exists for the group: `" <> L.fromStrict name <> "`\n"-      in void $ tell @L.Text ctx $ failedMsg <> "Help for group `" <> L.fromStrict name <> "`: \n" <> helpForGroup ctx grp+            else "No command or group with the path: `" <> L.fromStrict (S.unwords path) <> "` exists for the group: `" <> L.fromStrict (NE.head names) <> "`\n"+      in void $ tell @L.Text ctx $ failedMsg <> "Help for group `" <> L.fromStrict (NE.head names) <> "`: \n" <> helpForGroup ctx grp     Nothing -> let failedMsg = if null path                      then ""                      else "No command or group with the path: `" <> L.fromStrict (S.unwords path) <> "` was found.\n"@@ -78,7 +109,7 @@ -- construct a help command that will provide help for all the commands and -- groups in the passed 'CommandHandler'. helpCommand' :: BotC r => CommandHandler -> Maybe Group -> [Check] -> P.Sem r Command-helpCommand' handler parent checks = buildCommand @'[[S.Text]] "help" parent checks helpCommandHelp+helpCommand' handler parent checks = buildCommand @'[[S.Text]] ("help" :| []) parent checks helpCommandHelp   (helpCommandCallback handler)  -- | Create and register the default help command for all the commands@@ -89,16 +120,18 @@   parent <- P.ask @(Maybe Group)   checks <- P.ask @[Check]   cmd <- raiseDSL $ helpCommand' handler parent checks-  ltell $ LH.singleton "help" cmd+  ltell $ LH.singleton "help" (cmd, Original)   pure cmd  findCommandOrGroup :: CommandHandler -> [S.Text] -> Maybe CommandOrGroup findCommandOrGroup handler path = go (handler ^. #commands, handler ^. #groups) path-  where go :: (LH.HashMap S.Text Command, LH.HashMap S.Text Group) -> [S.Text] -> Maybe CommandOrGroup+  where go :: (LH.HashMap S.Text (Command, AliasType), LH.HashMap S.Text (Group, AliasType))+           -> [S.Text]+           -> Maybe CommandOrGroup         go (commands, groups) (x : xs) =           case LH.lookup x commands of-            Just cmd -> Just (Command' cmd)-            Nothing  -> case LH.lookup x groups of-              Just group -> go (group ^. #commands, group ^. #children) xs <|> Just (Group' group xs)-              Nothing    -> Nothing+            Just (cmd, _) -> Just (Command' cmd)+            Nothing       -> case LH.lookup x groups of+              Just (group, _) -> go (group ^. #commands, group ^. #children) xs <|> Just (Group' group xs)+              Nothing         -> Nothing         go _ [] = Nothing
src/Calamity/Commands/Utils.hs view
@@ -9,6 +9,7 @@ import           Calamity.Metrics.Eff import           Calamity.Client.Client import           Calamity.Client.Types+import           Calamity.Commands.AliasType import           Calamity.Commands.Command import           Calamity.Commands.CommandUtils import           Calamity.Commands.Context@@ -82,15 +83,17 @@   let handler = CommandHandler groups cmds   pure (handler, a) -  where inner :: CommandHandler -> P.Sem (DSLState r) a -> P.Sem (P.Fixpoint ': r) (LH.HashMap S.Text Group, (LH.HashMap S.Text Command, a))+  where inner :: CommandHandler -> P.Sem (DSLState r) a+              -> P.Sem (P.Fixpoint ': r) (LH.HashMap S.Text (Group, AliasType),+                                          (LH.HashMap S.Text (Command, AliasType), a))         inner h =           P.runReader h .           P.runReader [] .           P.runReader defaultHelp . P.untag @"original-help" .           P.runReader defaultHelp .           P.runReader Nothing .-          runLocalWriter @(LH.HashMap S.Text Group) .-          runLocalWriter @(LH.HashMap S.Text Command)+          runLocalWriter @(LH.HashMap S.Text (Group, AliasType)) .+          runLocalWriter @(LH.HashMap S.Text (Command, AliasType))         defaultHelp = (const "This command or group has no help.")  @@ -125,8 +128,8 @@       (((, xs) <$> attachInitial (LH.lookup (L.toStrict x) (g ^. #commands)))        <> (attachInitial (LH.lookup (L.toStrict x) (g ^. #children)) >>= goG (nextWord xs))) -    attachInitial :: Maybe a -> Either [L.Text] a-    attachInitial (Just a) = Right a+    attachInitial :: Maybe (a, b) -> Either [L.Text] a+    attachInitial (Just (a, _)) = Right a     attachInitial Nothing = Left []      attachSoFar :: L.Text -> Either [L.Text] a -> Either [L.Text] a
src/Calamity/Gateway/Types.hs view
@@ -22,6 +22,7 @@ import           Calamity.Types.LogEff import           Calamity.Types.Model.Guild.Guild import           Calamity.Types.Model.Voice+import           Calamity.Types.Model.Presence.Activity import           Calamity.Types.Snowflake  import           Control.Concurrent.Async@@ -211,7 +212,7 @@  data StatusUpdateData = StatusUpdateData   { since  :: Maybe Integer-  , game   :: Maybe Value+  , game   :: Maybe Activity   , status :: Text   , afk    :: Bool   }
src/Calamity/Types/Model/Presence/Activity.hs view
@@ -1,6 +1,7 @@ -- | User activities module Calamity.Types.Model.Presence.Activity     ( Activity(..)+    , activity     , ActivityType(..)     , ActivityTimestamps(..)     , ActivityParty(..)@@ -54,6 +55,24 @@   deriving ( Eq, Show, Generic )   deriving ( TextShow ) via TSG.FromGeneric Activity   deriving ( ToJSON, FromJSON ) via CalamityJSON Activity++-- | Make an 'Activity' with all optional fields set to Nothing+activity :: Text -> ActivityType -> Activity+activity name type_ =+  Activity+    { name = name,+      type_ = type_,+      url = Nothing,+      timestamps = Nothing,+      applicationID = Nothing,+      details = Nothing,+      state = Nothing,+      party = Nothing,+      assets = Nothing,+      secrets = Nothing,+      instance_ = Nothing,+      flags = Nothing+    }  data ActivityTimestamps = ActivityTimestamps   { start :: Maybe UnixTimestamp