packages feed

calamity 0.1.9.2 → 0.1.9.3

raw patch · 15 files changed

+195/−17 lines, 15 filesPVP: major bump suggested

API removals or changes: PVP suggests a major version bump

API changes (from Hackage documentation)

- Calamity.Commands.Parser: instance forall k (a :: k) (r :: [(* -> *) -> * -> *]). Data.Typeable.Internal.Typeable (Calamity.Types.Snowflake.Snowflake a) => Calamity.Commands.Parser.Parser (Calamity.Types.Snowflake.Snowflake a) r
- Calamity.Types.Snowflake: instance forall k (a :: k). Calamity.Types.Snowflake.HasID a (Calamity.Types.Snowflake.Snowflake a)
- Calamity.Types.Snowflake: instance forall k (b :: k) c (field :: GHC.Types.Symbol) a. (Calamity.Types.Snowflake.HasID b c, Data.Generics.Product.Fields.HasField' field a c) => Calamity.Types.Snowflake.HasID b (Calamity.Types.Snowflake.HasIDField field a)
- Calamity.Types.Snowflake: instance forall k (t :: k). (Data.Typeable.Internal.Typeable t, Data.Typeable.Internal.Typeable k) => Data.Data.Data (Calamity.Types.Snowflake.Snowflake t)
- Calamity.Types.Snowflake: instance forall k (t :: k). Control.DeepSeq.NFData (Calamity.Types.Snowflake.Snowflake t)
- Calamity.Types.Snowflake: instance forall k (t :: k). Data.Aeson.Types.FromJSON.FromJSON (Calamity.Types.Snowflake.Snowflake t)
- Calamity.Types.Snowflake: instance forall k (t :: k). Data.Aeson.Types.ToJSON.ToJSON (Calamity.Types.Snowflake.Snowflake t)
- Calamity.Types.Snowflake: instance forall k (t :: k). Data.Aeson.Types.ToJSON.ToJSONKey (Calamity.Types.Snowflake.Snowflake t)
- Calamity.Types.Snowflake: instance forall k (t :: k). Data.Hashable.Class.Hashable (Calamity.Types.Snowflake.Snowflake t)
- Calamity.Types.Snowflake: instance forall k (t :: k). Data.Vector.Generic.Base.Vector Data.Vector.Unboxed.Base.Vector (Calamity.Types.Snowflake.Snowflake t)
- Calamity.Types.Snowflake: instance forall k (t :: k). Data.Vector.Generic.Mutable.Base.MVector Data.Vector.Unboxed.Base.MVector (Calamity.Types.Snowflake.Snowflake t)
- Calamity.Types.Snowflake: instance forall k (t :: k). Data.Vector.Unboxed.Base.Unbox (Calamity.Types.Snowflake.Snowflake t)
- Calamity.Types.Snowflake: instance forall k (t :: k). GHC.Classes.Eq (Calamity.Types.Snowflake.Snowflake t)
- Calamity.Types.Snowflake: instance forall k (t :: k). GHC.Classes.Ord (Calamity.Types.Snowflake.Snowflake t)
- Calamity.Types.Snowflake: instance forall k (t :: k). GHC.Generics.Generic (Calamity.Types.Snowflake.Snowflake t)
- Calamity.Types.Snowflake: instance forall k (t :: k). GHC.Show.Show (Calamity.Types.Snowflake.Snowflake t)
- Calamity.Types.Snowflake: instance forall k (t :: k). TextShow.Classes.TextShow (Calamity.Types.Snowflake.Snowflake t)
- Calamity.Types.Snowflake: instance forall k1 k2 (c :: k1) d (field :: GHC.Types.Symbol) a (b :: k2). (Calamity.Types.Snowflake.HasID c d, Data.Generics.Product.Fields.HasField' field a d) => Calamity.Types.Snowflake.HasID b (Calamity.Types.Snowflake.HasIDFieldCoerce field a c)
+ Calamity.Commands.Dsl: group' :: Member (Final IO) r => Text -> Sem (DSLState r) a -> Sem (DSLState r) a
+ Calamity.Commands.Parser: instance Data.Typeable.Internal.Typeable (Calamity.Types.Snowflake.Snowflake a) => Calamity.Commands.Parser.Parser (Calamity.Types.Snowflake.Snowflake a) r
+ Calamity.Types.Snowflake: instance (Calamity.Types.Snowflake.HasID b c, Data.Generics.Product.Fields.HasField' field a c) => Calamity.Types.Snowflake.HasID b (Calamity.Types.Snowflake.HasIDField field a)
+ Calamity.Types.Snowflake: instance (Calamity.Types.Snowflake.HasID c d, Data.Generics.Product.Fields.HasField' field a d) => Calamity.Types.Snowflake.HasID b (Calamity.Types.Snowflake.HasIDFieldCoerce field a c)
+ Calamity.Types.Snowflake: instance Calamity.Types.Snowflake.HasID a (Calamity.Types.Snowflake.Snowflake a)
+ Calamity.Types.Snowflake: instance Control.DeepSeq.NFData (Calamity.Types.Snowflake.Snowflake t)
+ Calamity.Types.Snowflake: instance Data.Aeson.Types.FromJSON.FromJSON (Calamity.Types.Snowflake.Snowflake t)
+ Calamity.Types.Snowflake: instance Data.Aeson.Types.ToJSON.ToJSON (Calamity.Types.Snowflake.Snowflake t)
+ Calamity.Types.Snowflake: instance Data.Aeson.Types.ToJSON.ToJSONKey (Calamity.Types.Snowflake.Snowflake t)
+ Calamity.Types.Snowflake: instance Data.Data.Data t => Data.Data.Data (Calamity.Types.Snowflake.Snowflake t)
+ Calamity.Types.Snowflake: instance Data.Hashable.Class.Hashable (Calamity.Types.Snowflake.Snowflake t)
+ Calamity.Types.Snowflake: instance Data.Vector.Generic.Base.Vector Data.Vector.Unboxed.Base.Vector (Calamity.Types.Snowflake.Snowflake t)
+ Calamity.Types.Snowflake: instance Data.Vector.Generic.Mutable.Base.MVector Data.Vector.Unboxed.Base.MVector (Calamity.Types.Snowflake.Snowflake t)
+ Calamity.Types.Snowflake: instance Data.Vector.Unboxed.Base.Unbox (Calamity.Types.Snowflake.Snowflake t)
+ Calamity.Types.Snowflake: instance GHC.Classes.Eq (Calamity.Types.Snowflake.Snowflake t)
+ Calamity.Types.Snowflake: instance GHC.Classes.Ord (Calamity.Types.Snowflake.Snowflake t)
+ Calamity.Types.Snowflake: instance GHC.Generics.Generic (Calamity.Types.Snowflake.Snowflake t)
+ Calamity.Types.Snowflake: instance GHC.Show.Show (Calamity.Types.Snowflake.Snowflake t)
+ Calamity.Types.Snowflake: instance TextShow.Classes.TextShow (Calamity.Types.Snowflake.Snowflake t)
- Calamity.Cache.Eff: delDM :: forall r_a9JOE. MemberWithError CacheEff r_a9JOE => Snowflake DMChannel -> Sem r_a9JOE ()
+ Calamity.Cache.Eff: delDM :: forall r_a9Jrm. MemberWithError CacheEff r_a9Jrm => Snowflake DMChannel -> Sem r_a9Jrm ()
- Calamity.Cache.Eff: delGuild :: forall r_a9JOx. MemberWithError CacheEff r_a9JOx => Snowflake Guild -> Sem r_a9JOx ()
+ Calamity.Cache.Eff: delGuild :: forall r_a9Jrf. MemberWithError CacheEff r_a9Jrf => Snowflake Guild -> Sem r_a9Jrf ()
- Calamity.Cache.Eff: delMessage :: forall r_a9JOZ. MemberWithError CacheEff r_a9JOZ => Snowflake Message -> Sem r_a9JOZ ()
+ Calamity.Cache.Eff: delMessage :: forall r_a9JrH. MemberWithError CacheEff r_a9JrH => Snowflake Message -> Sem r_a9JrH ()
- Calamity.Cache.Eff: delUnavailableGuild :: forall r_a9JOS. MemberWithError CacheEff r_a9JOS => Snowflake Guild -> Sem r_a9JOS ()
+ Calamity.Cache.Eff: delUnavailableGuild :: forall r_a9JrA. MemberWithError CacheEff r_a9JrA => Snowflake Guild -> Sem r_a9JrA ()
- Calamity.Cache.Eff: delUser :: forall r_a9JOL. MemberWithError CacheEff r_a9JOL => Snowflake User -> Sem r_a9JOL ()
+ Calamity.Cache.Eff: delUser :: forall r_a9Jrt. MemberWithError CacheEff r_a9Jrt => Snowflake User -> Sem r_a9Jrt ()
- Calamity.Cache.Eff: getBotUser :: forall r_a9JOr. MemberWithError CacheEff r_a9JOr => Sem r_a9JOr (Maybe User)
+ Calamity.Cache.Eff: getBotUser :: forall r_a9Jr9. MemberWithError CacheEff r_a9Jr9 => Sem r_a9Jr9 (Maybe User)
- Calamity.Cache.Eff: getDM :: forall r_a9JOB. MemberWithError CacheEff r_a9JOB => Snowflake DMChannel -> Sem r_a9JOB (Maybe DMChannel)
+ Calamity.Cache.Eff: getDM :: forall r_a9Jrj. MemberWithError CacheEff r_a9Jrj => Snowflake DMChannel -> Sem r_a9Jrj (Maybe DMChannel)
- Calamity.Cache.Eff: getDMs :: forall r_a9JOD. MemberWithError CacheEff r_a9JOD => Sem r_a9JOD [DMChannel]
+ Calamity.Cache.Eff: getDMs :: forall r_a9Jrl. MemberWithError CacheEff r_a9Jrl => Sem r_a9Jrl [DMChannel]
- Calamity.Cache.Eff: getGuild :: forall r_a9JOu. MemberWithError CacheEff r_a9JOu => Snowflake Guild -> Sem r_a9JOu (Maybe Guild)
+ Calamity.Cache.Eff: getGuild :: forall r_a9Jrc. MemberWithError CacheEff r_a9Jrc => Snowflake Guild -> Sem r_a9Jrc (Maybe Guild)
- Calamity.Cache.Eff: getGuilds :: forall r_a9JOw. MemberWithError CacheEff r_a9JOw => Sem r_a9JOw [Guild]
+ Calamity.Cache.Eff: getGuilds :: forall r_a9Jre. MemberWithError CacheEff r_a9Jre => Sem r_a9Jre [Guild]
- Calamity.Cache.Eff: getMessage :: forall r_a9JOW. MemberWithError CacheEff r_a9JOW => Snowflake Message -> Sem r_a9JOW (Maybe Message)
+ Calamity.Cache.Eff: getMessage :: forall r_a9JrE. MemberWithError CacheEff r_a9JrE => Snowflake Message -> Sem r_a9JrE (Maybe Message)
- Calamity.Cache.Eff: getMessages :: forall r_a9JOY. MemberWithError CacheEff r_a9JOY => Sem r_a9JOY [Message]
+ Calamity.Cache.Eff: getMessages :: forall r_a9JrG. MemberWithError CacheEff r_a9JrG => Sem r_a9JrG [Message]
- Calamity.Cache.Eff: getUnavailableGuilds :: forall r_a9JOR. MemberWithError CacheEff r_a9JOR => Sem r_a9JOR [Snowflake Guild]
+ Calamity.Cache.Eff: getUnavailableGuilds :: forall r_a9Jrz. MemberWithError CacheEff r_a9Jrz => Sem r_a9Jrz [Snowflake Guild]
- Calamity.Cache.Eff: getUser :: forall r_a9JOI. MemberWithError CacheEff r_a9JOI => Snowflake User -> Sem r_a9JOI (Maybe User)
+ Calamity.Cache.Eff: getUser :: forall r_a9Jrq. MemberWithError CacheEff r_a9Jrq => Snowflake User -> Sem r_a9Jrq (Maybe User)
- Calamity.Cache.Eff: getUsers :: forall r_a9JOK. MemberWithError CacheEff r_a9JOK => Sem r_a9JOK [User]
+ Calamity.Cache.Eff: getUsers :: forall r_a9Jrs. MemberWithError CacheEff r_a9Jrs => Sem r_a9Jrs [User]
- Calamity.Cache.Eff: isUnavailableGuild :: forall r_a9JOP. MemberWithError CacheEff r_a9JOP => Snowflake Guild -> Sem r_a9JOP Bool
+ Calamity.Cache.Eff: isUnavailableGuild :: forall r_a9Jrx. MemberWithError CacheEff r_a9Jrx => Snowflake Guild -> Sem r_a9Jrx Bool
- Calamity.Cache.Eff: setBotUser :: forall r_a9JOp. MemberWithError CacheEff r_a9JOp => User -> Sem r_a9JOp ()
+ Calamity.Cache.Eff: setBotUser :: forall r_a9Jr7. MemberWithError CacheEff r_a9Jr7 => User -> Sem r_a9Jr7 ()
- Calamity.Cache.Eff: setDM :: forall r_a9JOz. MemberWithError CacheEff r_a9JOz => DMChannel -> Sem r_a9JOz ()
+ Calamity.Cache.Eff: setDM :: forall r_a9Jrh. MemberWithError CacheEff r_a9Jrh => DMChannel -> Sem r_a9Jrh ()
- Calamity.Cache.Eff: setGuild :: forall r_a9JOs. MemberWithError CacheEff r_a9JOs => Guild -> Sem r_a9JOs ()
+ Calamity.Cache.Eff: setGuild :: forall r_a9Jra. MemberWithError CacheEff r_a9Jra => Guild -> Sem r_a9Jra ()
- Calamity.Cache.Eff: setMessage :: forall r_a9JOU. MemberWithError CacheEff r_a9JOU => Message -> Sem r_a9JOU ()
+ Calamity.Cache.Eff: setMessage :: forall r_a9JrC. MemberWithError CacheEff r_a9JrC => Message -> Sem r_a9JrC ()
- Calamity.Cache.Eff: setUnavailableGuild :: forall r_a9JON. MemberWithError CacheEff r_a9JON => Snowflake Guild -> Sem r_a9JON ()
+ Calamity.Cache.Eff: setUnavailableGuild :: forall r_a9Jrv. MemberWithError CacheEff r_a9Jrv => Snowflake Guild -> Sem r_a9Jrv ()
- Calamity.Cache.Eff: setUser :: forall r_a9JOG. MemberWithError CacheEff r_a9JOG => User -> Sem r_a9JOG ()
+ Calamity.Cache.Eff: setUser :: forall r_a9Jro. MemberWithError CacheEff r_a9Jro => User -> Sem r_a9Jro ()
- Calamity.Commands.Dsl: type DSLState r = (LocalWriter (HashMap Text Command) : LocalWriter (HashMap Text Group) : Reader (Maybe Group) : Reader (Context -> Text) : Reader [Check] : Reader CommandHandler : Fixpoint : r)
+ 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.ParsePrefix: parsePrefix :: forall r_a6EVW. MemberWithError ParsePrefix r_a6EVW => Message -> Sem r_a6EVW (Maybe (Text, Text))
+ Calamity.Commands.ParsePrefix: parsePrefix :: forall r_a6EUN. MemberWithError ParsePrefix r_a6EUN => Message -> Sem r_a6EUN (Maybe (Text, Text))
- Calamity.Commands.Parser: data KleeneConcat a
+ Calamity.Commands.Parser: data KleeneConcat (a :: Type)
- Calamity.Commands.Parser: data Named (s :: Symbol) a
+ Calamity.Commands.Parser: data Named (s :: Symbol) (a :: Type)
- Calamity.Internal.LocalWriter: llisten :: forall o_aC49 r_aCgk a_XC49. MemberWithError (LocalWriter o_aC49) r_aCgk => Sem r_aCgk a_XC49 -> Sem r_aCgk (o_aC49, a_XC49)
+ Calamity.Internal.LocalWriter: llisten :: forall o_aC3M r_aCfX a_XC3M. MemberWithError (LocalWriter o_aC3M) r_aCfX => Sem r_aCfX a_XC3M -> Sem r_aCfX (o_aC3M, a_XC3M)
- Calamity.Internal.LocalWriter: ltell :: forall o_aC45 r_aCgi. MemberWithError (LocalWriter o_aC45) r_aCgi => o_aC45 -> Sem r_aCgi ()
+ Calamity.Internal.LocalWriter: ltell :: forall o_aC3I r_aCfV. MemberWithError (LocalWriter o_aC3I) r_aCfV => o_aC3I -> Sem r_aCfV ()
- Calamity.Internal.RunIntoIO: intoIO :: forall p_aDGc r_aDGe r_aDLo. MemberWithError (IntoIO p_aDGc r_aDGe) r_aDLo => (p_aDGc -> Sem r_aDLo r_aDGe) -> Sem r_aDLo (p_aDGc -> IO (Maybe r_aDGe))
+ Calamity.Internal.RunIntoIO: intoIO :: forall p_aDFP r_aDFR r_aDL1. MemberWithError (IntoIO p_aDFP r_aDFR) r_aDL1 => (p_aDFP -> Sem r_aDL1 r_aDFR) -> Sem r_aDL1 (p_aDFP -> IO (Maybe r_aDFR))
- Calamity.Metrics.Eff: addCounter :: forall r_aGid. MemberWithError MetricEff r_aGid => Int -> Counter -> Sem r_aGid Int
+ Calamity.Metrics.Eff: addCounter :: forall r_aGhQ. MemberWithError MetricEff r_aGhQ => Int -> Counter -> Sem r_aGhQ Int
- Calamity.Metrics.Eff: modifyGauge :: forall r_aGig. MemberWithError MetricEff r_aGig => (Double -> Double) -> Gauge -> Sem r_aGig Double
+ Calamity.Metrics.Eff: modifyGauge :: forall r_aGhT. MemberWithError MetricEff r_aGhT => (Double -> Double) -> Gauge -> Sem r_aGhT Double
- Calamity.Metrics.Eff: observeHistogram :: forall r_aGij. MemberWithError MetricEff r_aGij => Double -> Histogram -> Sem r_aGij HistogramSample
+ Calamity.Metrics.Eff: observeHistogram :: forall r_aGhW. MemberWithError MetricEff r_aGhW => Double -> Histogram -> Sem r_aGhW HistogramSample
- Calamity.Metrics.Eff: registerCounter :: forall r_aGi3. MemberWithError MetricEff r_aGi3 => Text -> [(Text, Text)] -> Sem r_aGi3 Counter
+ Calamity.Metrics.Eff: registerCounter :: forall r_aGhG. MemberWithError MetricEff r_aGhG => Text -> [(Text, Text)] -> Sem r_aGhG Counter
- Calamity.Metrics.Eff: registerGauge :: forall r_aGi6. MemberWithError MetricEff r_aGi6 => Text -> [(Text, Text)] -> Sem r_aGi6 Gauge
+ Calamity.Metrics.Eff: registerGauge :: forall r_aGhJ. MemberWithError MetricEff r_aGhJ => Text -> [(Text, Text)] -> Sem r_aGhJ Gauge
- Calamity.Metrics.Eff: registerHistogram :: forall r_aGi9. MemberWithError MetricEff r_aGi9 => Text -> [(Text, Text)] -> [Double] -> Sem r_aGi9 Histogram
+ Calamity.Metrics.Eff: registerHistogram :: forall r_aGhM. MemberWithError MetricEff r_aGhM => Text -> [(Text, Text)] -> [Double] -> Sem r_aGhM Histogram
- Calamity.Types.Snowflake: Snowflake :: Word64 -> Snowflake t
+ Calamity.Types.Snowflake: Snowflake :: Word64 -> Snowflake (t :: Type)
- Calamity.Types.Snowflake: [$sel:fromSnowflake:Snowflake] :: Snowflake t -> Word64
+ Calamity.Types.Snowflake: [$sel:fromSnowflake:Snowflake] :: Snowflake (t :: Type) -> Word64
- Calamity.Types.Snowflake: newtype Snowflake t
+ Calamity.Types.Snowflake: newtype Snowflake (t :: Type)

Files

README.md view
@@ -110,6 +110,11 @@   void . P.runFinal . P.embedToFinal . runCounterAtomic . runCacheInMemory . runMetricsPrometheusIO . useConstantPrefix "!"     $ runBotIO (BotToken token) $ do     addCommands $ do+      helpCommand+      command @'[User] "utest" $ \ctx u -> do+        void $ tellt ctx $ "got user: " <> showtl u+      command @'[Named "u" User, Named "u1" User] "utest2" $ \ctx u u1 -> do+        void $ tellt ctx $ "got user: " <> showtl u <> "\nand: " <> showtl u1       command @'[L.Text, Snowflake User] "test" $ \ctx something aUser -> do         info $ "something = " <> showt something <> ", aUser = " <> showt aUser       command @'[] "hello" $ \ctx -> do@@ -123,10 +128,6 @@         group "say" $ do           command @'[KleeneConcat L.Text] "this" $ \ctx msg -> do             void $ tellt ctx msg-      command @'[User] "utest" $ \ctx u -> do-        void $ tellt ctx $ "got user: " <> showtl u-      command @'[Named "u" User, Named "u1" User] "utest2" $ \ctx u u1 -> do-        void $ tellt ctx $ "got user: " <> showtl u <> "\nand: " <> showtl u1       command @'[Snowflake Emoji] "etest" $ \ctx e -> do         void $ tellt ctx $ "got emoji: " <> showtl e       command @'[] "explode" $ \ctx -> do
calamity.cabal view
@@ -4,10 +4,10 @@ -- -- see: https://github.com/sol/hpack ----- hash: ab08a364b5d3e67e015dfa8b1e5a96b8255ea898856a72811e1d1462bb984147+-- hash: f88c96cab00a86482d236a3a5f86d11d093b8179d8390725eabf46a12e054881  name:           calamity-version:        0.1.9.2+version:        0.1.9.3 synopsis:       A library for writing discord bots description:    Please see the README on GitHub at <https://github.com/nitros12/calamity#readme> category:       Network, Web
src/Calamity/Client/Client.hs view
@@ -119,7 +119,7 @@ -- -- @ -- 'react' @(\''CustomEvt' "my-event" ('Data.Text.Text', 'Message')) $ \(s, m) ->---    'void' $ 'Calamity.Tellable.tell' @'Data.Text.Text' m ("Somebody told me to tell you about: " '<>' s)+--    'void' $ 'Calamity.Types.Tellable.tell' @'Data.Text.Text' m ("Somebody told me to tell you about: " '<>' s) -- @ -- -- ==== Notes
src/Calamity/Commands.hs view
@@ -7,7 +7,10 @@     , module Calamity.Commands.Utils     , module Calamity.Commands.ParsePrefix     , module Calamity.Commands.Parser-    , module Calamity.Commands.Help ) where+    , module Calamity.Commands.Help+    -- * Commands+    -- $commandDocs+    ) where  import           Calamity.Commands.Dsl import           Calamity.Commands.Error@@ -16,3 +19,33 @@ import           Calamity.Commands.ParsePrefix import           Calamity.Commands.Parser import           Calamity.Commands.Utils++-- $commandDocs+--+-- This module provides abstractions for writing declarative commands, that+-- support grouping, pre-invokation checks, and automatic argument parsing by+-- using a type level list of parameter types.+--+-- A DSL is provided in 'Calamity.Commands.Dsl' for constructing commands+-- declaratively.+--+-- You can implement 'Parser' for your own types to allow them to be used in the+-- parameter list of commands.+--+-- A default help command is provided in 'Calamity.Commands.Help' which can be+-- added just by using 'helpCommand' inside the command declaration DSL.+--+-- ==== Examples+--+-- An example of using commands:+--+-- @+-- 'addCommands' $ do+--   'helpCommand'+--   'command' \@\'['Calamity.Types.Model.User.User'] "utest" $ \ctx u \-\> do+--     'Control.Monad.void' $ 'Calamity.Tellable.tell' ctx $ "got user: " '<>' 'TextShow.showtl' u+--   'group' "admin" $ do+--     'command' \@'[] "bye" $ \ctx -> do+--       'Control.Monad.void' $ 'Calamity.Types.Tellable.tell' ctx "bye!"+--       'Calamity.Client.stopBot'+-- @
src/Calamity/Commands/Check.hs view
@@ -21,20 +21,31 @@  import qualified Polysemy                    as P +-- | A check for a command.+--+-- Every check for a command must return Nothing for the command to be run. data Check = MkCheck   { name     :: S.Text+    -- ^ The name of the check.   , callback :: Context -> IO (Maybe L.Text)+    -- ^ The callback for the check, returns Nothing if it passes, otherwise+    -- returns the reason for it not passing.   }   deriving ( Generic ) +-- | Given the name of a check and a callback in the 'P.Sem' monad, build a+-- check by transforming the Polysemy action into an IO action. buildCheck :: P.Member (P.Final IO) r => S.Text -> (Context -> P.Sem r (Maybe L.Text)) -> P.Sem r Check buildCheck name cb = do   cb' <- bindSemToIO cb   let cb'' = fromMaybe (Just "failed internally") <.> cb'   pure $ MkCheck name cb'' +-- | Given the name of a check and a pure callback function, build a check. buildCheckPure :: S.Text -> (Context -> Maybe L.Text) -> Check buildCheckPure name cb = MkCheck name (pure . cb) +-- | Given an invokation 'Context', run a check and transform the result into an+-- @'Either' 'CommandError' ()@. runCheck :: P.Member (P.Embed IO) r => Context -> Check -> P.Sem r (Either CommandError ()) runCheck ctx chk = P.embed (callback chk ctx) <&> justToEither . (CheckError (chk ^. #name) <$>)
src/Calamity/Commands/Command.hs view
@@ -17,14 +17,23 @@ import           TextShow import qualified TextShow.Generic          as TSG +-- | A command data Command = forall a. Command   { name     :: S.Text   , parent   :: Maybe Group-  , checks   :: [Check]+  , checks   :: [Check] -- TODO check checks on default help+    -- ^ A list of checks that must pass for this command to be invoked   , params   :: [S.Text]+    -- ^ A list of the parameters the command takes, only used for constructing+    -- help messages.   , help     :: Context -> L.Text+    -- ^ A function producing the \'help\' for the command.   , parser   :: Context -> IO (Either CommandError a)+    -- ^ A function that parses the context for the command, producing the input+    -- @a@ for the command.   , callback :: (Context, a) -> IO (Maybe L.Text)+    -- ^ A function that given the context and the input (@a@) of the command,+    -- performs the action of the command.   }  data CommandS = CommandS
src/Calamity/Commands/CommandUtils.hs view
@@ -31,6 +31,9 @@ import qualified Polysemy.Error              as P import qualified Polysemy.Fail               as P +-- | Given the properties of a 'Command' with the @parser@ and @callback@ in the+-- 'P.Sem' monad, build a command by transforming the Polysemy actions into IO+-- actions. buildCommand' :: P.Member (P.Final IO) r               => S.Text               -> Maybe Group@@ -45,6 +48,22 @@   parser' <- buildParser name parser   pure $ Command name 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+-- the callback.+--+-- ==== Examples+--+-- Building a command that bans a user by id.+--+-- @+-- 'buildCommand' @\'['Named' "user" ('Snowflake' 'User'), 'Named' "reason" ('KleeneConcat' 'S.Text')]+--    "ban" 'Nothing' [] ('const' "Ban a user") $ \ctx uid r -> case (ctx 'Control.Lens.^.' #guild) of+--      'Just' guild -> do+--        'void' . 'Calamity.HTTP.invoke' . 'Calamity.HTTP.reason' r $ 'Calamity.HTTP.Guild.CreateGuildBan' guild uid+--        '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."+-- @ buildCommand :: forall ps r.              (P.Member (P.Final IO) r, TypedCommandC ps r)              => S.Text@@ -56,6 +75,9 @@ buildCommand name parent checks help command = let (parser, cb) = buildTypedCommand @ps command                                                in buildCommand' name 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+-- IO action. buildParser :: P.Member (P.Final IO) r             => S.Text             -> (Context -> P.Sem r (Either CommandError a))@@ -65,6 +87,8 @@   let cb'' ctx = fromMaybe (Left $ ParseError ("Parser for command: " <> name) "failed internally") <$> cb' ctx   pure cb'' +-- | Given a callback for a command in the 'P.Sem' monad, build a command callback by+-- transforming the Polysemy action into an IO action. buildCallback   :: P.Member (P.Final IO) r => ((Context, a) -> P.Sem (P.Fail ': r) ()) -> P.Sem r ((Context, a) -> IO (Maybe L.Text)) buildCallback cb = do@@ -74,11 +98,14 @@   let cb'' = fromMaybe (Just "failed internally") <.> cb'   pure cb'' +-- | 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   Left e   -> pure $ Left e   Right p' -> P.embed (callback (ctx, p')) <&> justToEither . (InvokeError name <$>) +-- | Given an invokation 'Context', first run all of the command's checks, then+-- run the command if they all pass. invokeCommand :: P.Member (P.Embed IO) r => Context -> Command -> P.Sem r (Either CommandError ()) invokeCommand ctx cmd@Command { checks } = P.runError $ do   for_ checks (P.fromEither <=< runCheck ctx)@@ -86,6 +113,7 @@  type CommandSemType r = P.Sem (P.Fail ': r) () +-- | Some constraints used for making parameter typed commands work type TypedCommandC ps r =   ( ApplyTupRes (ParserResult (ListToTup ps)) (CommandSemType r) ~ CommandForParsers ps r   , Parser (ListToTup ps) r@@ -138,6 +166,8 @@   ListToTup '[] = ()   ListToTup (x ': xs) = (x, ListToTup xs) +-- | Transform a type level list of types implementing the parser typeclass into+-- the type a command callback matching those parameters should be. type family CommandForParsers (ps :: [Type]) r where   CommandForParsers '[] r = P.Sem (P.Fail ': r) ()   CommandForParsers (x ': xs) r = ParserResult x -> CommandForParsers xs r
src/Calamity/Commands/Context.hs view
@@ -16,14 +16,22 @@ import           TextShow import qualified TextShow.Generic             as TSG +-- | Invokation context for commands data Context = Context   { message        :: Message+    -- ^ The message that the command was invoked from   , guild          :: Maybe Guild+    -- ^ If the command was sent in a guild, this will be present   , member         :: Maybe Member+    -- ^ The member that invoked the command, if in a guild   , channel        :: Channel+    -- ^ The channel the command was invoked from   , user           :: User+    -- ^ The user that invoked the command   , command        :: Command+    -- ^ The command that was invoked   , prefix         :: L.Text+    -- ^ The prefix that was used to invoke the command   , unparsedParams :: L.Text     -- ^ The message remaining after consuming the prefix   }
src/Calamity/Commands/Dsl.hs view
@@ -9,6 +9,7 @@     , requires'     , requiresPure     , group+    , group'     , DSLState     , raiseDSL ) where @@ -27,6 +28,7 @@  import qualified Polysemy                      as P import qualified Polysemy.Fail                 as P+import qualified Polysemy.Tagged               as P import qualified Polysemy.Fixpoint             as P import qualified Polysemy.Reader               as P @@ -34,14 +36,19 @@                        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)  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+raiseDSL = P.raise . P.raise . P.raise . P.raise . P.raise . P.raise . P.raise . P.raise --- | Build a command with an already prepared invokation action+-- | Given the command name 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. command'   :: P.Member (P.Final IO) r   => S.Text@@ -57,6 +64,22 @@   ltell $ LH.singleton name cmd   pure cmd +-- | Given the name 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.+--+-- @+-- 'command' \@\'['Calamity.Commands.Parser.Named' "user" ('Calamity.Types.Snowflake' 'Calamity.Types.Model.User'),+--                'Calamity.Commands.Parser.Named' "reason" ('Calamity.Commands.Parser.KleeneConcat' '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."+-- @ command :: forall ps r.         ( P.Member (P.Final IO) r,           TypedCommandC ps r)@@ -71,17 +94,22 @@   ltell $ LH.singleton name cmd'   pure cmd' +-- | Set the help for any groups or commands registered inside the given action. help :: P.Member (P.Reader (Context -> L.Text)) r      => (Context -> L.Text)      -> P.Sem r a      -> P.Sem r a help = P.local . const +-- | Add to the list of checks for any commands registered inside the given+-- action. requires :: [Check]          -> P.Sem (DSLState r) a          -> P.Sem (DSLState r) a requires = P.local . (<>) +-- | Construct a check and add it to the list of checks for any commands+-- registered inside the given action. requires' :: P.Member (P.Final IO) r           => S.Text           -> (Context -> P.Sem r (Maybe L.Text))@@ -91,11 +119,18 @@   check <- raiseDSL $ buildCheck name cb   requires [check] m +-- | Construct some pure checks and add them to the list of checks for any+-- commands registered inside the given action. requiresPure :: [(S.Text, Context -> Maybe L.Text)]              -> P.Sem (DSLState r) a              -> P.Sem (DSLState r) a requiresPure checks = requires $ map (uncurry buildCheckPure) checks +-- | Construct a group 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). group :: P.Member (P.Final IO) r          => S.Text          -> P.Sem (DSLState r) a@@ -104,10 +139,34 @@   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) $-                                 P.local @(Maybe Group) (const $ Just group') m+                                 P.local @(Maybe Group) (const $ Just group') $+                                 P.local @(Context -> L.Text) (const origHelp) m   ltell $ LH.singleton name group'   pure res +fetchOrigHelp :: P.Member (P.Tagged "original-help" (P.Reader (Context -> L.Text))) r => P.Sem r (Context -> L.Text)+fetchOrigHelp = P.tag P.ask++-- | Construct a group 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.+group' :: P.Member (P.Final IO) r+         => S.Text+         -> P.Sem (DSLState r) a+         -> P.Sem (DSLState r) a+group' name 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) $+                                 P.local @(Maybe Group) (const $ Just group') m+  ltell $ LH.singleton name group'+  pure res
src/Calamity/Commands/Group.hs view
@@ -17,13 +17,18 @@ import           TextShow import qualified TextShow.Generic          as TSG +-- | A group of commands data Group = Group   { name     :: S.Text   , parent   :: Maybe Group   , commands :: LH.HashMap S.Text Command+    -- ^ Any child commands of this group   , children :: LH.HashMap S.Text Group+    -- ^ Any child groups of this group   , help     :: Context -> L.Text+    -- ^ A function producing the \'help' for the group   , checks   :: [Check]+    -- -- ^ A list of checks that must pass   }   deriving ( Generic ) 
src/Calamity/Commands/Help.hs view
@@ -80,10 +80,15 @@                      else "No command or group with the path: `" <> L.fromStrict (S.intercalate " " path) <> "` was found.\n"                in void $ tell @L.Text ctx $ failedMsg <> rootHelp handler +-- | Given a 'CommandHandler', optionally a parent 'Group', and a list of 'Check's,+-- 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   (helpCommandCallback handler) +-- | Create and register the default help command for all the commands+-- registered in the commands DSL this is used in. helpCommand :: BotC r => P.Sem (DSLState r) Command helpCommand = do   handler <- P.ask @CommandHandler
src/Calamity/Commands/ParsePrefix.hs view
@@ -14,11 +14,13 @@  import qualified Polysemy                             as P +-- | An effect for parsing the prefix of a command. data ParsePrefix m a where   ParsePrefix :: Message -> ParsePrefix m (Maybe (L.Text, L.Text))  P.makeSem ''ParsePrefix +-- | A default interpretation for 'ParsePrefix' that uses a single constant prefix. useConstantPrefix :: L.Text -> P.Sem (ParsePrefix ': r) a -> P.Sem r a useConstantPrefix pre = P.interpret (\case                                        ParsePrefix m -> pure ((pre, ) <$> L.stripPrefix pre (m ^. #content)))
src/Calamity/Commands/Parser.hs view
@@ -64,7 +64,9 @@    parse :: P.Sem (ParserEffs r) (ParserResult a) -data Named (s :: Symbol) a+-- | A named parameter, used to attach the name @s@ to a type in the command's+-- help output+data Named (s :: Symbol) (a :: Type)  instance (KnownSymbol s, Parser a r) => Parser (Named s a) r where   type ParserResult (Named s a) = ParserResult a@@ -114,7 +116,10 @@     as <- parse @[a]     pure $ a :| as -data KleeneConcat a+-- | A parser that consumes zero or more of @a@ then concatenates them together.+--+-- @'KleeneConcat' 'L.Text'@ Is therefore consumes all remaining input.+data KleeneConcat (a :: Type)  instance (Monoid (ParserResult a), Parser a r) => Parser (KleeneConcat a) r where   type ParserResult (KleeneConcat a) = ParserResult a
src/Calamity/Commands/Utils.hs view
@@ -33,6 +33,7 @@ import qualified Polysemy                       as P import qualified Polysemy.Error                 as P import qualified Polysemy.Fail                  as P+import qualified Polysemy.Tagged                as P import qualified Polysemy.Fixpoint              as P import qualified Polysemy.Reader                as P @@ -46,6 +47,10 @@   | NF [L.Text]   | ERR Context CommandError +-- | Construct commands and groups from a command DSL, then registers an event+-- handler on the bot that manages running those commands.+--+-- Returns an action to remove the event handler, and the 'CommandHandler' that was constructed addCommands :: (BotC r, P.Member ParsePrefix r) => P.Sem (DSLState r) a -> P.Sem r (P.Sem r (), CommandHandler, a) addCommands m = do   (handler, res) <- buildCommands m@@ -64,6 +69,7 @@   pure (remove, handler, res)  +-- | Run a command DSL, returning the constructed 'CommandHandler' buildCommands :: forall r a. P.Member (P.Final IO) r               => P.Sem (DSLState r) a               -> P.Sem r (CommandHandler, a)@@ -76,12 +82,15 @@         inner h =           P.runReader h .           P.runReader [] .-          P.runReader (const "This command or group has no help.") .+          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)+        defaultHelp = (const "This command or group has no help.")  +-- | Attempt to build the context for a command buildContext :: BotC r => Message -> L.Text -> Command -> L.Text -> P.Sem r (Maybe Context) buildContext msg prefix command unparsed = (rightToMaybe <$>) . P.runFail $ do   guild <- join <$> getGuild `traverse` (msg ^. #guildID)
src/Calamity/Types/Snowflake.hs view
@@ -16,6 +16,7 @@ import           Data.Data import           Data.Generics.Product.Fields import           Data.Hashable+import           Data.Kind import           Data.Text.Read import qualified Data.Vector.Generic.Base     as V import qualified Data.Vector.Generic.Mutable  as MV@@ -25,11 +26,11 @@ import           GHC.Generics  import           TextShow-import qualified TextShow.Generic as TSG+import qualified TextShow.Generic             as TSG  -- Thanks sbrg -- https://github.com/saevarb/haskord/blob/d1bb07bcc4f3dbc29f2dfd3351ff9f16fc100c07/haskord-lib/src/Haskord/Types/Common.hs#L78-newtype Snowflake t = Snowflake+newtype Snowflake (t :: Type) = Snowflake   { fromSnowflake :: Word64   }   deriving ( Generic, Show, Eq, Ord, Data )