calamity 0.1.20.0 → 0.1.20.1
raw patch · 12 files changed
+142/−24 lines, 12 filesPVP: minor bump suggested
API additions: PVP suggests at least a minor version bump
API changes (from Hackage documentation)
+ Calamity.Commands.Parser: type ParserEffs r = State ParserState : Error (Text, Text) : Reader Context : r
Files
- ChangeLog.md +4/−0
- calamity.cabal +2/−2
- src/Calamity/Cache/Eff.hs +1/−1
- src/Calamity/Client.hs +1/−1
- src/Calamity/Commands.hs +5/−5
- src/Calamity/Commands/CommandUtils.hs +8/−1
- src/Calamity/Commands/Dsl.hs +53/−3
- src/Calamity/Commands/Help.hs +44/−1
- src/Calamity/Commands/ParsePrefix.hs +1/−0
- src/Calamity/Commands/Parser.hs +3/−2
- src/Calamity/Commands/Utils.hs +13/−1
- src/Calamity/Utils/Permissions.hs +7/−7
ChangeLog.md view
@@ -1,5 +1,9 @@ # Changelog for Calamity +## 0.1.20.1++* Documentation improvements.+ ## 0.1.20.0 * Migrate do di-polysemy 0.2, runBotIO no longer handles the Log effect.
calamity.cabal view
@@ -4,10 +4,10 @@ -- -- see: https://github.com/sol/hpack ----- hash: 0c8bab4fd581f5309d85bd6e640b7f1f3f953f8862ad5b5c607caabf95e1cb3e+-- hash: 55bf5727de4e0d34fab772f8f03176d91db899e03912214153fdfd0bf161eedc name: calamity-version: 0.1.20.0+version: 0.1.20.1 synopsis: A library for writing discord bots in haskell description: Please see the README on GitHub at <https://github.com/nitros12/calamity#readme> category: Network, Web
src/Calamity/Cache/Eff.hs view
@@ -65,7 +65,7 @@ SetDM :: DMChannel -> CacheEff m () -- | Get a 'DMChannel' from the cache GetDM :: Snowflake DMChannel -> CacheEff m (Maybe DMChannel)- -- | Get all 'DM's from the cache+ -- | Get all 'DMChannel's from the cache GetDMs :: CacheEff m [DMChannel] -- | Delete a 'DMChannel' from the cache DelDM :: Snowflake DMChannel -> CacheEff m ()
src/Calamity/Client.hs view
@@ -40,5 +40,5 @@ -- -- @ -- 'Control.Monad.void' . 'Polysemy.runFinal' . 'Polysemy.embedToFinal' . 'Calamity.Cache.InMemory.runCacheInMemory' . 'Calamity.Metrics.Noop.runMetricsNoop' $ 'runBotIO' ('Calamity.Types.Token.BotToken' token) $ do--- 'react' \@\''MessageCreateEvt' (\msg -> 'Polysemy.embed' $ 'print' msg)+-- 'react' \@\''MessageCreateEvt' $ \\msg -> 'Polysemy.embed' $ 'print' msg -- @
src/Calamity/Commands.hs view
@@ -1,5 +1,5 @@ -- | Calamity commands--- This module only exports the DSL and core types for using commands+-- This module exports the DSL and core types for using commands module Calamity.Commands ( module Calamity.Commands.Dsl , module Calamity.Commands.Error@@ -28,13 +28,13 @@ -- 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+-- 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+-- A default help command is provided in "Calamity.Commands.Help" which can be -- added just by using 'helpCommand' inside the command declaration DSL. -- --@@ -69,10 +69,10 @@ -- @ -- 'addCommands' $ do -- 'helpCommand'--- 'command' \@\'['Calamity.Types.Model.User.User'] "utest" $ \ctx u \-\> do+-- 'command' \@\'['Calamity.Types.Model.User.User'] "utest" $ \\ctx u \-\> do -- 'Control.Monad.void' $ 'Calamity.Types.Tellable.tell' ctx $ "got user: " '<>' 'TextShow.showtl' u -- 'group' "admin" $ do--- 'command' \@'[] "bye" $ \ctx -> do+-- 'command' \@'[] "bye" $ \\ctx -> do -- 'Control.Monad.void' $ 'Calamity.Types.Tellable.tell' ctx "bye!" -- 'Calamity.Client.stopBot' -- @
src/Calamity/Commands/CommandUtils.hs view
@@ -198,8 +198,15 @@ ListToTup '[] = () ListToTup (x ': xs) = (x, ListToTup xs) --- | Transform a type level list of types implementing the parser typeclass into+-- | Transform a type level list of types implementing the 'Parser' typeclass into -- the type a command callback matching those parameters should be.+--+-- As an example:+--+-- @+-- 'CommandForParsers' [ 'L.Text', 'Calamity.Types.Snowflake' 'Calamity.Types.User', 'Calamity.Commands.Parser.Named' "something" 'L.Text' ] r ~+-- ('L.Text' -> 'Calamity.Types.Snowflake' 'Calamity.Types.User' -> 'L.Text' -> 'P.Sem' r ('P.Fail' ': r) ())+-- @ 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/Dsl.hs view
@@ -2,7 +2,9 @@ -- | A DSL for generating commands and groups module Calamity.Commands.Dsl- ( command+ ( -- * Commands DSL+ -- $dslTutorial+ command , command' , commandA , commandA'@@ -40,6 +42,49 @@ import qualified Polysemy.Reader as P import Data.List.NonEmpty (NonEmpty(..)) +-- $dslTutorial+--+-- This module provides a way of constructing bot commands in a declarative way.+--+-- The main component of this is the 'command' function, which takes a+-- type-level list of command parameters, the name, and the callback and+-- produces a command. There are also the alternatives 'command'', 'commandA'+-- and 'commandA'', for when you want to handle parsing of the input yourself,+-- and/or want aliases of the command.+--+-- The functions: 'hide', 'help', 'requires', and 'group' can be used to change+-- attributes of any commands declared inside the monadic action passed to them,+-- for example:+--+-- @+-- 'hide' '$' do+-- 'command' \@'[] "test" \ctx -> 'pure' ()+-- @+--+-- In the above block, any command declared inside 'hide' will have it's+-- \'hidden\' flag set and will not be shown by the default help command:+-- 'Calamity.Commands.Help.helpCommand'+--+-- The 'Calamity.Commands.Help.helpCommand' function can be used to create a+-- help command for the commands DSL action it is used in, read it's doc page+-- for more information on how it functions.+--+-- The 'Calamity.Commands.Utils.addCommands' function creates the command+-- handler for the commands registered in the passed action, it is what reads a+-- message to determine what command was invoked. It should be used to register the+-- commands with the bot by using it inside the setup action, for example:+--+-- @+-- 'Calamity.Client.runBotIO' ('Calamity.BotToken' token)+-- $ 'Calamity.Commands.Utils.addCommands' $ do+-- 'Calamity.Commands.Help.helpCommand'+-- 'Calamity.Commands.Dsl.command' \@'[] "test" \ctx ->+-- 'Control.Monad.void' $ 'Calamity.Types.Tellable.tell' \@'L.Text' ctx "hi"+-- @+--+-- The above block will create a command with no parameters named \'test\',+-- along with a help command.+ type DSLState r = ( LocalWriter (LH.HashMap S.Text (Command, AliasType)) ': LocalWriter (LH.HashMap S.Text (Group, AliasType))@@ -110,6 +155,11 @@ -- The parent group, visibility, checks, and command help are drawn from the -- reader context. --+-- Command parameters are parsed by first invoking+-- 'Calamity.Commands.Parser.parse' for the first+-- 'Calamity.Commands.Parser.Parser', then running the next parser on the+-- remaining input, and so on.+-- -- ==== Examples -- -- Building a command that bans a user by id.@@ -117,7 +167,7 @@ -- @ -- 'command' \@\'['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+-- "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)@@ -146,7 +196,7 @@ -- @ -- '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+-- "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)
src/Calamity/Commands/Help.hs view
@@ -105,7 +105,7 @@ 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 (NE.head names) <> "`\n"+ else "No command or group with the path: `" <> L.fromStrict (S.unwords remainingPath) <> "` 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 ""@@ -121,6 +121,49 @@ -- | Create and register the default help command for all the commands -- registered in the commands DSL this is used in.+--+-- The registered command will have the name \'help\', called with no parameters+-- it will print the top-level groups and commands, for example:+--+-- @+-- The following groups exist:+-- - reanimate+-- - prefix[prefixes]+-- - alias[aliases]+-- - remind[reminder|reminders]+--+-- The following commands exist:+-- - help :[Text]+-- @+--+-- Both commands and groups are listed in the form: @\<name\>[\<alias 0\>|\<alias 1\>]@,+-- commands also have their parameter list shown.+--+-- If a path to a group is passed, the help, aliases, and pre-invokation checks+-- will be listed, along with the subgroups and commands, For example:+--+-- @+-- Help for group remind:+-- Group: remind+-- Aliases: reminder reminders+-- Commands related to making reminders+--+-- The following child commands exist:+-- - list+-- - remove reminder_id:Text+-- - add :KleenePlusConcat Text+-- @+--+-- If a command path is passed, the usage, checks and help for the command are+-- shown, for example:+--+-- @+-- Help for command add:+-- Usage: c!prefix add prefix:Text+-- Checks: prefixLimit guildOnly+--+-- Add a new prefix+-- @ helpCommand :: BotC r => P.Sem (DSLState r) Command helpCommand = do handler <- P.ask @CommandHandler
src/Calamity/Commands/ParsePrefix.hs view
@@ -16,6 +16,7 @@ -- | An effect for parsing the prefix of a command. data ParsePrefix m a where+ -- | Parse a prefix in a message, returning a tuple of @(prefix, remaining message)@ ParsePrefix :: Message -> ParsePrefix m (Maybe (L.Text, L.Text)) P.makeSem ''ParsePrefix
src/Calamity/Commands/Parser.hs view
@@ -4,6 +4,7 @@ , Named , KleeneStarConcat , KleenePlusConcat+ , ParserEffs , runCommandParser ) where import Calamity.Cache.Eff@@ -150,7 +151,7 @@ -- | A parser that consumes zero or more of @a@ then concatenates them together. ----- @'KleeneStarConcat' 'L.Text'@ Is therefore consumes all remaining input.+-- @'KleeneStarConcat' 'L.Text'@ therefore consumes all remaining input. data KleeneStarConcat (a :: Type) instance (Monoid (ParserResult a), Parser a r) => Parser (KleeneStarConcat a) r where@@ -172,7 +173,7 @@ -- | A parser that consumes one or more of @a@ then concatenates them together. ----- @'KleenePlusConcat' 'L.Text'@ Is therefore consumes all remaining input.+-- @'KleenePlusConcat' 'L.Text'@ therefore consumes all remaining input. data KleenePlusConcat (a :: Type) instance (Semigroup (ParserResult a), Parser a r) => Parser (KleenePlusConcat a) r where
src/Calamity/Commands/Utils.hs view
@@ -54,8 +54,20 @@ -- | 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. --+-- ==== Command Resolution+--+-- To determine if a command was invoked, and if so which command was invoked, the following happens:+--+-- 1. 'parsePrefix' is invoked, if no prefix is found: stop here.+--+-- 2. The input is read a word at a time until a matching command is found,+-- fire the \"command-not-found\" event if not.+--+-- 3. A 'Calamity.Commands.Context.Context' is built, and the command invoked.+-- -- ==== Custom Events -- -- This will fire the following events:@@ -130,7 +142,7 @@ runLocalWriter @(LH.HashMap S.Text (Command, AliasType)) defaultHelp = (const "This command or group has no help.") -+-- TODO: turn this into an effect -- | 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
src/Calamity/Utils/Permissions.hs view
@@ -23,7 +23,7 @@ import qualified Polysemy as P import Data.Foldable (Foldable(foldl')) --- | Calculate a 'Member''s 'Permissions' in a 'Guild'+-- | Calculate a 'Member'\'s 'Permissions' in a 'Guild' basePermissions :: Guild -> Member -> Permissions basePermissions g m | (g ^. #ownerID == getID m) = allFlags@@ -57,14 +57,14 @@ -- | Things that 'Member's have 'Permissions' in class PermissionsIn a where- -- | Calculate a 'Member''s 'Permissions' in something+ -- | Calculate a 'Member'\'s 'Permissions' in something permissionsIn :: a -> Member -> Permissions --- | A 'Member''s 'Permissions' in a channel are their roles and overwrites+-- | A 'Member'\'s 'Permissions' in a channel are their roles and overwrites instance PermissionsIn (Guild, GuildChannel) where permissionsIn (g, c) m = applyOverwrites c m $ basePermissions g m --- | A 'Member''s 'Permissions' in a guild are just their roles+-- | A 'Member'\'s 'Permissions' in a guild are just their roles instance PermissionsIn Guild where permissionsIn g m = basePermissions g m @@ -89,7 +89,7 @@ (Just m, Just g') -> pure $ permissionsIn (g', c) m _cantFind -> pure noFlags --- | A 'Member''s 'Permissions' in a guild are just their roles+-- | A 'Member'\'s 'Permissions' in a guild are just their roles instance PermissionsIn' Guild where permissionsIn' g (getID @User -> uid) = do m <- upgrade (getID @Guild g, coerceSnowflake @_ @Member uid)@@ -97,7 +97,7 @@ Just m' -> pure $ permissionsIn g m' Nothing -> pure noFlags --- | A 'Member''s 'Permissions' in a channel are their roles and overwrites+-- | A 'Member'\'s 'Permissions' in a channel are their roles and overwrites -- -- This will fetch the guild and channel from the cache or http as needed instance PermissionsIn' (Snowflake GuildChannel) where@@ -107,7 +107,7 @@ Just c' -> permissionsIn' c' u Nothing -> pure noFlags --- | A 'Member''s 'Permissions' in a guild are just their roles+-- | A 'Member'\'s 'Permissions' in a guild are just their roles -- -- This will fetch the guild from the cache or http as needed instance PermissionsIn' (Snowflake Guild) where