diff --git a/docs/guides/commands/commands.md b/docs/guides/commands/commands.md index e021b1eb3..0ac21c2a2 100644 --- a/docs/guides/commands/commands.md +++ b/docs/guides/commands/commands.md @@ -1,25 +1,18 @@ # The Command Service >[!WARNING] ->This article is out of date, and has not been rewritten yet. +>This article is out of date and has not been rewritten yet. Information is not guaranteed to be accurate. -[Discord.Commands](xref:Discord.Commands) provides an Attribute-based - Command Parser. +[Discord.Commands](xref:Discord.Commands) provides an Attribute-based command parser. ## Setup -To use Commands, you must create a [Commands Service] and a -Command Handler. +To use Commands, you must create a [Commands Service] and a Command Handler. -Included below is a very bare-bones Command Handler. You can extend -your Command Handler as much as you like, however the below is the -bare minimum. +Included below is a very barebone Command Handler. You can extend your Command Handler as much as you like; however, the below is the bare minimum. -The CommandService optionally will accept a [CommandServiceConfig], -which _does_ set a few default values for you. It is recommended to -look over the properties in [CommandServiceConfig], and their default -values. +The `CommandService` will optionally accept a [CommandServiceConfig], which _does_ set a few default values for you. It is recommended to look over the properties in [CommandServiceConfig] and their default values. [!code-csharp[Command Handler](samples/command_handler.cs)] @@ -28,32 +21,23 @@ values. ## With Attributes -In 1.0, Commands can be defined ahead of time, with attributes, or -at runtime, with builders. +In 1.0, Commands can be defined ahead of time with attributes, or at runtime with builders. -For most bots, ahead-of-time commands should be all you need, and this -is the recommended method of defining commands. +For most bots, ahead-of-time Commands should be all you need, and this is the recommended method of defining Commands. ### Modules -The first step to creating commands is to create a _module_. +The first step to creating Commands is to create a _module_. -Modules are an organizational pattern that allow you to write your -commands in different classes, and have them automatically loaded. +A Module is an organizational pattern that allows you to write your Commands in different classes and have them automatically loaded. -Discord.Net's implementation of Modules is influenced heavily from -ASP.Net Core's Controller pattern. This means that the lifetime of a -module instance is only as long as the command being invoked. +Discord.NET's implementation of Modules is influenced heavily from ASP.NET Core's Controller pattern. This means that the lifetime of a module instance is only as long as the Command is being invoked. -**Avoid using long-running code** in your modules wherever possible. -You should **not** be implementing very much logic into your modules; -outsource to a service for that. +**Avoid using long-running code** in your modules wherever possible. You should **not** be implementing very much logic into your modules; you should outsource to a service for that. -If you are unfamiliar with Inversion of Control, it is recommended to -read the MSDN article on [IoC] and [Dependency Injection]. +If you are unfamiliar with Inversion of Control, it is recommended to read the MSDN article on [IoC] and [Dependency Injection]. -To begin, create a new class somewhere in your project, and -inherit the class from [ModuleBase]. This class **must** be `public`. +To begin, create a new class somewhere in your project and inherit the class from [ModuleBase]. This class **must** be `public`. >[!NOTE] >[ModuleBase] is an _abstract_ class, meaning that you may extend it @@ -69,72 +53,47 @@ By now, your module should look like this: ### Adding Commands -The next step to creating commands, is actually creating commands. +The next step to creating Commands is actually creating the Commands. -To create a command, add a method to your module of type `Task`. -Typically, you will want to mark this method as `async`, although it is -not required. +To create a Command, add a method to your module of type `Task`. Typically, you will want to mark this method as `async`, although it is not required. -Adding parameters to a command is done by adding parameters to the -parent Task. +Adding parameters to a Command is done by adding parameters to the parent Task. -For example, to take an integer as an argument, add `int arg`. To take -a user as an argument, add `IUser user`. In 1.0, a command can accept -nearly any type of argument; a full list of types that are parsed by -default can be found in the below section on _Type Readers_. +For example, to take an integer as an argument from the user, add `int arg`; to take a user as an argument from the user, add `IUser user`. In 1.0, a Command can accept nearly any type of argument; a full list of types that are parsed by default can be found in the below section on _Type Readers_. -Parameters, by default, are always required. To make a parameter -optional, give it a default value. To accept a comma-separated list, -set the parameter to `params Type[]`. +Parameters, by default, are always required. To make a parameter optional, give it a default value. To accept a comma-separated list, set the parameter to `params Type[]`. -Should a parameter include spaces, it **must** be wrapped in quotes. -For example, for a command with a parameter `string food`, you would -execute it with `!favoritefood "Key Lime Pie"`. +Should a parameter include spaces, it **must** be wrapped in quotes. For example, for a Command with a parameter `string food`, you would execute it with `!favoritefood "Key Lime Pie"`. -If you would like a parameter to parse until the end of a command, -flag the parameter with the [RemainderAttribute]. This will allow a -user to invoke a command without wrapping a parameter in quotes. +If you would like a parameter to parse until the end of a Command, flag the parameter with the [RemainderAttribute]. This will allow a user to invoke a Command without wrapping a parameter in quotes. -Finally, flag your command with the [CommandAttribute]. (You must -specify a name for this command, except for when it is part of a -module group - see below). +Finally, flag your Command with the [CommandAttribute] (you must specify a name for this Command, except for when it is part of a Module Group - see below). [RemainderAttribute]: xref:Discord.Commands.RemainderAttribute [CommandAttribute]: xref:Discord.Commands.CommandAttribute ### Command Overloads -You may add overloads of your commands, and the command parser will -automatically pick up on it. +You may add overloads to your Commands, and the Command parser will automatically pick up on it. -If, for whatever reason, you have too commands which are ambiguous to -each other, you may use the @Discord.Commands.PriorityAttribute to -specify which should be tested before the other. +If for whatever reason, you have two Commands which are ambiguous to each other, you may use the @Discord.Commands.PriorityAttribute to specify which should be tested before the other. -Priority's are sorted in ascending order; the higher priority will be -called first. +The `Priority` attributes are sorted in ascending order; the higher priority will be called first. -### CommandContext +### Command Context -Every command can access the execution context through the [Context] -property on [ModuleBase]. CommandContext allows you to access the -message, channel, guild, and user that the command was invoked from, -as well as the underlying discord client the command was invoked from. +Every Command can access the execution context through the [Context] property on [ModuleBase]. `ICommandContext` allows you to access the message, channel, guild, and user that the Command was invoked from, as well as the underlying Discord client that the Command was invoked from. -Different types of Contexts may be specified using the generic variant -of [ModuleBase]. When using a [SocketCommandContext], for example, -the properties on this context will already be Socket entities. You -will not need to cast them. +Different types of Contexts may be specified using the generic variant of [ModuleBase]. When using a [SocketCommandContext], for example, the properties on this context will already be Socket entities, so you will not need to cast them. -To reply to messages, you may also invoke [ReplyAsync], instead of -accessing the channel through the [Context] and sending a message. +To reply to messages, you may also invoke [ReplyAsync], instead of accessing the channel through the [Context] and sending a message. [Context]: xref:Discord.Commands.ModuleBase`1#Discord_Commands_ModuleBase_1_Context [SocketCommandContext]: xref:Discord.Commands.SocketCommandContext >![WARNING] >Contexts should **NOT** be mixed! You cannot have one module that ->uses CommandContext, and another that uses SocketCommandContext. +>uses CommandContext and another that uses SocketCommandContext. ### Example Module @@ -143,53 +102,38 @@ At this point, your module should look comparable to this example: #### Loading Modules Automatically -The Command Service can automatically discover all classes in an -Assembly that inherit [ModuleBase], and load them. +The Command Service can automatically discover all classes in an Assembly that inherits [ModuleBase] and load them. -To opt a module out of auto-loading, flag it with -[DontAutoLoadAttribute] +To opt a module out of auto-loading, flag it with [DontAutoLoadAttribute]. -Invoke [CommandService.AddModulesAsync] to discover modules and -install them. +Invoke [CommandService.AddModulesAsync] to discover modules and install them. [DontAutoLoadAttribute]: xref:Discord.Commands.DontAutoLoadAttribute [CommandService.AddModulesAsync]: xref:Discord_Commands_CommandService#Discord_Commands_CommandService_AddModulesAsync_Assembly_ #### Loading Modules Manually -To manually load a module, invoke [CommandService.AddModuleAsync], -by passing in the generic type of your module, and optionally -a dependency map. +To manually load a module, invoke [CommandService.AddModuleAsync], by passing in the generic type of your module and optionally, a dependency map. [CommandService.AddModuleAsync]: xref:Discord.Commands.CommandService#Discord_Commands_CommandService_AddModuleAsync__1 ### Module Constructors -Modules are constructed using Dependency Injection. Any parameters -that are placed in the constructor must be injected into an -@System.IServiceProvider. Alternatively, you may accept an -IServiceProvider as an argument and extract services yourself. +Modules are constructed using Dependency Injection. Any parameters that are placed in the Module's constructor must be injected into an @System.IServiceProvider first. Alternatively, you may accept an `IServiceProvider` as an argument and extract services yourself. ### Module Properties -Modules with public settable properties will have them injected after module -construction. +Modules with `public` settable properties will have the dependencies injected after the construction of the Module. ### Module Groups -Module Groups allow you to create a module where commands are prefixed. -To create a group, flag a module with the -@Discord.Commands.GroupAttribute +Module Groups allow you to create a module where Commands are prefixed. To create a group, flag a module with the @Discord.Commands.GroupAttribute. -Module groups also allow you to create **nameless commands**, where the -[CommandAttribute] is configured with no name. In this case, the -command will inherit the name of the group it belongs to. +Module groups also allow you to create **nameless Commands**, where the [CommandAttribute] is configured with no name. In this case, the Command will inherit the name of the group it belongs to. ### Submodules -Submodules are modules that reside within another module. Typically, -submodules are used to create nested groups (although not required to -create nested groups). +Submodules are Modules that reside within another one. Typically, submodules are used to create nested groups (although not required to create nested groups). [!code-csharp[Groups and Submodules](samples/groups.cs)] @@ -199,54 +143,42 @@ create nested groups). ## Dependency Injection -The commands service is bundled with a very barebones Dependency -Injection service for your convienence. It is recommended that -you use DI when writing your modules. +The Command Service is bundled with a very barebone Dependency Injection service for your convenience. It is recommended that you use DI when writing your modules. ### Setup -First, you need to create an @System.IServiceProvider -You may create your own IServiceProvider if you wish. +First, you need to create an @System.IServiceProvider; you may create your own one if you wish. -Next, add the dependencies your modules will use to the map. +Next, add the dependencies that your modules will use to the map. -Finally, pass the map into the `LoadAssembly` method. -Your modules will automatically be loaded with this dependency map. +Finally, pass the map into the `LoadAssembly` method. Your modules will be automatically loaded with this dependency map. [!code-csharp[IServiceProvider Setup](samples/dependency_map_setup.cs)] ### Usage in Modules -In the constructor of your module, any parameters will be filled in by -the @System.IServiceProvider you pass into `LoadAssembly`. +In the constructor of your Module, any parameters will be filled in by the @System.IServiceProvider that you've passed into `LoadAssembly`. Any publicly settable properties will also be filled in the same manner. >[!NOTE] -> Annotating a property with the [DontInject] attribute will prevent it from -being injected. +> Annotating a property with the [DontInject] attribute will prevent it from being injected. >[!NOTE] ->If you accept `CommandService` or `IServiceProvider` as a parameter in -your constructor or as an injectable property, these entries will be filled -by the CommandService the module was loaded from, and the ServiceProvider passed -into it, respectively. +>If you accept `CommandService` or `IServiceProvider` as a parameter in your constructor, or as an injectable property, these entries will be filled by the `CommandService` that the Module is loaded from, and the `ServiceProvider` that is passed into it respectively. [!code-csharp[ServiceProvider in Modules](samples/dependency_module.cs)] # Preconditions -Preconditions serve as a permissions system for your commands. Keep in -mind, however, that they are not limited to _just_ permissions, and -can be as complex as you want them to be. +Precondition serve as a permissions system for your Commands. Keep in mind, however, that they are not limited to _just_ permissions and can be as complex as you want them to be. >[!NOTE] >Preconditions can be applied to Modules, Groups, or Commands. ## Bundled Preconditions -Commands ships with four bundled preconditions; you may view their -usages on their API page. +Commands ship with four bundled preconditions; you may view their usages on their respective API pages. - @Discord.Commands.RequireContextAttribute - @Discord.Commands.RequireOwnerAttribute @@ -255,17 +187,13 @@ usages on their API page. ## Custom Preconditions -To write your own preconditions, create a new class that inherits from - @Discord.Commands.PreconditionAttribute +To write your own precondition, create a new class that inherits from @Discord.Commands.PreconditionAttribute. -In order for your precondition to function, you will need to override -[CheckPermissions]. +In order for your precondition to function, you will need to override the [CheckPermissions] method. Your IDE should provide an option to fill this in for you. -Return [PreconditionResult.FromSuccess] if the context met the -required parameters, otherwise return [PreconditionResult.FromError], -optionally including an error message. +Return [PreconditionResult.FromSuccess] if the context meets the required parameters, otherwise return [PreconditionResult.FromError] and optionally include an error message. [!code-csharp[Custom Precondition](samples/require_owner.cs)] @@ -275,8 +203,7 @@ optionally including an error message. # Type Readers -Type Readers allow you to parse different types of arguments in -your commands. +Type Readers allow you to parse different types of arguments in your Commands. By default, the following Types are supported arguments: @@ -296,20 +223,18 @@ By default, the following Types are supported arguments: ### Creating a Type Readers -To create a TypeReader, create a new class that imports @Discord and -@Discord.Commands. Ensure your class inherits from @Discord.Commands.TypeReader +To create a `TypeReader`, create a new class that imports @Discord and @Discord.Commands and ensure the class inherits from @Discord.Commands.TypeReader. -Next, satisfy the `TypeReader` class by overriding [Read]. +Next, satisfy the `TypeReader` class by overriding the [Read] method. >[!NOTE] ->In many cases, Visual Studio can fill this in for you, using the +>In many cases, Visual Studio can fill this in for you using the >"Implement Abstract Class" IntelliSense hint. Inside this task, add whatever logic you need to parse the input string. Finally, return a `TypeReaderResult`. If you were able to successfully -parse the input, return `TypeReaderResult.FromSuccess(parsedInput)`. -Otherwise, return `TypeReaderResult.FromError`. +parse the input, return `TypeReaderResult.FromSuccess(parsedInput)`, otherwise, return `TypeReaderResult.FromError` and optionally include an error message. [Read]: xref:Discord.Commands.TypeReader#Discord_Commands_TypeReader_Read_Discord_Commands_CommandContext_System_String_ @@ -319,5 +244,6 @@ Otherwise, return `TypeReaderResult.FromError`. ### Installing TypeReaders -TypeReaders are not automatically discovered by the Command Service, -and must be explicitly added. To install a TypeReader, invoke [CommandService.AddTypeReader](xref:Discord.Commands.CommandService#Discord_Commands_CommandService_AddTypeReader__1_Discord_Commands_TypeReader_). +TypeReaders are not automatically discovered by the Command Service and must be explicitly added. + +To install a TypeReader, invoke [CommandService.AddTypeReader](xref:Discord.Commands.CommandService#Discord_Commands_CommandService_AddTypeReader__1_Discord_Commands_TypeReader_).