diff --git a/sources/LevelAPI/Features/Commands/BuiltInCommands/ACommandHelp.uc b/sources/LevelAPI/Features/Commands/BuiltInCommands/ACommandHelp.uc index a4ec0f9..0540cc7 100644 --- a/sources/LevelAPI/Features/Commands/BuiltInCommands/ACommandHelp.uc +++ b/sources/LevelAPI/Features/Commands/BuiltInCommands/ACommandHelp.uc @@ -102,21 +102,22 @@ protected function Finalizer() protected function BuildData(CommandDataBuilder builder) { - builder.Name(P("help")).Group(P("core")) - .Summary(P("Displays detailed information about available commands.")); - builder.OptionalParams() - .ParamTextList(P("commands")) - .Describe(P("Displays information about all specified commands.")); - builder.Option(P("aliases")) - .Describe(P("When displaying available commands, specifying this flag" - @ "will additionally make command to display all of their available" - @ "aliases.")) - .Option(P("list")) - .Describe(P("Display available commands. Optionally command groups can" - @ "be specified and then only commands from such groups will be" - @ "listed. Otherwise all commands will be displayed.")) - .OptionalParams() - .ParamTextList(P("groups")); + builder.Name(P("help")); + builder.Group(P("core")); + builder.Summary(P("Displays detailed information about available commands.")); + builder.OptionalParams(); + builder.ParamTextList(P("commands")); + + builder.Option(P("aliases")); + builder.Describe(P("When displaying available commands, specifying this flag will additionally" + @ "make command to display all of their available aliases.")); + + builder.Option(P("list")); + builder.Describe(P("Display available commands. Optionally command groups can be specified and" + @ "then only commands from such groups will be listed. Otherwise all commands will" + @ "be displayed.")); + builder.OptionalParams(); + builder.ParamTextList(P("groups")); } protected function Executed(Command.CallData callData, EPlayer callerPlayer) diff --git a/sources/LevelAPI/Features/Commands/CommandDataBuilder.uc b/sources/LevelAPI/Features/Commands/CommandDataBuilder.uc index c441157..8232917 100644 --- a/sources/LevelAPI/Features/Commands/CommandDataBuilder.uc +++ b/sources/LevelAPI/Features/Commands/CommandDataBuilder.uc @@ -1,7 +1,8 @@ /** - * Utility class that provides developers with a simple interface to - * prepare data that describes command's parameters and options. - * Copyright 2021-2022 Anton Tarasenko + * Author: dkanus + * Home repo: https://www.insultplayers.ru/git/AcediaFramework/AcediaCore + * License: GPL + * Copyright 2021-2023 Anton Tarasenko *------------------------------------------------------------------------------ * This file is part of Acedia. * @@ -21,105 +22,82 @@ class CommandDataBuilder extends AcediaObject dependson(Command); -/** - * # `CommandDataBuilder` - * - * This class is made for convenient creation of `Command.Data` using - * a builder pattern. - * - * ## Usage - * - * `CommandDataBuilder` should be able to fill information about: - * subcommands/options and their parameters. - * As far as user is concerned, the process of filling both should be - * identical. Overall, intended flow for creating a new sub-command or option - * is to select either, fill it with data with public methods `Param...()` into - * "selected data" and then copy it into "prepared data" - * (through a `RecordSelection()` method below). - * For examples see `BuildData()` methods from `ACommandHelp` or any of - * the commands from "Futility" package. - * - * ## Implementation - * - * We will store all defined data in two ways: - * - * 1. Selected data: data about parameters for subcommand/option that is - * currently being filled; - * 2. Prepared data: data that was already filled as "selected data" then - * stored in these records. Whenever we want to switch to filling - * another subcommand/option or return already prepared data we must - * dump "selected data" into "prepared data" first and then return - * the latter. - * - * Builder object is automatically created when new `Command` instance is - * allocated and, therefore, doesn't normally need to be allocated by hand. - */ - -// "Prepared data" -var private Text commandName, commandGroup; -var private Text commandSummary; -var private array subcommands; -var private array options; -var private bool requiresTarget; -// Auxiliary arrays signifying that we've started adding optional -// parameters into appropriate `subcommands` and `options`. -// All optional parameters must follow strictly after required parameters -// and so, after user have started adding optional parameters to -// subcommand/option, we prevent them from adding required ones -// (to that particular command/option). +//! This is an auxiliary class for convenient creation of [`Command::Data`] using a builder pattern. +//! +//! ## Implementation +//! +//! We will store all defined data in two ways: +//! +//! 1. Selected data: data about parameters for subcommand/option that is currently being filled; +//! 2. Prepared data: data that was already filled as "selected data" then stored in these records. +//! Whenever we want to switch to filling another subcommand/option or return already prepared +//! data we must dump "selected data" into "prepared data" first and then return the latter. +//! +//! Builder object is automatically created when new `Command` instance is allocated and doesn't +//! normally need to be allocated by hand. + +// "Prepared data" +var private Text commandName, commandGroup; +var private Text commandSummary; +var private array subcommands; +var private array options; +var private bool requiresTarget; + +// Auxiliary arrays signifying that we've started adding optional parameters into appropriate +// `subcommands` and `options`. +// +// All optional parameters must follow strictly after required parameters and so, after user have +// started adding optional parameters to subcommand/option, we prevent them from adding required +// ones (to that particular command/option). var private array subcommandsIsOptional; var private array optionsIsOptional; -// "Selected data" -// `false` means we have selected sub-command, `true` - option -var private bool selectedItemIsOption; -// `name` for sub-commands, `longName` for options -var private Text selectedItemName; -// Description of selected sub-command/option -var private Text selectedDescription; -// Are we filling optional parameters (`true`)? Or required ones (`false`)? -var private bool selectionIsOptional; -// Array of parameters we are currently filling (either required or optional) -var private array selectedParameterArray; - -var LoggerAPI.Definition errLongNameTooShort, errShortNameTooLong; -var LoggerAPI.Definition warnSameLongName, warnSameShortName; - -protected function Constructor() -{ +// "Selected data" +// `false` means we have selected sub-command, `true` - option +var private bool selectedItemIsOption; +// `name` for sub-commands, `longName` for options +var private Text selectedItemName; +// Description of selected sub-command/option +var private Text selectedDescription; +// Are we filling optional parameters (`true`)? Or required ones (`false`)? +var private bool selectionIsOptional; +// Array of parameters we are currently filling (either required or optional) +var private array selectedParameterArray; + +var private LoggerAPI.Definition errLongNameTooShort, errShortNameTooLong; +var private LoggerAPI.Definition warnSameLongName, warnSameShortName; + +protected function Constructor() { // Fill empty subcommand (no special key word) by default - SelectSubCommand(P("")); + SubCommand(P("")); } -protected function Finalizer() -{ - subcommands.length = 0; - subcommandsIsOptional.length = 0; - options.length = 0; - optionsIsOptional.length = 0; - selectedParameterArray.length = 0; - commandName = none; - commandGroup = none; - commandSummary = none; - selectedItemName = none; - selectedDescription = none; - requiresTarget = false; - selectedItemIsOption = false; - selectionIsOptional = false; -} - -// Find index of sub-command with a given name `name` in `subcommands`. -// `-1` if there's not sub-command with such name. -// Case-sensitive. -private final function int FindSubCommandIndex(BaseText name) -{ +protected function Finalizer() { + subcommands.length = 0; + subcommandsIsOptional.length = 0; + options.length = 0; + optionsIsOptional.length = 0; + selectedParameterArray.length = 0; + commandName = none; + commandGroup = none; + commandSummary = none; + selectedItemName = none; + selectedDescription = none; + requiresTarget = false; + selectedItemIsOption = false; + selectionIsOptional = false; +} + +// Find index of sub-command with a given name `name` in `subcommands`. +// `-1` if there's not sub-command with such name. +// Case-sensitive. +private final function int FindSubCommandIndex(BaseText name) { local int i; if (name == none) { return -1; } - for (i = 0; i < subcommands.length; i += 1) - { + for (i = 0; i < subcommands.length; i += 1) { if (name.Compare(subcommands[i].name)) { return i; } @@ -127,18 +105,16 @@ private final function int FindSubCommandIndex(BaseText name) return -1; } -// Find index of option with a given name `name` in `options`. -// `-1` if there's not sub-command with such name. -// Case-sensitive. -private final function int FindOptionIndex(BaseText longName) -{ +// Find index of option with a given name `name` in `options`. +// `-1` if there's not sub-command with such name. +// Case-sensitive. +private final function int FindOptionIndex(BaseText longName) { local int i; if (longName == none) { return -1; } - for (i = 0; i < options.length; i += 1) - { + for (i = 0; i < options.length; i += 1) { if (longName.Compare(options[i].longName)) { return i; } @@ -146,180 +122,111 @@ private final function int FindOptionIndex(BaseText longName) return -1; } -// Creates an empty selection record for subcommand or option with -// name (long name) `name`. -// Doe not check whether subcommand/option with that name already exists. -// Copies passed `name`, assumes that it is not `none`. -private final function MakeEmptySelection(BaseText name, bool selectedOption) -{ - selectedItemIsOption = selectedOption; - selectedItemName = name.Copy(); - selectedDescription = none; - selectedParameterArray.length = 0; - selectionIsOptional = false; +// Creates an empty selection record for subcommand or option with name (long name) `name`. +// Doe not check whether subcommand/option with that name already exists. +// Copies passed `name`, assumes that it is not `none`. +private final function MakeEmptySelection(BaseText name, bool selectedOption) { + selectedItemIsOption = selectedOption; + selectedItemName = name.Copy(); + selectedDescription = none; + selectedParameterArray.length = 0; + selectionIsOptional = false; } -// Select sub-command with a given name `name` from `subcommands`. -// If there is no command with specified name `name` in prepared data - -// creates new record in selection, otherwise copies previously saved data. -// Automatically saves previously selected data into prepared data. -// Copies `name` if it has to create new record. -private final function SelectSubCommand(BaseText name) -{ - local int subcommandIndex; +// Select option with a given long name `longName` from `options`. +// If there is no option with specified `longName` in prepared data - creates new record in +// selection, otherwise copies previously saved data. +// Automatically saves previously selected data into prepared data. +// Copies `name` if it has to create new record. +private final function SelectOption(BaseText longName) { + local int optionIndex; - if (name == none) return; - if ( !selectedItemIsOption && selectedItemName != none - && selectedItemName.Compare(name)) - { - return; - } - RecordSelection(); - subcommandIndex = FindSubCommandIndex(name); - if (subcommandIndex < 0) - { - MakeEmptySelection(name, false); + if (longName == none) { return; } - // Load appropriate prepared data, if it exists for - // sub-command with name `name` - selectedItemIsOption = false; - selectedItemName = subcommands[subcommandIndex].name; - selectedDescription = subcommands[subcommandIndex].description; - selectionIsOptional = subcommandsIsOptional[subcommandIndex] > 0; - if (selectionIsOptional) { - selectedParameterArray = subcommands[subcommandIndex].optional; - } - else { - selectedParameterArray = subcommands[subcommandIndex].required; - } -} - -// Select option with a given long name `longName` from `options`. -// If there is no option with specified `longName` in prepared data - -// creates new record in selection, otherwise copies previously saved data. -// Automatically saves previously selected data into prepared data. -// Copies `name` if it has to create new record. -private final function SelectOption(BaseText longName) -{ - local int optionIndex; - - if (longName == none) return; - if ( selectedItemIsOption && selectedItemName != none - && selectedItemName.Compare(longName)) - { + if (selectedItemIsOption && selectedItemName != none && selectedItemName.Compare(longName)) { return; } RecordSelection(); optionIndex = FindOptionIndex(longName); - if (optionIndex < 0) - { + if (optionIndex < 0) { MakeEmptySelection(longName, true); return; } - // Load appropriate prepared data, if it exists for - // option with long name `longName` - selectedItemIsOption = true; - selectedItemName = options[optionIndex].longName; - selectedDescription = options[optionIndex].description; - selectionIsOptional = optionsIsOptional[optionIndex] > 0; + // Load appropriate prepared data, if it exists for + // option with long name `longName` + selectedItemIsOption = true; + selectedItemName = options[optionIndex].longName; + selectedDescription = options[optionIndex].description; + selectionIsOptional = optionsIsOptional[optionIndex] > 0; if (selectionIsOptional) { selectedParameterArray = options[optionIndex].optional; - } - else { + } else { selectedParameterArray = options[optionIndex].required; } } // Saves currently selected data into prepared data. -private final function RecordSelection() -{ +private final function RecordSelection() { if (selectedItemName == none) { return; } if (selectedItemIsOption) { RecordSelectedOption(); - } - else { + } else { RecordSelectedSubCommand(); } } // Saves selected sub-command into prepared records. // Assumes that command and not an option is selected. -private final function RecordSelectedSubCommand() -{ - local int selectedSubCommandIndex; - local Command.SubCommand newSubcommand; - - if (selectedItemName == none) return; +private final function RecordSelectedSubCommand() { + local int selectedSubCommandIndex; + local Command.SubCommand newSubcommand; + if (selectedItemName == none) { + return; + } selectedSubCommandIndex = FindSubCommandIndex(selectedItemName); - if (selectedSubCommandIndex < 0) - { + if (selectedSubCommandIndex < 0) { selectedSubCommandIndex = subcommands.length; subcommands[selectedSubCommandIndex] = newSubcommand; } - subcommands[selectedSubCommandIndex].name = selectedItemName; - subcommands[selectedSubCommandIndex].description = selectedDescription; - if (selectionIsOptional) - { + subcommands[selectedSubCommandIndex].name = selectedItemName; + subcommands[selectedSubCommandIndex].description = selectedDescription; + if (selectionIsOptional) { subcommands[selectedSubCommandIndex].optional = selectedParameterArray; subcommandsIsOptional[selectedSubCommandIndex] = 1; - } - else - { + } else { subcommands[selectedSubCommandIndex].required = selectedParameterArray; subcommandsIsOptional[selectedSubCommandIndex] = 0; } } -// Saves currently selected option into prepared records. -// Assumes that option and not an command is selected. -private final function RecordSelectedOption() -{ - local int selectedOptionIndex; - local Command.Option newOption; - - if (selectedItemName == none) return; +// Saves currently selected option into prepared records. +// Assumes that option and not an command is selected. +private final function RecordSelectedOption() { + local int selectedOptionIndex; + local Command.Option newOption; + if (selectedItemName == none) { + return; + } selectedOptionIndex = FindOptionIndex(selectedItemName); - if (selectedOptionIndex < 0) - { + if (selectedOptionIndex < 0) { selectedOptionIndex = options.length; options[selectedOptionIndex] = newOption; } - options[selectedOptionIndex].longName = selectedItemName; - options[selectedOptionIndex].description = selectedDescription; - if (selectionIsOptional) - { + options[selectedOptionIndex].longName = selectedItemName; + options[selectedOptionIndex].description = selectedDescription; + if (selectionIsOptional) { options[selectedOptionIndex].optional = selectedParameterArray; optionsIsOptional[selectedOptionIndex] = 1; - } - else - { + } else { options[selectedOptionIndex].required = selectedParameterArray; optionsIsOptional[selectedOptionIndex] = 0; } } -/** - * Method to use to start defining a new sub-command. - * - * Does two things: - * 1. Creates new sub-command with a given name (if it's missing); - * 2. Selects sub-command with name `name` to add parameters to. - * - * @param name Name of the sub-command user wants to define, - * case-sensitive. Variable will be copied. - * If `none` is passed, this method will do nothing. - * @return Returns the caller `CommandDataBuilder` to allow for - * method chaining. - */ -public final function CommandDataBuilder SubCommand(BaseText name) -{ - SelectSubCommand(name); - return self; -} // Validates names (printing errors in case of failure) for the option. // Long name must be at least 2 characters long. @@ -333,14 +240,13 @@ public final function CommandDataBuilder SubCommand(BaseText name) // (if `shortName` was used for it - it's value will be copied). private final function BaseText.Character GetValidShortName( BaseText longName, - BaseText shortName) -{ + BaseText shortName +) { // Validate `longName` if (longName == none) { return _.text.GetInvalidCharacter(); } - if (longName.GetLength() < 2) - { + if (longName.GetLength() < 2) { _.logger.Auto(errLongNameTooShort).ArgClass(class).Arg(longName.Copy()); return _.text.GetInvalidCharacter(); } @@ -349,8 +255,7 @@ private final function BaseText.Character GetValidShortName( if (shortName == none) { return longName.GetCharacter(0); } - if (shortName.IsEmpty() || shortName.GetLength() > 1) - { + if (shortName.IsEmpty() || shortName.GetLength() > 1) { _.logger.Auto(errShortNameTooLong).ArgClass(class).Arg(longName.Copy()); return _.text.GetInvalidCharacter(); } @@ -363,780 +268,596 @@ private final function BaseText.Character GetValidShortName( // i.e. we cannot have several options with identical names: // (--silent, -s) and (--sick, -s). private final function bool VerifyNoOptionNamingConflict( - BaseText longName, - BaseText.Character shortName) -{ + BaseText longName, + BaseText.Character shortName +) { local int i; + local bool sameShortNames, sameLongNames; // To make sure we will search through the up-to-date `options`, // record selection into prepared records. RecordSelection(); - for (i = 0; i < options.length; i += 1) - { - // Is same long name, but different long names? - if ( !_.text.AreEqual(shortName, options[i].shortName) - && longName.Compare(options[i].longName)) - { - _.logger.Auto(warnSameLongName) - .ArgClass(class) - .Arg(longName.Copy()); + for (i = 0; i < options.length; i += 1) { + sameShortNames = _.text.AreEqual(shortName, options[i].shortName); + sameLongNames = longName.Compare(options[i].longName); + if (sameLongNames && !sameShortNames) { + _.logger.Auto(warnSameLongName).ArgClass(class).Arg(longName.Copy()); return true; } - // Is same short name, but different short ones? - if ( _.text.AreEqual(shortName, options[i].shortName) - && !longName.Compare(options[i].longName)) - { - _.logger.Auto(warnSameLongName) - .ArgClass(class) - .Arg(_.text.FromCharacter(shortName)); + if (!sameLongNames && sameShortNames) { + _.logger.Auto(warnSameLongName).ArgClass(class).Arg(_.text.FromCharacter(shortName)); return true; } } return false; } -/** - * Method to use to start defining a new option. - * - * Does three things: - * 1. Checks if some of the recorded options are in conflict with given - * `longName` and `shortName` (already using one and only one of them). - * 2. Creates new option with a long and short names - * (if such option is missing); - * 3. Selects option with a long name `longName` to add parameters to. - * - * @param longName Long name of the option, case-sensitive - * (for using an option in form "--..."). - * Must be at least two characters long. If passed value is either `none` - * or too short, method will log an error and omits this option. - * @param shortName Short name of the option, case-sensitive - * (for using an option in form "-..."). - * Must be exactly one character. If `none` value is passed - * (or the argument altogether omitted) - uses first character of - * the `longName`. - * If `shortName` is not `none` and is not exactly 1 character long - - * logs an error and omits this option. - * @return Returns the caller `CommandDataBuilder` to allow for - * method chaining. - */ -public final function CommandDataBuilder Option( - BaseText longName, - optional BaseText shortName) -{ +/// Method that starts defining a new sub-command. +/// +/// Creates new sub-command with a given name (if it's missing) and then selects sub-command with +/// a given name to add parameters to. +/// +/// [`name`] defines name of the sub-command user wants, case-sensitive. +/// If `none` is passed, this method will do nothing. +public final function SubCommand(BaseText name) { + local int subcommandIndex; + + if (name == none) { + return; + } + if (!selectedItemIsOption && selectedItemName != none && selectedItemName.Compare(name)) { + return; + } + RecordSelection(); + subcommandIndex = FindSubCommandIndex(name); + if (subcommandIndex < 0) { + MakeEmptySelection(name, false); + return; + } + // Load appropriate prepared data, if it exists for + // sub-command with name `name` + selectedItemIsOption = false; + selectedItemName = subcommands[subcommandIndex].name; + selectedDescription = subcommands[subcommandIndex].description; + selectionIsOptional = subcommandsIsOptional[subcommandIndex] > 0; + if (selectionIsOptional) { + selectedParameterArray = subcommands[subcommandIndex].optional; + } else { + selectedParameterArray = subcommands[subcommandIndex].required; + } +} + +/// Method that starts defining a new option. +/// +/// This method checks if some of the recorded options are in conflict with given `longName` and +/// `shortName` (already using one and only one of them). +/// In case there is no conflict, it creates new option with specified long and short names +/// (if such option is missing) and selects option with a long name `longName` to add parameters to. +/// +/// [`longName`] defines long name of the option, case-sensitive (for using an option in form +/// "--..."). Must be at least two characters long. +/// [`shortName`] defines short name of the option, case-sensitive (for using an option in form +/// "-..."). Must be exactly one character. +/// +/// # Errors +/// +/// Errors will be logged in case either of arguments are `none`, have inappropriate length or are +/// in conflict with each other. +public final function Option(BaseText longName, optional BaseText shortName) { local int optionIndex; local BaseText.Character shortNameAsCharacter; - // Unlike for `SubCommand()`, we need to ensure that option naming is - // correct and does not conflict with existing options - // (user might attempt to add two options with same long names and - // different short ones). + // Unlike for `SubCommand()`, we need to ensure that option naming is + // correct and does not conflict with existing options + // (user might attempt to add two options with same long names and + // different short ones). shortNameAsCharacter = GetValidShortName(longName, shortName); if ( !_.text.IsValidCharacter(shortNameAsCharacter) - || VerifyNoOptionNamingConflict(longName, shortNameAsCharacter)) - { + || VerifyNoOptionNamingConflict(longName, shortNameAsCharacter)) { // ^ `GetValidShortName()` and `VerifyNoOptionNamingConflict()` // are responsible for logging warnings/errors - return self; + return; } SelectOption(longName); // Set short name for new options optionIndex = FindOptionIndex(longName); - if (optionIndex < 0) - { + if (optionIndex < 0) { // We can only be here if option was created for the first time RecordSelection(); // So now it cannot fail optionIndex = FindOptionIndex(longName); options[optionIndex].shortName = shortNameAsCharacter; } - return self; } -/** - * Adds description to the selected sub-command / option. - * - * Previous description is discarded (default description is empty). - * - * Does nothing if nothing is selected. - * - * @param description New description of selected sub-command / option. - * Variable will be copied. - * @return Returns the caller `CommandDataBuilder` to allow for - * method chaining. - */ -public final function CommandDataBuilder Describe(BaseText description) -{ - if (selectedDescription == description) { - return self; - } +/// Adds description to the selected sub-command / option. +/// +/// Does nothing if nothing is yet selected. +public final function Describe(BaseText description) { _.memory.Free(selectedDescription); if (description != none) { selectedDescription = description.Copy(); } - return self; } -/** - * Sets new name of `Command.Data` under construction. This is a name that will - * be used unless Acedia is configured to do otherwise. - * - * @return Returns the caller `CommandDataBuilder` to allow for - * method chaining. - */ -public final function CommandDataBuilder Name(BaseText newName) -{ +/// Sets new name of the command that caller [`CommandDataBuilder`] constructs. +public final function Name(BaseText newName) { if (newName != none && newName == commandName) { - return self; + return; } _.memory.Free(commandName); if (newName != none) { commandName = newName.Copy(); - } - else { + } else { commandName = none; } - return self; } -/** - * Sets new group of `Command.Data` under construction. Group name is meant to - * be shared among several commands, allowing user to filter or fetch commands - * of a certain group. - * - * @return Returns the caller `CommandDataBuilder` to allow for - * method chaining. - */ -public final function CommandDataBuilder Group(BaseText newName) -{ +/// Sets new group of `Command.Data` under construction. +/// +/// Group name is meant to be shared among several commands, allowing user to filter or +/// fetch commands of a certain group. +public final function Group(BaseText newName) { if (newName != none && newName == commandGroup) { - return self; + return; } _.memory.Free(commandGroup); if (newName != none) { commandGroup = newName.Copy(); - } - else { + } else { commandGroup = none; } - return self; } -/** - * Sets new summary of `Command.Data` under construction. Summary gives a short - * description of the command on the whole, to be displayed in a command list. - * - * @return Returns the caller `CommandDataBuilder` to allow for - * method chaining. - */ -public final function CommandDataBuilder Summary(BaseText newSummary) -{ +/// Sets new summary of `Command.Data` under construction. +/// +/// Summary gives a short description of the command on the whole that will displayed when "help" +/// command is listing available command +public final function Summary(BaseText newSummary) { if (newSummary != none && newSummary == commandSummary) { - return self; + return; } _.memory.Free(commandSummary); if (newSummary != none) { commandSummary = newSummary.Copy(); - } - else { + } else { commandSummary = none; } - return self; } -/** - * Makes caller builder to mark `Command.Data` under construction to require - * a player target. - * - * @return Returns the caller `CommandDataBuilder` to allow for - * method chaining. - */ -public final function CommandDataBuilder RequireTarget() -{ +/// Makes caller builder to mark `Command.Data` under construction to require a player target. +public final function RequireTarget() { requiresTarget = true; - return self; } -/** - * Any parameters added to currently selected sub-command / option after - * calling this method will be marked as optional. - * - * Further calls when the same sub-command / option is selected do nothing. - * - * @return Returns the caller `CommandDataBuilder` to allow for - * method chaining. - */ -public final function CommandDataBuilder OptionalParams() + +/// Any parameters added to currently selected sub-command / option after calling this method will +/// be marked as optional. +/// +/// Further calls when the same sub-command / option is selected will do nothing. +public final function OptionalParams() { if (selectionIsOptional) { - return self; + return; } // Record all required parameters first, otherwise there would be no way // to distinguish between them and optional parameters RecordSelection(); selectionIsOptional = true; selectedParameterArray.length = 0; - return self; } -/** - * Returns data that has been constructed so far by - * the caller `CommandDataBuilder`. - * - * Does not reset progress. - * - * @return Returns the caller `CommandDataBuilder` to allow for - * method chaining. - */ -public final function Command.Data BorrowData() -{ +/// Returns data that has been constructed so far by the caller [`CommandDataBuilder`]. +/// +/// Does not reset progress. +public final function Command.Data BorrowData() { local Command.Data newData; RecordSelection(); - newData.name = commandName; - newData.group = commandGroup; - newData.summary = commandSummary; - newData.subcommands = subcommands; - newData.options = options; - newData.requiresTarget = requiresTarget; + newData.name = commandName; + newData.group = commandGroup; + newData.summary = commandSummary; + newData.subcommands = subcommands; + newData.options = options; + newData.requiresTarget = requiresTarget; return newData; } -// Adds new parameter to selected sub-command / option -private final function PushParameter(Command.Parameter newParameter) -{ +// Adds new parameter to selected sub-command / option +private final function PushParameter(Command.Parameter newParameter) { selectedParameterArray[selectedParameterArray.length] = newParameter; } -// Fills `Command.ParameterType` struct with given values -// (except boolean format). Assumes `displayName != none`. +// Fills `Command.ParameterType` struct with given values (except boolean format). +// Assumes `displayName != none`. private final function Command.Parameter NewParameter( - BaseText displayName, - Command.ParameterType parameterType, - bool isListParameter, - optional BaseText variableName) -{ + BaseText displayName, + Command.ParameterType parameterType, + bool isListParameter, + optional BaseText variableName +) { local Command.Parameter newParameter; - newParameter.displayName = displayName.Copy(); - newParameter.type = parameterType; - newParameter.allowsList = isListParameter; + newParameter.displayName = displayName.Copy(); + newParameter.type = parameterType; + newParameter.allowsList = isListParameter; if (variableName != none) { newParameter.variableName = variableName.Copy(); - } - else { + } else { newParameter.variableName = displayName.Copy(); } return newParameter; } -/** - * Adds new boolean parameter (required or optional depends on whether - * `RequireTarget()` call happened) to the currently selected - * sub-command / option. - * - * Only fails if provided `name` is `none`. - * - * @param name Name of the parameter, will be copied - * (as it would appear in the generated help info). - * - * @param format Preferred format of boolean values. - * Command parser will still accept boolean values in any form, - * this setting only affects how parameter will be displayed in - * generated help. - * @param variableName Name of the variable that will store this - * parameter's value in `HashTable` after user's command input - * is parsed. Provided value will be copied. - * If left `none`, - will coincide with `name` parameter. - * @return Returns the caller `CommandDataBuilder` to allow for - * method chaining. - */ -public final function CommandDataBuilder ParamBoolean( - BaseText name, +/// Adds new boolean parameter (required or optional depends on whether `OptionalParams()` call +/// happened) to the currently selected sub-command / option. +/// +/// Only fails if provided `name` is `none`. +/// +/// [`name`] will become the name of the parameter +/// (it would appear in the generated "help" command info). +/// +/// [`format`] defines preferred format of boolean values. +/// Command parser will still accept boolean values in any form, this setting only affects how +/// parameter will be displayed in generated help. +/// +/// [`variableName`] will become key for this parameter's value in `HashTable` after user's command +/// input is parsed. +/// If left `none`, - will coincide with `name` parameter. +public final function ParamBoolean( + BaseText name, optional Command.PreferredBooleanFormat format, - optional BaseText variableName) -{ + optional BaseText variableName +) { local Command.Parameter newParam; - if (name == none) { - return self; - } - newParam = NewParameter(name, CPT_Boolean, false, variableName); - newParam.booleanFormat = format; - PushParameter(newParam); - return self; -} - -/** - * Adds new boolean list parameter (required or optional depends on whether - * `RequireTarget()` call happened) to the currently selected - * sub-command / option. - * - * Only fails if provided `name` is `none`. - * - * @param name Name of the parameter, will be copied - * (as it would appear in the generated help info). - * @param format Preferred format of boolean values. - * Command parser will still accept boolean values in any form, - * this setting only affects how parameter will be displayed in - * generated help. - * @param variableName Name of the variable that will store this - * parameter's value in `HashTable` after user's command input - * is parsed. Provided value will be copied. - * If left `none`, - will coincide with `name` parameter. - * @return Returns the caller `CommandDataBuilder` to allow for - * method chaining. - */ -public final function CommandDataBuilder ParamBooleanList( - BaseText name, + if (name != none) { + newParam = NewParameter(name, CPT_Boolean, false, variableName); + newParam.booleanFormat = format; + PushParameter(newParam); + } +} + +/// Adds new integer list parameter (required or optional depends on whether `OptionalParams()` +/// call happened) to the currently selected sub-command / option. +/// +/// Only fails if provided `name` is `none`. +/// +/// List parameters expect user to enter one or more value of the same type as command's arguments. +/// +/// [`name`] will become the name of the parameter +/// (it would appear in the generated "help" command info). +/// +/// [`format`] defines preferred format of boolean values. +/// Command parser will still accept boolean values in any form, this setting only affects how +/// parameter will be displayed in generated help. +/// +/// [`variableName`] will become key for this parameter's value in `HashTable` after user's command +/// input is parsed. +/// If left `none`, - will coincide with `name` parameter. +public final function ParamBooleanList( + BaseText name, optional Command.PreferredBooleanFormat format, - optional BaseText variableName) -{ + optional BaseText variableName +) { local Command.Parameter newParam; - if (name == none) { - return self; - } - newParam = NewParameter(name, CPT_Boolean, true, variableName); - newParam.booleanFormat = format; - PushParameter(newParam); - return self; -} - -/** - * Adds new integer parameter (required or optional depends on whether - * `RequireTarget()` call happened) to the currently selected - * sub-command / option. - * - * Only fails if provided `name` is `none`. - * - * @param name Name of the parameter, will be copied - * (as it would appear in the generated help info). - * @param variableName Name of the variable that will store this - * parameter's value in `HashTable` after user's command input - * is parsed. Provided value will be copied. - * If left `none`, - will coincide with `name` parameter. - * @return Returns the caller `CommandDataBuilder` to allow for - * method chaining. - */ -public final function CommandDataBuilder ParamInteger( - BaseText name, - optional BaseText variableName) -{ - if (name == none) { - return self; - } - PushParameter(NewParameter(name, CPT_Integer, false, variableName)); - return self; -} - -/** - * Adds new integer list parameter (required or optional depends on whether - * `RequireTarget()` call happened) to the currently selected - * sub-command / option. - * - * Only fails if provided `name` is `none`. - * - * @param name Name of the parameter, will be copied - * (as it would appear in the generated help info). - * @param variableName Name of the variable that will store this - * parameter's value in `HashTable` after user's command input - * is parsed. Provided value will be copied. - * If left `none`, - will coincide with `name` parameter. - * @return Returns the caller `CommandDataBuilder` to allow for - * method chaining. - */ -public final function CommandDataBuilder ParamIntegerList( - BaseText name, - optional BaseText variableName) -{ - if (name == none) { - return self; - } - PushParameter(NewParameter(name, CPT_Integer, true, variableName)); - return self; -} - -/** - * Adds new numeric parameter (required or optional depends on whether - * `RequireTarget()` call happened) to the currently selected - * sub-command / option. - * - * Only fails if provided `name` is `none`. - * - * @param name Name of the parameter, will be copied - * (as it would appear in the generated help info). - * @param variableName Name of the variable that will store this - * parameter's value in `HashTable` after user's command input - * is parsed. Provided value will be copied. - * If left `none`, - will coincide with `name` parameter. - * @return Returns the caller `CommandDataBuilder` to allow for - * method chaining. - */ -public final function CommandDataBuilder ParamNumber( - BaseText name, - optional BaseText variableName) -{ - if (name == none) { - return self; - } - PushParameter(NewParameter(name, CPT_Number, false, variableName)); - return self; -} - -/** - * Adds new numeric list parameter (required or optional depends on whether - * `RequireTarget()` call happened) to the currently selected - * sub-command / option. - * - * Only fails if provided `name` is `none`. - * - * @param name Name of the parameter, will be copied - * (as it would appear in the generated help info). - * @param variableName Name of the variable that will store this - * parameter's value in `HashTable` after user's command input - * is parsed. Provided value will be copied. - * If left `none`, - will coincide with `name` parameter. - * @return Returns the caller `CommandDataBuilder` to allow for - * method chaining. - */ -public final function CommandDataBuilder ParamNumberList( - BaseText name, - optional BaseText variableName) -{ - if (name == none) { - return self; - } - PushParameter(NewParameter(name, CPT_Number, true, variableName)); - return self; -} - -/** - * Adds new text parameter (required or optional depends on whether - * `RequireTarget()` call happened) to the currently selected - * sub-command / option. - * - * Only fails if provided `name` is `none`. - * - * @param name Name of the parameter, will be copied - * (as it would appear in the generated help info). - * @param variableName Name of the variable that will store this - * parameter's value in `HashTable` after user's command input - * is parsed. Provided value will be copied. - * If left `none`, - will coincide with `name` parameter. - * @param aliasSourceName Name of the alias source that must be used to - * auto-resolve this parameter's value. `none` means that parameter will be - * recorded as-is, any other value (either "weapon", "color", "feature", - * "entity" or some kind of custom alias source name) will make values - * prefixed with "$" to be resolved as aliases. - * @return Returns the caller `CommandDataBuilder` to allow for - * method chaining. - */ -public final function CommandDataBuilder ParamText( - BaseText name, - optional BaseText variableName, - optional BaseText aliasSourceName) -{ + if (name != none) { + newParam = NewParameter(name, CPT_Boolean, true, variableName); + newParam.booleanFormat = format; + PushParameter(newParam); + } +} + +/// Adds new integer parameter (required or optional depends on whether `OptionalParams()` call +/// happened) to the currently selected sub-command / option. +/// +/// Only fails if provided `name` is `none`. +/// +/// [`name`] will become the name of the parameter +/// (it would appear in the generated "help" command info). +/// +/// [`variableName`] will become key for this parameter's value in `HashTable` after user's command +/// input is parsed. +/// If left `none`, - will coincide with `name` parameter. +public final function ParamInteger(BaseText name, optional BaseText variableName) { + if (name != none) { + PushParameter(NewParameter(name, CPT_Integer, false, variableName)); + } +} + +/// Adds new integer list parameter (required or optional depends on whether `OptionalParams()` +/// call happened) to the currently selected sub-command / option. +/// +/// Only fails if provided `name` is `none`. +/// +/// List parameters expect user to enter one or more value of the same type as command's arguments. +/// +/// [`name`] will become the name of the parameter +/// (it would appear in the generated "help" command info). +/// +/// [`variableName`] will become key for this parameter's value in `HashTable` after user's command +/// input is parsed. +/// If left `none`, - will coincide with `name` parameter. +public final function ParamIntegerList(BaseText name, optional BaseText variableName) { + if (name != none) { + PushParameter(NewParameter(name, CPT_Integer, true, variableName)); + } +} + +/// Adds new numeric parameter (required or optional depends on whether `OptionalParams()` call +/// happened) to the currently selected sub-command / option. +/// +/// Only fails if provided `name` is `none`. +/// +/// [`name`] will become the name of the parameter +/// (it would appear in the generated "help" command info). +/// +/// [`variableName`] will become key for this parameter's value in `HashTable` after user's command +/// input is parsed. +/// If left `none`, - will coincide with `name` parameter. +public final function ParamNumber(BaseText name, optional BaseText variableName) { + if (name != none) { + PushParameter(NewParameter(name, CPT_Number, false, variableName)); + } +} + +/// Adds new numeric list parameter (required or optional depends on whether `OptionalParams()` +/// call happened) to the currently selected sub-command / option. +/// +/// Only fails if provided `name` is `none`. +/// +/// List parameters expect user to enter one or more value of the same type as command's arguments. +/// +/// [`name`] will become the name of the parameter +/// (it would appear in the generated "help" command info). +/// +/// [`variableName`] will become key for this parameter's value in `HashTable` after user's command +/// input is parsed. +/// If left `none`, - will coincide with `name` parameter. +public final function ParamNumberList(BaseText name, optional BaseText variableName) { + if (name != none) { + PushParameter(NewParameter(name, CPT_Number, true, variableName)); + } +} + +/// Adds new text parameter (required or optional depends on whether `OptionalParams()` call +/// happened) to the currently selected sub-command / option. +/// +/// Only fails if provided `name` is `none`. +/// +/// [`name`] will become the name of the parameter +/// (it would appear in the generated "help" command info). +/// +/// [`variableName`] will become key for this parameter's value in `HashTable` after user's command +/// input is parsed. +/// If left `none`, - will coincide with `name` parameter. +/// +/// [`aliasSourceName`] defines name of the alias source that must be used to auto-resolve this +/// parameter's value. `none` means that parameter will be recorded as-is, any other value +/// (either "weapon", "color", "feature", "entity" or some kind of custom alias source name) will +/// make values prefixed with "$" to be resolved as custom aliases. +public final function ParamText( + BaseText name, + optional BaseText variableName, + optional BaseText aliasSourceName +) { local Command.Parameter newParameterValue; if (name == none) { - return self; + return; } newParameterValue = NewParameter(name, CPT_Text, false, variableName); if (aliasSourceName != none) { newParameterValue.aliasSourceName = aliasSourceName.Copy(); } PushParameter(newParameterValue); - return self; } -/** - * Adds new text list parameter (required or optional depends on whether - * `RequireTarget()` call happened) to the currently selected - * sub-command / option. - * - * Only fails if provided `name` is `none`. - * - * @param name Name of the parameter, will be copied - * (as it would appear in the generated help info). - * @param variableName Name of the variable that will store this - * parameter's value in `HashTable` after user's command input - * is parsed. Provided value will be copied. - * If left `none`, - will coincide with `name` parameter. - * @param aliasSource Name of the alias source that must be used to - * auto-resolve this parameter's value. `none` means that parameter will be - * recorded as-is, any other value (either "weapon", "color", "feature", - * "entity" or some kind of custom alias source name) will make values - * prefixed with "$" to be resolved as aliases. - * @return Returns the caller `CommandDataBuilder` to allow for - * method chaining. - */ -public final function CommandDataBuilder ParamTextList( - BaseText name, - optional BaseText variableName, - optional BaseText aliasSourceName) -{ +/// Adds new text list parameter (required or optional depends on whether `OptionalParams()` call +/// happened) to the currently selected sub-command / option. +/// +/// Only fails if provided `name` is `none`. +/// +/// List parameters expect user to enter one or more value of the same type as command's arguments. +/// +/// [`name`] will become the name of the parameter +/// (it would appear in the generated "help" command info). +/// +/// [`variableName`] will become key for this parameter's value in `HashTable` after user's command +/// input is parsed. +/// If left `none`, - will coincide with `name` parameter. +/// +/// [`aliasSourceName`] defines name of the alias source that must be used to auto-resolve this +/// parameter's value. `none` means that parameter will be recorded as-is, any other value +/// (either "weapon", "color", "feature", "entity" or some kind of custom alias source name) will +/// make values prefixed with "$" to be resolved as custom aliases. +public final function ParamTextList( + BaseText name, + optional BaseText variableName, + optional BaseText aliasSourceName +) { local Command.Parameter newParameterValue; if (name == none) { - return self; + return; } newParameterValue = NewParameter(name, CPT_Text, true, variableName); if (aliasSourceName != none) { newParameterValue.aliasSourceName = aliasSourceName.Copy(); } PushParameter(newParameterValue); - return self; -} - -/** - * Adds new remainder parameter (required or optional depends on whether - * `RequireTarget()` call happened) to the currently selected - * sub-command / option. - * - * Only fails if provided `name` is `none`. - * - * @param name Name of the parameter, will be copied - * (as it would appear in the generated help info). - * @param variableName Name of the variable that will store this - * parameter's value in `HashTable` after user's command input - * is parsed. Provided value will be copied. - * If left `none`, - will coincide with `name` parameter. - * @return Returns the caller `CommandDataBuilder` to allow for - * method chaining. - */ -public final function CommandDataBuilder ParamRemainder( - BaseText name, - optional BaseText variableName) -{ - if (name == none) { - return self; - } - PushParameter(NewParameter(name, CPT_Remainder, false, variableName)); - return self; -} - -/** - * Adds new object parameter (required or optional depends on whether - * `RequireTarget()` call happened) to the currently selected - * sub-command / option. - * - * Only fails if provided `name` is `none`. - * - * @param name Name of the parameter, will be copied - * (as it would appear in the generated help info). - * @param variableName Name of the variable that will store this - * parameter's value in `HashTable` after user's command input - * is parsed. Provided value will be copied. - * If left `none`, - will coincide with `name` parameter. - * @return Returns the caller `CommandDataBuilder` to allow for - * method chaining. - */ -public final function CommandDataBuilder ParamObject( - BaseText name, - optional BaseText variableName) -{ - if (name == none) { - return self; - } - PushParameter(NewParameter(name, CPT_Object, false, variableName)); - return self; -} - -/** - * Adds new parameter for list of objects (required or optional depends on - * whether `RequireTarget()` call happened) to the currently selected - * sub-command / option. - * - * Only fails if provided `name` is `none`. - * - * @param name Name of the parameter, will be copied - * (as it would appear in the generated help info). - * @param variableName Name of the variable that will store this - * parameter's value in `HashTable` after user's command input - * is parsed. Provided value will be copied. - * If left `none`, - will coincide with `name` parameter. - * @return Returns the caller `CommandDataBuilder` to allow for - * method chaining. - */ -public final function CommandDataBuilder ParamObjectList( - BaseText name, - optional BaseText variableName) -{ - if (name == none) { - return self; - } - PushParameter(NewParameter(name, CPT_Object, true, variableName)); - return self; -} - -/** - * Adds new array parameter (required or optional depends on whether - * `RequireTarget()` call happened) to the currently selected - * sub-command / option. - * - * Only fails if provided `name` is `none`. - * - * @param name Name of the parameter, will be copied - * (as it would appear in the generated help info). - * @param variableName Name of the variable that will store this - * parameter's value in `HashTable` after user's command input - * is parsed. Provided value will be copied. - * If left `none`, - will coincide with `name` parameter. - * @return Returns the caller `CommandDataBuilder` to allow for - * method chaining. - */ -public final function CommandDataBuilder ParamArray( - BaseText name, - optional BaseText variableName) -{ - if (name == none) { - return self; - } - PushParameter(NewParameter(name, CPT_Array, false, variableName)); - return self; -} - -/** - * Adds new parameter for list of arrays (required or optional depends on - * whether `RequireTarget()` call happened) to the currently selected - * sub-command / option. - * - * Only fails if provided `name` is `none`. - * - * @param name Name of the parameter, will be copied - * (as it would appear in the generated help info). - * @param variableName Name of the variable that will store this - * parameter's value in `HashTable` after user's command input - * is parsed. Provided value will be copied. - * If left `none`, - will coincide with `name` parameter. - * @return Returns the caller `CommandDataBuilder` to allow for - * method chaining. - */ -public final function CommandDataBuilder ParamArrayList( - BaseText name, - optional BaseText variableName) -{ - if (name == none) { - return self; - } - PushParameter(NewParameter(name, CPT_Array, true, variableName)); - return self; } -/** - * Adds new JSON value parameter (required or optional depends on whether - * `RequireTarget()` call happened) to the currently selected - * sub-command / option. - * - * Only fails if provided `name` is `none`. - * - * @param name Name of the parameter, will be copied - * (as it would appear in the generated help info). - * @param variableName Name of the variable that will store this - * parameter's value in `HashTable` after user's command input - * is parsed. Provided value will be copied. - * If left `none`, - will coincide with `name` parameter. - * @return Returns the caller `CommandDataBuilder` to allow for - * method chaining. - */ -public final function CommandDataBuilder ParamJSON( - BaseText name, - optional BaseText variableName) -{ - if (name == none) { - return self; - } - PushParameter(NewParameter(name, CPT_JSON, false, variableName)); - return self; -} - -/** - * Adds new parameter for list of JSON values (required or optional depends on - * whether `RequireTarget()` call happened) to the currently selected - * sub-command / option. - * - * Only fails if provided `name` is `none`. - * - * @param name Name of the parameter, will be copied - * (as it would appear in the generated help info). - * @param variableName Name of the variable that will store this - * parameter's value in `HashTable` after user's command input - * is parsed. Provided value will be copied. - * If left `none`, - will coincide with `name` parameter. - * @return Returns the caller `CommandDataBuilder` to allow for - * method chaining. - */ -public final function CommandDataBuilder ParamJSONList( - BaseText name, - optional BaseText variableName) -{ - if (name == none) { - return self; - } - PushParameter(NewParameter(name, CPT_JSON, true, variableName)); - return self; -} - -/** - * Adds new players value parameter (required or optional depends on whether - * `RequireTarget()` call happened) to the currently selected - * sub-command / option. - * - * Players parameter is a parameter that allows one to specify a list of - * players through special selectors, the same way one does for - * targeted commands. - * - * Only fails if provided `name` is `none`. - * - * @param name Name of the parameter, will be copied - * (as it would appear in the generated help info). - * @param variableName Name of the variable that will store this - * parameter's value in `HashTable` after user's command input - * is parsed. Provided value will be copied. - * If left `none`, - will coincide with `name` parameter. - * @return Returns the caller `CommandDataBuilder` to allow for - * method chaining. - */ -public final function CommandDataBuilder ParamPlayers( - BaseText name, - optional BaseText variableName) -{ - if (name == none) { - return self; - } - PushParameter(NewParameter(name, CPT_PLAYERS, false, variableName)); - return self; -} - -/** - * Adds new parameter for list of players values (required or optional depends - * on whether `RequireTarget()` call happened) to the currently selected - * sub-command / option. - * - * Players parameter is a parameter that allows one to specify a list of - * players through special selectors, the same way one does for - * targeted commands. - * - * Only fails if provided `name` is `none`. - * - * @param name Name of the parameter, will be copied - * (as it would appear in the generated help info). - * @param variableName Name of the variable that will store this - * parameter's value in `HashTable` after user's command input - * is parsed. Provided value will be copied. - * If left `none`, - will coincide with `name` parameter. - * @return Returns the caller `CommandDataBuilder` to allow for - * method chaining. - */ -public final function CommandDataBuilder ParamPlayersList( - BaseText name, - optional BaseText variableName) -{ - if (name == none) { - return self; +/// Adds new remainder parameter (required or optional depends on whether `OptionalParams()` call +/// happened) to the currently selected sub-command / option. +/// +/// Only fails if provided `name` is `none`. +/// +/// Remainder parameter is a special parameter that will simply consume all remaining command's +/// input as-is. +/// +/// [`name`] will become the name of the parameter +/// (it would appear in the generated "help" command info). +/// +/// [`variableName`] will become key for this parameter's value in `HashTable` after user's command +/// input is parsed. +/// If left `none`, - will coincide with `name` parameter. +public final function ParamRemainder(BaseText name, optional BaseText variableName) { + if (name != none) { + PushParameter(NewParameter(name, CPT_Remainder, false, variableName)); + } +} + +/// Adds new JSON object parameter (required or optional depends on whether `OptionalParams()` call +/// happened) to the currently selected sub-command / option. +/// +/// Only fails if provided `name` is `none`. +/// +/// [`name`] will become the name of the parameter +/// (it would appear in the generated "help" command info). +/// +/// [`variableName`] will become key for this parameter's value in `HashTable` after user's command +/// input is parsed. +/// If left `none`, - will coincide with `name` parameter. +public final function ParamObject(BaseText name, optional BaseText variableName) { + if (name != none) { + PushParameter(NewParameter(name, CPT_Object, false, variableName)); + } +} + +/// Adds new JSON object list parameter (required or optional depends on whether `OptionalParams()` +/// call happened) to the currently selected sub-command / option. +/// +/// Only fails if provided `name` is `none`. +/// +/// List parameters expect user to enter one or more value of the same type as command's arguments. +/// +/// [`name`] will become the name of the parameter +/// (it would appear in the generated "help" command info). +/// +/// [`variableName`] will become key for this parameter's value in `HashTable` after user's command +/// input is parsed. +/// If left `none`, - will coincide with `name` parameter. +public final function ParamObjectList(BaseText name, optional BaseText variableName) { + if (name != none) { + PushParameter(NewParameter(name, CPT_Object, true, variableName)); + } +} + +/// Adds new JSON array parameter (required or optional depends on whether `OptionalParams()` call +/// happened) to the currently selected sub-command / option. +/// +/// Only fails if provided `name` is `none`. +/// +/// [`name`] will become the name of the parameter +/// (it would appear in the generated "help" command info). +/// +/// [`variableName`] will become key for this parameter's value in `HashTable` after user's command +/// input is parsed. +/// If left `none`, - will coincide with `name` parameter. +public final function ParamArray(BaseText name, optional BaseText variableName) { + if (name != none) { + PushParameter(NewParameter(name, CPT_Array, false, variableName)); + } +} + +/// Adds new JSON array list parameter (required or optional depends on whether `OptionalParams()` +/// call happened) to the currently selected sub-command / option. +/// +/// Only fails if provided `name` is `none`. +/// +/// List parameters expect user to enter one or more value of the same type as command's arguments. +/// +/// [`name`] will become the name of the parameter +/// (it would appear in the generated "help" command info). +/// +/// [`variableName`] will become key for this parameter's value in `HashTable` after user's command +/// input is parsed. +/// If left `none`, - will coincide with `name` parameter. +public final function ParamArrayList(BaseText name, optional BaseText variableName) { + if (name != none) { + PushParameter(NewParameter(name, CPT_Array, true, variableName)); + } +} + +/// Adds new JSON value parameter (required or optional depends on whether `OptionalParams()` call +/// happened) to the currently selected sub-command / option. +/// +/// Only fails if provided `name` is `none`. +/// +/// [`name`] will become the name of the parameter +/// (it would appear in the generated "help" command info). +/// +/// [`variableName`] will become key for this parameter's value in `HashTable` after user's command +/// input is parsed. +/// If left `none`, - will coincide with `name` parameter. +public final function ParamJSON(BaseText name, optional BaseText variableName) { + if (name != none) { + PushParameter(NewParameter(name, CPT_JSON, false, variableName)); + } +} + +/// Adds new JSON value list parameter (required or optional depends on whether `OptionalParams()` +/// call happened) to the currently selected sub-command / option. +/// +/// Only fails if provided `name` is `none`. +/// +/// List parameters expect user to enter one or more value of the same type as command's arguments. +/// +/// [`name`] will become the name of the parameter +/// (it would appear in the generated "help" command info). +/// +/// [`variableName`] will become key for this parameter's value in `HashTable` after user's command +/// input is parsed. +/// If left `none`, - will coincide with `name` parameter. +public final function ParamJSONList(BaseText name, optional BaseText variableName) { + if (name != none) { + PushParameter(NewParameter(name, CPT_JSON, true, variableName)); + } +} + + +/// Adds new integer parameter (required or optional depends on whether `OptionalParams()` call +/// happened) to the currently selected sub-command / option. +/// +/// Only fails if provided `name` is `none`. +/// +/// Players parameter is a parameter that allows one to specify a list of players through +/// special selectors, the same way one does for targeted commands. +/// +/// [`name`] will become the name of the parameter +/// (it would appear in the generated "help" command info). +/// +/// [`variableName`] will become key for this parameter's value in `HashTable` after user's command +/// input is parsed. +/// If left `none`, - will coincide with `name` parameter. +public final function ParamPlayers(BaseText name, optional BaseText variableName) { + if (name != none) { + PushParameter(NewParameter(name, CPT_PLAYERS, false, variableName)); + } +} + +/// Adds new integer list parameter (required or optional depends on whether `OptionalParams()` +/// call happened) to the currently selected sub-command / option. +/// +/// Only fails if provided `name` is `none`. +/// +/// Players parameter is a parameter that allows one to specify a list of players through +/// special selectors, the same way one does for targeted commands. +/// +/// List parameters expect user to enter one or more value of the same type as command's arguments. +/// +/// [`name`] will become the name of the parameter +/// (it would appear in the generated "help" command info). +/// +/// [`variableName`] will become key for this parameter's value in `HashTable` after user's command +/// input is parsed. +/// If left `none`, - will coincide with `name` parameter. +public final function ParamPlayersList(BaseText name,optional BaseText variableName) { + if (name != none) { + PushParameter(NewParameter(name, CPT_PLAYERS, true, variableName)); } - PushParameter(NewParameter(name, CPT_PLAYERS, true, variableName)); - return self; } defaultproperties diff --git a/sources/LevelAPI/Features/Commands/Tests/MockCommandA.uc b/sources/LevelAPI/Features/Commands/Tests/MockCommandA.uc index 48bfbc6..630b1d6 100644 --- a/sources/LevelAPI/Features/Commands/Tests/MockCommandA.uc +++ b/sources/LevelAPI/Features/Commands/Tests/MockCommandA.uc @@ -21,16 +21,17 @@ class MockCommandA extends Command; protected function BuildData(CommandDataBuilder builder) { - builder.ParamObject(P("just_obj")) - .ParamArrayList(P("manyLists")) - .OptionalParams() - .ParamObject(P("last_obj")); - builder.SubCommand(P("simple")) - .ParamBooleanList(P("isItSimple?")) - .ParamInteger(P("integer variable"), P("int")) - .OptionalParams() - .ParamNumberList(P("numeric list"), P("list")) - .ParamTextList(P("another list")); + builder.ParamObject(P("just_obj")); + builder.ParamArrayList(P("manyLists")); + builder.OptionalParams(); + builder.ParamObject(P("last_obj")); + + builder.SubCommand(P("simple")); + builder.ParamBooleanList(P("isItSimple?")); + builder.ParamInteger(P("integer variable"), P("int")); + builder.OptionalParams(); + builder.ParamNumberList(P("numeric list"), P("list")); + builder.ParamTextList(P("another list")); } defaultproperties diff --git a/sources/LevelAPI/Features/Commands/Tests/MockCommandB.uc b/sources/LevelAPI/Features/Commands/Tests/MockCommandB.uc index 49b6896..7f27fdc 100644 --- a/sources/LevelAPI/Features/Commands/Tests/MockCommandB.uc +++ b/sources/LevelAPI/Features/Commands/Tests/MockCommandB.uc @@ -21,31 +21,39 @@ class MockCommandB extends Command; protected function BuildData(CommandDataBuilder builder) { - builder.ParamArray(P("just_array")) - .ParamText(P("just_text")); - builder.Option(P("values")) - .ParamIntegerList(P("types")); - builder.Option(P("long")) - .ParamInteger(P("num")) - .ParamNumberList(P("text")) - .ParamBoolean(P("huh")); - builder.Option(P("type"), P("t")) - .ParamText(P("type")); - builder.Option(P("Test")) - .ParamText(P("to_test")); - builder.Option(P("silent")) - .Option(P("forced")) - .Option(P("verbose"), P("V")) - .Option(P("actual")); - builder.SubCommand(P("do")) - .OptionalParams() - .ParamNumberList(P("numeric list"), P("list")) - .ParamBoolean(P("maybe")); - builder.Option(P("remainder")) - .ParamRemainder(P("everything")); - builder.SubCommand(P("json")) - .ParamJSON(P("first_json")) - .ParamJSONList(P("other_json")); + builder.ParamArray(P("just_array")); + builder.ParamText(P("just_text")); + + builder.Option(P("values")); + builder.ParamIntegerList(P("types")); + + builder.Option(P("long")); + builder.ParamInteger(P("num")); + builder.ParamNumberList(P("text")); + builder.ParamBoolean(P("huh")); + + builder.Option(P("type"), P("t")); + builder.ParamText(P("type")); + + builder.Option(P("Test")); + builder.ParamText(P("to_test")); + + builder.Option(P("silent")); + builder.Option(P("forced")); + builder.Option(P("verbose"), P("V")); + builder.Option(P("actual")); + + builder.SubCommand(P("do")); + builder.OptionalParams(); + builder.ParamNumberList(P("numeric list"), P("list")); + builder.ParamBoolean(P("maybe")); + + builder.Option(P("remainder")); + builder.ParamRemainder(P("everything")); + + builder.SubCommand(P("json")); + builder.ParamJSON(P("first_json")); + builder.ParamJSONList(P("other_json")); } defaultproperties diff --git a/sources/LevelAPI/Features/Commands/Tests/TEST_CommandDataBuilder.uc b/sources/LevelAPI/Features/Commands/Tests/TEST_CommandDataBuilder.uc index a573e52..1494e46 100644 --- a/sources/LevelAPI/Features/Commands/Tests/TEST_CommandDataBuilder.uc +++ b/sources/LevelAPI/Features/Commands/Tests/TEST_CommandDataBuilder.uc @@ -24,27 +24,33 @@ class TEST_CommandDataBuilder extends TestCase protected static function CommandDataBuilder PrepareBuilder() { local CommandDataBuilder builder; - builder = - CommandDataBuilder(__().memory.Allocate(class'CommandDataBuilder')); - builder.ParamNumber(P("var")).ParamText(P("str_var"), P("otherName")); + builder = CommandDataBuilder(__().memory.Allocate(class'CommandDataBuilder')); + builder.ParamNumber(P("var")); + builder.ParamText(P("str_var"), P("otherName")); builder.OptionalParams(); builder.Describe(P("Simple command")); builder.ParamBooleanList(P("list"), PBF_OnOff); // Subcommands - builder.SubCommand(P("sub")).ParamArray(P("array_var")); + builder.SubCommand(P("sub")); + builder.ParamArray(P("array_var")); builder.Describe(P("Alternative command!")); builder.ParamIntegerList(P("int")); builder.SubCommand(P("empty")); builder.Describe(P("Empty one!")); - builder.SubCommand(P("huh")).ParamNumber(P("list")); - builder.SubCommand(P("sub")).ParamObjectList(P("one_more"), P("but")); + builder.SubCommand(P("huh")); + builder.ParamNumber(P("list")); + builder.SubCommand(P("sub")); + builder.ParamObjectList(P("one_more"), P("but")); builder.Describe(P("Alternative command! Updated!")); // Options - builder.Option(P("silent")).Describe(P("Just an option, I dunno.")); + builder.Option(P("silent")); + builder.Describe(P("Just an option, I dunno.")); builder.Option(P("Params"), P("d")); builder.ParamBoolean(P("www"), PBF_YesNo, P("random")); - builder.OptionalParams().ParamIntegerList(P("www2")); - return builder.RequireTarget(); + builder.OptionalParams(); + builder.ParamIntegerList(P("www2")); + builder.RequireTarget(); + return builder; } protected static function Command.SubCommand GetSubCommand( diff --git a/sources/Users/ACommandUserGroups.uc b/sources/Users/ACommandUserGroups.uc index b58f706..62d18ba 100644 --- a/sources/Users/ACommandUserGroups.uc +++ b/sources/Users/ACommandUserGroups.uc @@ -22,56 +22,59 @@ class ACommandUserGroups extends Command protected function BuildData(CommandDataBuilder builder) { - builder.Name(P("usergroups")) - .Group(P("admin")) - .Summary(P("User groups management.")) - .Describe(P("Allows to add/remove user groups and users to these:" - @ "groups. Changes made by it will always affect current session," - @ "but might fail to be saved in case user groups are stored in" - @ "a database that is either corrupted or in read-only mode.")); - builder.SubCommand(P("list")) - .Describe(P("Lists specified groups along with users that belong to" - @ "them. If no groups were specified at all - lists all available" - @ "groups.")) - .OptionalParams() - .ParamTextList(P("groups")); - builder.SubCommand(P("add")) - .Describe(P("Adds a new group")) - .ParamText(P("group_name")); - builder.SubCommand(P("remove")) - .Describe(P("Removes a group")) - .ParamText(P("group_name")); - builder.SubCommand(P("addplayer")) - .Describe(F("Adds new user to the group, specified by the player" - @ "selector. Can add several players at once." - @ "Allows to also optionally specify annotation" - @ "(human-readable name) that can be thought of as" - @ "a {$TextEmphasis comment}. If annotation isn't specified" - @ "current nickname will be used as one.")) - .ParamText(P("group_name")) - .ParamPlayers(P("player_selector")) - .OptionalParams() - .ParamText(P("annotation")); - builder.SubCommand(P("removeplayer")) - .Describe(P("Removes user from the group, specified by player selector." - @ "Can remove several players at once.")) - .ParamText(P("group_name")) - .ParamPlayers(P("player_selector")); - builder.SubCommand(P("adduser")) - .Describe(F("Adds new user to the group. Allows to also optionally" - @ "specify annotation (human-readable name) that can be thought of" - @ "as a {$TextEmphasis comment}.")) - .ParamText(P("group_name")) - .ParamText(P("user_id")) - .OptionalParams() - .ParamText(P("annotation")); - builder.SubCommand(P("removeuser")) - .Describe(P("Removes user from the group. User can be specified by both" - @ "user's id or annotation, with id taking priority.")) - .ParamText(P("group_name")) - .ParamText(P("user_name")); - builder.Option(P("force")) - .Describe(P("Allows to force usage of invalid user IDs.")); + builder.Name(P("usergroups")); + builder.Group(P("admin")); + builder.Summary(P("User groups management.")); + builder.Describe(P("Allows to add/remove user groups and users to these: groups. Changes made" + @ "by it will always affect current session, but might fail to be saved in case user groups" + @ "are stored in a database that is either corrupted or in read-only mode.")); + + builder.SubCommand(P("list")); + builder.Describe(P("Lists specified groups along with users that belong to them. If no groups" + @ "were specified at all - lists all available groups.")); + builder.OptionalParams(); + builder.ParamTextList(P("groups")); + + builder.SubCommand(P("add")); + builder.Describe(P("Adds a new group")); + builder.ParamText(P("group_name")); + + builder.SubCommand(P("remove")); + builder.Describe(P("Removes a group")); + builder.ParamText(P("group_name")); + + builder.SubCommand(P("addplayer")); + builder.Describe(F("Adds new user to the group, specified by the player selector. Can add" + @ "several players at once. Allows to also optionally specify annotation (human-readable" + @ "name) that can be thought of as a {$TextEmphasis comment}. If annotation isn't" + @ "specified current nickname will be used as one.")); + builder.ParamText(P("group_name")); + builder.ParamPlayers(P("player_selector")); + builder.OptionalParams(); + builder.ParamText(P("annotation")); + + builder.SubCommand(P("removeplayer")); + builder.Describe(P("Removes user from the group, specified by player selector." + @ "Can remove several players at once.")); + builder.ParamText(P("group_name")); + builder.ParamPlayers(P("player_selector")); + + builder.SubCommand(P("adduser")); + builder.Describe(F("Adds new user to the group. Allows to also optionally specify annotation" + @ "(human-readable name) that can be thought of as a {$TextEmphasis comment}.")); + builder.ParamText(P("group_name")); + builder.ParamText(P("user_id")); + builder.OptionalParams(); + builder.ParamText(P("annotation")); + + builder.SubCommand(P("removeuser")); + builder.Describe(P("Removes user from the group. User can be specified by both user's id or" + @ "annotation, with id taking priority.")); + builder.ParamText(P("group_name")); + builder.ParamText(P("user_name")); + + builder.Option(P("force")); + builder.Describe(P("Allows to force usage of invalid user IDs.")); } protected function Executed(CallData arguments, EPlayer instigator)