Skip to content

Add CommandInfoService #13

@TheBrambleShark

Description

@TheBrambleShark

Getting command information to build a help command is a common activity in any environment where a dedicated command parser is required. This command service should be able to return information on all commands, a branch of the command tree, or a single command node depending on user selection. Additionally, the command service should not make any assumptions about how the consumer of the CommandHelpService will render their command information, as each application would be different. For instance, a consumer in a console command line would likely want to display results differently than a consumer in a Discord bot.

The description of the group, command, and argument would be pulled from System.ComponentModel.DescriptionAttribute. If no attribute is found, Description will be null.

Proposed API

// Contains info on a specific command.
public interface ICommandInfo
{
    // The name of the command
    string Name { get; }

    // The description of the command.
    string? Description { get; }

    // A collection of command aliases
    IReadOnlyList<string> Aliases { get; }

    // Whether the command was adorned with a hidden attribute.
    bool Hidden { get; }

    // A collection of conditions which must be satisfied for this
    // command to run.
    IReadOnlyList<IConditionInfo> Conditions { get; }

    // A collection of info about the command's arguments, if any.
    IReadOnlyList<ICommandArgumentInfo> Arguments { get; }
}
// Contains info about a specific command argument.
public interface ICommandArgumentInfo
{
    // The name of the argument.
    string Name { get; }

    // The description of the argument.
    string? Description { get; }

    // The position of the argument
    int Position { get; }

    // The type of the argument (of TValue)
    Type ArgumentType { get; }

    // Returns true if the argument is not required.
    // To satisfy this condition, an argument must have a default value.
    // Depending on performance, this may be used to merge command
    // overloads which only add an additional argument or arguments.
    bool IsOptional { get; }

    // Whether the argument has a default value
    bool HasDefaultValue { get; }

    // The provided default value, if present.
    // Throws an InvalidOperationException if HasDefaultValue is false.
    object? DefaultValue { get; }
}
// Contains info about a particular command group.
public interface IGroupInfo
{
    // The name of the group.
    string Name { get; }

    // The group's description.
    string? Description { get; }

    // Whether the group was adorned with a hidden attribute.
    bool Hidden { get; }

    // A list of commands contained in this group.
    IReadOnlyList<ICommandInfo> { get; }

    // A list of child groups contained in this group.
    IReadOnlyList<IGroupInfo> { get; }
}
Contains information about a condition.
public interface IConditionInfo
{
    // The name of the condition. Usually just `nameof(MyCondition)`
    string Name { get; }

    // The description of the condition.
    string? Description { get; }
}
/// <summary>
/// A service which handles retrieving informational classes for building command help.
/// </summary>
public interface ICommandHelpService
{
    /// <summary>
    /// Attempts to perform a search against the command tree using the provided command string.
    /// </summary>
    /// <param name="commandString">A search string, either terminating with a command group or the command node itself, but without any parameters.</param>
    /// <param name="tokenizerOptions">Tokenization options to determine how to parse the <paramref name="commandString"/>.</param>
    /// <param name="treeSearchOptions">Tree search options to determine how to perform the search.</param>
    /// <returns>One of <see cref="IGroupInfo"/>, <see cref="ICommandInfo"/>, or an immutable collection of <see cref="ICommandInfo"/>s where multiple overloads are present.</returns>
    /// <example>
    /// User executes: -help "options reload"
    /// Where "options reload" would normally be the command string passed in place of help.
    /// This would locate a "reload" command located in the "commands" module.
    /// </example>
    Result<OneOf<IGroupInfo, ICommandInfo, ICommandInfo[]>> FindInfo(string commandString, Tokenization.TokenizerOptions? tokenizerOptions = null, Trees.TreeSearchOptions? treeSearchOptions = null);

    /// <summary>
    /// Gets information about the specified group.
    /// </summary>
    /// <param name="commandGroupType">The type of the command group to gather information on.</param>
    /// <param name="buildChildGroups">If true, child nodes will be created and populated. If false, the <see cref="IGroupInfo.ChildGroups"/> collection will be empty.</param>
    /// <returns>A <see cref="GroupInfo"/> representing the retrieved group.</returns>
    Result<IGroupInfo> GetGroupInfo(Type commandGroupType, bool buildChildGroups = false);

    /// <inheritdoc cref="GetGroupInfo(string, bool)"/>
    /// <typeparam name="TCommandGroup">The type of the command group to gather information on.</typeparam>
    Result<IGroupInfo> GetGroupInfo<TCommandGroup>(bool buildChildGroups = false)
        where TCommandGroup : CommandGroup;

    /// <summary>
    /// Gets information about all registered command groups and their commands.
    /// </summary>
    /// <param name="commandService">A <see cref="CommandService"/>containing all currently registered commands.</param>
    /// <returns>A read-only list of <see cref="GroupInfo"/>s representing the retrieved groups.</returns>
    Result<IRootInfo> GetAllCommands();
}
// Marks a group or command as being hidden.
// Attribute usage: class, method
public sealed class HiddenFromHelpAttribute : Attribute
{
    public string? Comment { get; init; }

    public HiddenFromHelpAttribute(string? comment = null)
    {
        Comment = comment;
    }
}

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions