From 106f346ddb8ada70ad2227d12e13be58d1234a17 Mon Sep 17 00:00:00 2001 From: Still Hsu <5843208+Still34@users.noreply.github.com> Date: Wed, 22 Apr 2020 14:04:10 +0800 Subject: [PATCH] docs: 2020 April Documentation Maintenance (#1484) * Add doc page for Named Arguments * Implement minor stylistic changes * Update docfx.json to support NS2.0 Signed-off-by: Still Hsu <5843208+Still34@users.noreply.github.com> * Fix broken xref in basic-operations * Fix broken crefs * Fix wordings in named argument * Fix misleading warning about long-running code * Fix misleading CommandService summary Signed-off-by: Still Hsu <5843208+Still34@users.noreply.github.com> * Update copyright year and version Signed-off-by: Still Hsu <5843208+Still34@users.noreply.github.com> * Escape example captions * Add warning regarding FlattenAsync for GetReactionUsersAsync * Fix a minor grammar mistake Co-authored-by: Joe4evr --- docs/docfx.json | 4 +- docs/faq/basics/basic-operations.md | 2 +- docs/guides/commands/intro.md | 8 +- docs/guides/commands/namedarguments.md | 79 +++++++++++++++++++ docs/guides/toc.yml | 2 + src/Discord.Net.Commands/CommandService.cs | 2 +- .../Entities/Channels/INestedChannel.cs | 8 +- .../Entities/Channels/ITextChannel.cs | 4 +- .../Entities/Guilds/IGuild.cs | 2 +- .../Entities/Messages/IMessage.cs | 29 +++++-- .../Entities/Messages/IUserMessage.cs | 2 +- .../Entities/Users/IGuildUser.cs | 4 +- src/Discord.Net.Core/Entities/Users/IUser.cs | 8 +- .../Extensions/MessageExtensions.cs | 6 +- .../Extensions/UserExtensions.cs | 4 +- src/Discord.Net.Core/IDiscordClient.cs | 2 +- src/Discord.Net.Core/RequestOptions.cs | 3 +- .../DataTypes/ChannelCreateAuditLogData.cs | 4 +- .../DataTypes/ChannelDeleteAuditLogData.cs | 4 +- .../AuditLogs/DataTypes/ChannelInfo.cs | 4 +- .../DiscordWebhookClient.cs | 2 +- 21 files changed, 139 insertions(+), 44 deletions(-) create mode 100644 docs/guides/commands/namedarguments.md diff --git a/docs/docfx.json b/docs/docfx.json index 17cf72388..759dc174f 100644 --- a/docs/docfx.json +++ b/docs/docfx.json @@ -9,7 +9,7 @@ "dest": "api", "filter": "filterConfig.yml", "properties": { - "TargetFramework": "netstandard1.3" + "TargetFramework": "netstandard2.0" } }], "build": { @@ -51,7 +51,7 @@ "overwrite": "_overwrites/**/**.md", "globalMetadata": { "_appTitle": "Discord.Net Documentation", - "_appFooter": "Discord.Net (c) 2015-2019 2.1.1", + "_appFooter": "Discord.Net (c) 2015-2020 2.2.0", "_enableSearch": true, "_appLogoPath": "marketing/logo/SVG/Logomark Purple.svg", "_appFaviconPath": "favicon.ico" diff --git a/docs/faq/basics/basic-operations.md b/docs/faq/basics/basic-operations.md index 93811977f..35c71709f 100644 --- a/docs/faq/basics/basic-operations.md +++ b/docs/faq/basics/basic-operations.md @@ -88,7 +88,7 @@ implement [IEmote] and are valid options. *** -[AddReactionAsync]: xref:Discord.IUserMessage.AddReactionAsync* +[AddReactionAsync]: xref:Discord.IMessage.AddReactionAsync* ## What is a "preemptive rate limit?" diff --git a/docs/guides/commands/intro.md b/docs/guides/commands/intro.md index f8ff1b596..abe7065c1 100644 --- a/docs/guides/commands/intro.md +++ b/docs/guides/commands/intro.md @@ -71,11 +71,11 @@ By now, your module should look like this: > [!WARNING] > **Avoid using long-running code** in your modules wherever possible. -> You should **not** be implementing very much logic into your -> modules, instead, outsource to a service for that. +> Long-running code, by default, within a command module +> can cause gateway thread to be blocked; therefore, interrupting +> the bot's connection to Discord. > -> If you are unfamiliar with Inversion of Control, it is recommended -> to read the MSDN article on [IoC] and [Dependency Injection]. +> You may read more about it in @FAQ.Commands.General . The next step to creating commands is actually creating the commands. diff --git a/docs/guides/commands/namedarguments.md b/docs/guides/commands/namedarguments.md new file mode 100644 index 000000000..890a8463f --- /dev/null +++ b/docs/guides/commands/namedarguments.md @@ -0,0 +1,79 @@ +--- +uid: Guides.Commands.NamedArguments +title: Named Arguments +--- + +# Named Arguments + +By default, arguments for commands are parsed positionally, meaning +that the order matters. But sometimes you may want to define a command +with many optional parameters, and it'd be easier for end-users +to only specify what they want to set, instead of needing them +to specify everything by hand. + +## Setting up Named Arguments + +In order to be able to specify different arguments by name, you have +to create a new class that contains all of the optional values that +the command will use, and apply an instance of +[NamedArgumentTypeAttribute] on it. + +### Example - Creating a Named Arguments Type + +```cs +[NamedArgumentType] +public class NamableArguments +{ + public string First { get; set; } + public string Second { get; set; } + public string Third { get; set; } + public string Fourth { get; set; } +} +``` + +## Usage in a Command + +The command where you want to use these values can be declared like so: +```cs +[Command("act")] +public async Task Act(int requiredArg, NamableArguments namedArgs) +``` + +The command can now be invoked as +`.act 42 first: Hello fourth: "A string with spaces must be wrapped in quotes" second: World`. + +A TypeReader for the named arguments container type is +automatically registered. +It's important that any other arguments that would be required +are placed before the container type. + +> [!IMPORTANT] +> A single command can have only __one__ parameter of a +> type annotated with [NamedArgumentTypeAttribute], and it +> **MUST** be the last parameter in the list. +> A command parameter of such an annotated type +> is automatically treated as if that parameter +> has [RemainderAttribute](xref:Discord.Commands.RemainderAttribute) +> applied. + +## Complex Types + +The TypeReader for Named Argument Types will look for a TypeReader +of every property type, meaning any other command parameter type +will work just the same. + +You can also read multiple values into a single property +by making that property an `IEnumerable`. So for example, if your +Named Argument Type has the following field, +```cs +public IEnumerable Numbers { get; set; } +``` +then the command can be invoked as +`.cmd numbers: "1, 2, 4, 8, 16, 32"` + +## Additional Notes + +The use of [`[OverrideTypeReader]`](xref:Discord.Commands.OverrideTypeReaderAttribute) +is also supported on the properties of a Named Argument Type. + +[NamedArgumentTypeAttribute]: xref:Discord.Commands.NamedArgumentTypeAttribute diff --git a/docs/guides/toc.yml b/docs/guides/toc.yml index 01c245301..a6c38768f 100644 --- a/docs/guides/toc.yml +++ b/docs/guides/toc.yml @@ -27,6 +27,8 @@ topicUid: Guides.Commands.Intro - name: TypeReaders topicUid: Guides.Commands.TypeReaders + - name: Named Arguments + topicUid: Guides.Commands.NamedArguments - name: Preconditions topicUid: Guides.Commands.Preconditions - name: Dependency Injection diff --git a/src/Discord.Net.Commands/CommandService.cs b/src/Discord.Net.Commands/CommandService.cs index d5c060fe4..1d4b0e15a 100644 --- a/src/Discord.Net.Commands/CommandService.cs +++ b/src/Discord.Net.Commands/CommandService.cs @@ -36,7 +36,7 @@ namespace Discord.Commands internal readonly AsyncEvent> _logEvent = new AsyncEvent>(); /// - /// Occurs when a command is successfully executed without any error. + /// Occurs when a command is executed. /// /// /// This event is fired when a command has been executed, successfully or not. When a command fails to diff --git a/src/Discord.Net.Core/Entities/Channels/INestedChannel.cs b/src/Discord.Net.Core/Entities/Channels/INestedChannel.cs index e38e1db41..2c9503db1 100644 --- a/src/Discord.Net.Core/Entities/Channels/INestedChannel.cs +++ b/src/Discord.Net.Core/Entities/Channels/INestedChannel.cs @@ -40,8 +40,8 @@ namespace Discord /// Creates a new invite to this channel. /// /// - /// The following example creates a new invite to this channel; the invite lasts for 12 hours and can only - /// be used 3 times throughout its lifespan. + /// The following example creates a new invite to this channel; the invite lasts for 12 hours and can only + /// be used 3 times throughout its lifespan. /// /// await guildChannel.CreateInviteAsync(maxAge: 43200, maxUses: 3); /// @@ -60,8 +60,8 @@ namespace Discord /// Gets a collection of all invites to this channel. /// B /// - /// The following example gets all of the invites that have been created in this channel and selects the - /// most used invite. + /// The following example gets all of the invites that have been created in this channel and selects the + /// most used invite. /// /// var invites = await channel.GetInvitesAsync(); /// if (invites.Count == 0) return; diff --git a/src/Discord.Net.Core/Entities/Channels/ITextChannel.cs b/src/Discord.Net.Core/Entities/Channels/ITextChannel.cs index 29c764e3f..a2baf6990 100644 --- a/src/Discord.Net.Core/Entities/Channels/ITextChannel.cs +++ b/src/Discord.Net.Core/Entities/Channels/ITextChannel.cs @@ -30,7 +30,7 @@ namespace Discord /// Gets the current slow-mode delay for this channel. /// /// - /// An representing the time in seconds required before the user can send another + /// An representing the time in seconds required before the user can send another /// message; 0 if disabled. /// int SlowModeInterval { get; } @@ -39,7 +39,7 @@ namespace Discord /// Bulk-deletes multiple messages. /// /// - /// The following example gets 250 messages from the channel and deletes them. + /// The following example gets 250 messages from the channel and deletes them. /// /// var messages = await textChannel.GetMessagesAsync(250).FlattenAsync(); /// await textChannel.DeleteMessagesAsync(messages); diff --git a/src/Discord.Net.Core/Entities/Guilds/IGuild.cs b/src/Discord.Net.Core/Entities/Guilds/IGuild.cs index a18e91b69..b39a49776 100644 --- a/src/Discord.Net.Core/Entities/Guilds/IGuild.cs +++ b/src/Discord.Net.Core/Entities/Guilds/IGuild.cs @@ -510,7 +510,7 @@ namespace Discord /// Creates a new text channel in this guild. /// /// - /// The following example creates a new text channel under an existing category named Wumpus with a set topic. + /// The following example creates a new text channel under an existing category named Wumpus with a set topic. /// /// diff --git a/src/Discord.Net.Core/Entities/Messages/IMessage.cs b/src/Discord.Net.Core/Entities/Messages/IMessage.cs index 05f505269..aac526831 100644 --- a/src/Discord.Net.Core/Entities/Messages/IMessage.cs +++ b/src/Discord.Net.Core/Entities/Messages/IMessage.cs @@ -161,7 +161,7 @@ namespace Discord /// Adds a reaction to this message. /// /// - /// The following example adds the reaction, 💕, to the message. + /// The following example adds the reaction, 💕, to the message. /// /// await msg.AddReactionAsync(new Emoji("\U0001f495")); /// @@ -177,7 +177,7 @@ namespace Discord /// Removes a reaction from message. /// /// - /// The following example removes the reaction, 💕, added by the message author from the message. + /// The following example removes the reaction, 💕, added by the message author from the message. /// /// await msg.RemoveReactionAsync(new Emoji("\U0001f495"), msg.Author); /// @@ -194,7 +194,7 @@ namespace Discord /// Removes a reaction from message. /// /// - /// The following example removes the reaction, 💕, added by the user with ID 84291986575613952 from the message. + /// The following example removes the reaction, 💕, added by the user with ID 84291986575613952 from the message. /// /// await msg.RemoveReactionAsync(new Emoji("\U0001f495"), 84291986575613952); /// @@ -219,8 +219,25 @@ namespace Discord /// /// Gets all users that reacted to a message with a given emote. /// + /// + /// + /// The returned collection is an asynchronous enumerable object; one must call + /// to access the users as a + /// collection. + /// + /// + /// Do not fetch too many users at once! This may cause unwanted preemptive rate limit or even actual + /// rate limit, causing your bot to freeze! + /// + /// This method will attempt to fetch the number of reactions specified under . + /// The library will attempt to split up the requests according to your and + /// . In other words, should the user request 500 reactions, + /// and the constant is 100, the request will + /// be split into 5 individual requests; thus returning 5 individual asynchronous responses, hence the need + /// of flattening. + /// /// - /// The following example gets the users that have reacted with the emoji 💕 to the message. + /// The following example gets the users that have reacted with the emoji 💕 to the message. /// /// var emoji = new Emoji("\U0001f495"); /// var reactedUsers = await message.GetReactionUsersAsync(emoji, 100).FlattenAsync(); @@ -230,9 +247,7 @@ namespace Discord /// The number of users to request. /// The options to be used when sending the request. /// - /// A paged collection containing a read-only collection of users that has reacted to this message. - /// Flattening the paginated response into a collection of users with - /// is required if you wish to access the users. + /// Paged collection of users. /// IAsyncEnumerable> GetReactionUsersAsync(IEmote emoji, int limit, RequestOptions options = null); } diff --git a/src/Discord.Net.Core/Entities/Messages/IUserMessage.cs b/src/Discord.Net.Core/Entities/Messages/IUserMessage.cs index be2523b21..bc52dd01c 100644 --- a/src/Discord.Net.Core/Entities/Messages/IUserMessage.cs +++ b/src/Discord.Net.Core/Entities/Messages/IUserMessage.cs @@ -17,7 +17,7 @@ namespace Discord /// method and what properties are available, please refer to . /// /// - /// The following example replaces the content of the message with Hello World!. + /// The following example replaces the content of the message with Hello World!. /// /// await msg.ModifyAsync(x => x.Content = "Hello World!"); /// diff --git a/src/Discord.Net.Core/Entities/Users/IGuildUser.cs b/src/Discord.Net.Core/Entities/Users/IGuildUser.cs index ae682afd5..60fa06cbd 100644 --- a/src/Discord.Net.Core/Entities/Users/IGuildUser.cs +++ b/src/Discord.Net.Core/Entities/Users/IGuildUser.cs @@ -72,8 +72,8 @@ namespace Discord /// Gets the level permissions granted to this user to a given channel. /// /// - /// The following example checks if the current user has the ability to send a message with attachment in - /// this channel; if so, uploads a file via . + /// The following example checks if the current user has the ability to send a message with attachment in + /// this channel; if so, uploads a file via . /// /// if (currentUser?.GetPermissions(targetChannel)?.AttachFiles) /// await targetChannel.SendFileAsync("fortnite.png"); diff --git a/src/Discord.Net.Core/Entities/Users/IUser.cs b/src/Discord.Net.Core/Entities/Users/IUser.cs index c59a75de1..c36fb2326 100644 --- a/src/Discord.Net.Core/Entities/Users/IUser.cs +++ b/src/Discord.Net.Core/Entities/Users/IUser.cs @@ -21,8 +21,8 @@ namespace Discord /// example). /// /// - /// The following example attempts to retrieve the user's current avatar and send it to a channel; if one is - /// not set, a default avatar for this user will be returned instead. + /// The following example attempts to retrieve the user's current avatar and send it to a channel; if one is + /// not set, a default avatar for this user will be returned instead. /// /// @@ -90,8 +90,8 @@ namespace Discord /// /// /// - /// The following example attempts to send a direct message to the target user and logs the incident should - /// it fail. + /// The following example attempts to send a direct message to the target user and logs the incident should + /// it fail. /// /// diff --git a/src/Discord.Net.Core/Extensions/MessageExtensions.cs b/src/Discord.Net.Core/Extensions/MessageExtensions.cs index 90ebea92f..64a1d89ab 100644 --- a/src/Discord.Net.Core/Extensions/MessageExtensions.cs +++ b/src/Discord.Net.Core/Extensions/MessageExtensions.cs @@ -39,7 +39,7 @@ namespace Discord /// /// A task that represents the asynchronous operation for adding a reaction to this message. /// - /// + /// /// public static async Task AddReactionsAsync(this IUserMessage msg, IEmote[] reactions, RequestOptions options = null) { @@ -51,7 +51,7 @@ namespace Discord /// /// /// This method does not bulk remove reactions! If you want to clear reactions from a message, - /// + /// /// /// /// @@ -64,7 +64,7 @@ namespace Discord /// /// A task that represents the asynchronous operation for removing a reaction to this message. /// - /// + /// /// public static async Task RemoveReactionsAsync(this IUserMessage msg, IUser user, IEmote[] reactions, RequestOptions options = null) { diff --git a/src/Discord.Net.Core/Extensions/UserExtensions.cs b/src/Discord.Net.Core/Extensions/UserExtensions.cs index f98bf7227..58c762090 100644 --- a/src/Discord.Net.Core/Extensions/UserExtensions.cs +++ b/src/Discord.Net.Core/Extensions/UserExtensions.cs @@ -44,8 +44,8 @@ namespace Discord /// Sends a file to this message channel with an optional caption. /// /// - /// The following example uploads a streamed image that will be called b1nzy.jpg embedded inside a - /// rich embed to the channel. + /// The following example uploads a streamed image that will be called b1nzy.jpg embedded inside a + /// rich embed to the channel. /// /// await channel.SendFileAsync(b1nzyStream, "b1nzy.jpg", /// embed: new EmbedBuilder {ImageUrl = "attachment://b1nzy.jpg"}.Build()); diff --git a/src/Discord.Net.Core/IDiscordClient.cs b/src/Discord.Net.Core/IDiscordClient.cs index e1c900680..f972cd71d 100644 --- a/src/Discord.Net.Core/IDiscordClient.cs +++ b/src/Discord.Net.Core/IDiscordClient.cs @@ -270,7 +270,7 @@ namespace Discord /// /// The options to be used when sending the request. /// - /// A task that represents the asynchronous get operation. The task result contains an + /// A task that represents the asynchronous get operation. The task result contains an /// that represents the number of shards that should be used with this account. /// Task GetRecommendedShardCountAsync(RequestOptions options = null); diff --git a/src/Discord.Net.Core/RequestOptions.cs b/src/Discord.Net.Core/RequestOptions.cs index 6aa0eea12..1b05df2a3 100644 --- a/src/Discord.Net.Core/RequestOptions.cs +++ b/src/Discord.Net.Core/RequestOptions.cs @@ -49,8 +49,7 @@ namespace Discord /// clock for rate-limiting. Defaults to true. /// /// - /// This property can also be set in . - /// + /// This property can also be set in . /// On a per-request basis, the system clock should only be disabled /// when millisecond precision is especially important, and the /// hosting system is known to have a desynced clock. diff --git a/src/Discord.Net.Rest/Entities/AuditLogs/DataTypes/ChannelCreateAuditLogData.cs b/src/Discord.Net.Rest/Entities/AuditLogs/DataTypes/ChannelCreateAuditLogData.cs index f432b4ca5..7a015d6bc 100644 --- a/src/Discord.Net.Rest/Entities/AuditLogs/DataTypes/ChannelCreateAuditLogData.cs +++ b/src/Discord.Net.Rest/Entities/AuditLogs/DataTypes/ChannelCreateAuditLogData.cs @@ -78,7 +78,7 @@ namespace Discord.Rest /// Gets the current slow-mode delay of the created channel. /// /// - /// An representing the time in seconds required before the user can send another + /// An representing the time in seconds required before the user can send another /// message; 0 if disabled. /// null if this is not mentioned in this entry. /// @@ -95,7 +95,7 @@ namespace Discord.Rest /// Gets the bit-rate that the clients in the created voice channel are requested to use. /// /// - /// An representing the bit-rate (bps) that the created voice channel defines and requests the + /// An representing the bit-rate (bps) that the created voice channel defines and requests the /// client(s) to use. /// null if this is not mentioned in this entry. /// diff --git a/src/Discord.Net.Rest/Entities/AuditLogs/DataTypes/ChannelDeleteAuditLogData.cs b/src/Discord.Net.Rest/Entities/AuditLogs/DataTypes/ChannelDeleteAuditLogData.cs index 390749929..81ae7155b 100644 --- a/src/Discord.Net.Rest/Entities/AuditLogs/DataTypes/ChannelDeleteAuditLogData.cs +++ b/src/Discord.Net.Rest/Entities/AuditLogs/DataTypes/ChannelDeleteAuditLogData.cs @@ -71,7 +71,7 @@ namespace Discord.Rest /// Gets the slow-mode delay of the deleted channel. /// /// - /// An representing the time in seconds required before the user can send another + /// An representing the time in seconds required before the user can send another /// message; 0 if disabled. /// null if this is not mentioned in this entry. /// @@ -88,7 +88,7 @@ namespace Discord.Rest /// Gets the bit-rate of this channel if applicable. /// /// - /// An representing the bit-rate set of the voice channel. + /// An representing the bit-rate set of the voice channel. /// null if this is not mentioned in this entry. /// public int? Bitrate { get; } diff --git a/src/Discord.Net.Rest/Entities/AuditLogs/DataTypes/ChannelInfo.cs b/src/Discord.Net.Rest/Entities/AuditLogs/DataTypes/ChannelInfo.cs index d6d2fb4b3..0284b63f5 100644 --- a/src/Discord.Net.Rest/Entities/AuditLogs/DataTypes/ChannelInfo.cs +++ b/src/Discord.Net.Rest/Entities/AuditLogs/DataTypes/ChannelInfo.cs @@ -32,7 +32,7 @@ namespace Discord.Rest /// Gets the current slow-mode delay of this channel. /// /// - /// An representing the time in seconds required before the user can send another + /// An representing the time in seconds required before the user can send another /// message; 0 if disabled. /// null if this is not mentioned in this entry. /// @@ -49,7 +49,7 @@ namespace Discord.Rest /// Gets the bit-rate of this channel if applicable. /// /// - /// An representing the bit-rate set for the voice channel; + /// An representing the bit-rate set for the voice channel; /// null if this is not mentioned in this entry. /// public int? Bitrate { get; } diff --git a/src/Discord.Net.Webhook/DiscordWebhookClient.cs b/src/Discord.Net.Webhook/DiscordWebhookClient.cs index 542ec7997..9c90df565 100644 --- a/src/Discord.Net.Webhook/DiscordWebhookClient.cs +++ b/src/Discord.Net.Webhook/DiscordWebhookClient.cs @@ -85,7 +85,7 @@ namespace Discord.Webhook } private static API.DiscordRestApiClient CreateApiClient(DiscordRestConfig config) => new API.DiscordRestApiClient(config.RestClientProvider, DiscordRestConfig.UserAgent); - /// Sends a message using to the channel for this webhook. + /// Sends a message to the channel for this webhook. /// Returns the ID of the created message. public Task SendMessageAsync(string text = null, bool isTTS = false, IEnumerable embeds = null, string username = null, string avatarUrl = null, RequestOptions options = null)