731 lines
26 KiB
Ucode
731 lines
26 KiB
Ucode
/**
|
|
* Command for displaying help information about registered Acedia's commands.
|
|
* Copyright 2021-2023 Anton Tarasenko
|
|
*------------------------------------------------------------------------------
|
|
* This file is part of Acedia.
|
|
*
|
|
* Acedia is free software: you can redistribute it and/or modify
|
|
* it under the terms of the GNU General Public License as published by
|
|
* the Free Software Foundation, version 3 of the License, or
|
|
* (at your option) any later version.
|
|
*
|
|
* Acedia is distributed in the hope that it will be useful,
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
* GNU General Public License for more details.
|
|
*
|
|
* You should have received a copy of the GNU General Public License
|
|
* along with Acedia. If not, see <https://www.gnu.org/licenses/>.
|
|
*/
|
|
class ACommandHelp extends Command
|
|
dependson(LoggerAPI)
|
|
dependson(CommandAPI);
|
|
|
|
/**
|
|
* # `ACommandHelp`
|
|
*
|
|
* This built-in command is meant to do two things:
|
|
*
|
|
* 1. List all available commands and aliases related to them;
|
|
* 2. Display help pages for available commands (both by command and
|
|
* alias names).
|
|
*
|
|
* ## Implementation
|
|
*
|
|
* ### Aliases loading
|
|
*
|
|
* First thing this command tries to do upon creation is to read all
|
|
* command aliases and build a reverse map that allows to access aliases names
|
|
* by command + subcommand (even if latter one is empty) that these names
|
|
* refer to. This allows us to display relevant aliases names alongside
|
|
* command names. Map is stored inside `commandToAliasesMap` variable.
|
|
* (If aliases feature isn't yet available, `ACommandHelp` connects to
|
|
* `OnFeatureEnabled()` signal to do its job the moment required feature is
|
|
* enabled).
|
|
* This map is also made to be two-level one - it is...
|
|
*
|
|
* * a `HashTable` with command names as keys,
|
|
* * that points to `HashTable`s with subcommand names as keys,
|
|
* * that points at `ArrayList` of aliases.
|
|
*
|
|
* This allows us to also sort aliases by the subcommand name when displaying
|
|
* their list. This work is done by `FillCommandToAliasesMap()` method (that
|
|
* uses `ParseCommandNames()` method, which is also used for displaying
|
|
* command list).
|
|
*
|
|
* ### Command list displaying
|
|
*
|
|
* This is a simple process performed by `DisplayCommandLists()` that calls on
|
|
* a bunch of auxiliary `Print...()` methods.
|
|
*
|
|
* ### Displaying help pages
|
|
*
|
|
* Similar to the above, this is mostly a simple process that displays
|
|
* `Command`s' `CommandData` as a help page. Work is performed by
|
|
* `DisplayCommandHelpPages()` method that calls on a bunch of auxiliary
|
|
* `Print...()` methods, most notably `PrintHelpPageFor()` that can display
|
|
* help pages both for full commands, as well as only for a singular
|
|
* subcommand, which allows us to print proper help pages for command aliases
|
|
* that refer to a particular subcommand.
|
|
*/
|
|
|
|
// For each key (given by lower case command name) stores another `HashMap`
|
|
// that uses sub-command names as keys and returns `ArrayList` of aliases.
|
|
var private HashTable commandToAliasesMap;
|
|
|
|
var private User callerUser;
|
|
|
|
var public const int TSPACE, TCOMMAND_NAME_FALLBACK, TPLUS;
|
|
var public const int TOPEN_BRACKET, TCLOSE_BRACKET, TCOLON_SPACE;
|
|
var public const int TKEY, TDOUBLE_KEY, TCOMMA_SPACE, TBOOLEAN, TINDENT;
|
|
var public const int TBOOLEAN_TRUE_FALSE, TBOOLEAN_ENABLE_DISABLE;
|
|
var public const int TBOOLEAN_ON_OFF, TBOOLEAN_YES_NO;
|
|
var public const int TOPTIONS, TCMD_WITH_TARGET, TCMD_WITHOUT_TARGET;
|
|
var public const int TSEPARATOR, TLIST_REGIRESTED_CMDS, TEMPTY_GROUP;
|
|
var public const int TALIASES_FOR, TEMPTY, TDOT, TNO_COMMAND_BEGIN;
|
|
var public const int TNO_COMMAND_END, TEMPTY_GROUP_BEGIN, TEMPTY_GROUP_END;
|
|
|
|
protected function Constructor()
|
|
{
|
|
local Feature preenabledInstance;
|
|
|
|
super.Constructor();
|
|
// We need to update aliases map every time aliases feature is reenabled
|
|
_.environment.OnFeatureEnabled(self).connect = FillCommandToAliasesMap;
|
|
// If `Aliases_Feature` is already enabled - read its command aliases now
|
|
preenabledInstance = class'Aliases_Feature'.static.GetEnabledInstance();
|
|
FillCommandToAliasesMap(Aliases_Feature(preenabledInstance));
|
|
_.memory.Free(preenabledInstance);
|
|
}
|
|
|
|
protected function Finalizer()
|
|
{
|
|
super.Finalizer();
|
|
_.memory.Free(commandToAliasesMap);
|
|
commandToAliasesMap = none;
|
|
}
|
|
|
|
protected function BuildData(CommandDataBuilder builder)
|
|
{
|
|
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,
|
|
CommandPermissions permissions
|
|
) {
|
|
local bool printedSomething;
|
|
local HashTable parameters, options;
|
|
local ArrayList commandsToDisplay, commandGroupsToDisplay;
|
|
|
|
callerUser = callerPlayer.GetIdentity();
|
|
parameters = callData.parameters;
|
|
options = callData.options;
|
|
// Print command list if "--list" option was specified
|
|
if (options.HasKey(P("list")))
|
|
{
|
|
commandGroupsToDisplay = options.GetArrayListBy(P("/list/groups"));
|
|
DisplayCommandLists(
|
|
commandGroupsToDisplay,
|
|
options.HasKey(P("aliases")));
|
|
_.memory.Free(commandGroupsToDisplay);
|
|
printedSomething = true;
|
|
}
|
|
// Help pages.
|
|
// Only need to print them if:
|
|
// 1. Any commands are specified as parameters;
|
|
// 2. No commands or "--list" option was specified, then we want to
|
|
// print a help page for this command.
|
|
if (!options.HasKey(P("list")) || parameters.HasKey(P("commands")))
|
|
{
|
|
commandsToDisplay = parameters.GetArrayList(P("commands"));
|
|
DisplayCommandHelpPages(commandsToDisplay, printedSomething);
|
|
_.memory.Free(commandsToDisplay);
|
|
}
|
|
_.memory.Free(callerUser);
|
|
callerUser = none;
|
|
}
|
|
|
|
// If instance of the `Aliases_Feature` is passed as an argument (allowing this
|
|
// method to be used as a slot for `OnFeatureEnabled` signal) and
|
|
// `commandAliasSource` is available - empties current `commandToAliasesMap`
|
|
// and refills it with available command aliases.
|
|
private final function FillCommandToAliasesMap(Feature enabledFeature)
|
|
{
|
|
local int i;
|
|
local Text aliasValue;
|
|
local array<Text> availableAliases;
|
|
local BaseAliasSource commandAliasSource;
|
|
local MutableText commandName, subcommandName;
|
|
|
|
if (enabledFeature == none) return;
|
|
if (enabledFeature.class != class'Aliases_Feature') return;
|
|
commandAliasSource = _.alias.GetCommandSource();
|
|
if (commandAliasSource == none) return;
|
|
|
|
// Drop map built by previous aliases (if it was even build up until now)
|
|
_.memory.Free(commandToAliasesMap);
|
|
commandToAliasesMap = _.collections.EmptyHashTable();
|
|
// Construct a command -> alias map by iterating over aliases
|
|
availableAliases = commandAliasSource.GetAllAliases();
|
|
for (i = 0; i < availableAliases.length; i += 1)
|
|
{
|
|
aliasValue = _.alias.ResolveCommand(availableAliases[i]);
|
|
ParseCommandNames(aliasValue, commandName, subcommandName);
|
|
aliasValue.FreeSelf();
|
|
InsertIntoAliasesMap(commandName, subcommandName, availableAliases[i]);
|
|
commandName.FreeSelf();
|
|
subcommandName.FreeSelf();
|
|
commandName = none;
|
|
subcommandName = none;
|
|
}
|
|
// Clean up
|
|
_.memory.FreeMany(availableAliases);
|
|
commandAliasSource.FreeSelf();
|
|
}
|
|
|
|
// Breaks command name as it is intended to be specified in command aliases
|
|
// ("<command>" or "<command>.<subcommand>") into command and subcommand,
|
|
// returning both as `out` parameters.
|
|
private final function ParseCommandNames(
|
|
BaseText source,
|
|
out MutableText commandName,
|
|
out MutableText subcommandName)
|
|
{
|
|
local Parser valueParser;
|
|
|
|
if (source == none) {
|
|
return;
|
|
}
|
|
if (subcommandName != none) {
|
|
subcommandName.FreeSelf();
|
|
}
|
|
valueParser = source.Parse();
|
|
subcommandName = valueParser
|
|
.MUntil(commandName, T(TDOT).GetCharacter(0))
|
|
.Match(T(TDOT))
|
|
.GetRemainderM();
|
|
_.memory.Free(valueParser);
|
|
}
|
|
|
|
// Assumes that `commandToAliasesMap` and its arguments are not `none`.
|
|
private final function InsertIntoAliasesMap(
|
|
BaseText commandName,
|
|
BaseText subcommandName,
|
|
BaseText alias)
|
|
{
|
|
local Text commandKey, subcommandKey;
|
|
local HashTable subcommandToAliasesMap;
|
|
local ArrayList aliasesArray;
|
|
|
|
commandKey = commandName.LowerCopy();
|
|
subcommandKey = subcommandName.LowerCopy();
|
|
subcommandToAliasesMap = commandToAliasesMap.GetHashTable(commandKey);
|
|
if (subcommandToAliasesMap == none) {
|
|
subcommandToAliasesMap = _.collections.EmptyHashTable();
|
|
}
|
|
commandToAliasesMap.SetItem(commandKey, subcommandToAliasesMap);
|
|
aliasesArray = subcommandToAliasesMap.GetArrayList(subcommandKey);
|
|
if (aliasesArray == none) {
|
|
aliasesArray = _.collections.EmptyArrayList();
|
|
}
|
|
subcommandToAliasesMap.SetItem(subcommandKey, aliasesArray);
|
|
if (aliasesArray.Find(alias) < 0) {
|
|
aliasesArray.AddItem(alias);
|
|
}
|
|
// Cleaning up local references to collections and keys
|
|
subcommandToAliasesMap.FreeSelf();
|
|
aliasesArray.FreeSelf();
|
|
commandKey.FreeSelf();
|
|
subcommandKey.FreeSelf();
|
|
}
|
|
|
|
private final function DisplayCommandLists(
|
|
ArrayList commandGroupsToDisplay,
|
|
bool displayAliases)
|
|
{
|
|
local int i;
|
|
local array<Text> commandNames, groupsNames;
|
|
|
|
if (commandGroupsToDisplay == none) {
|
|
groupsNames = _.commands.GetGroupsNames();
|
|
}
|
|
else
|
|
{
|
|
for (i = 0; i < commandGroupsToDisplay.GetLength(); i += 1) {
|
|
groupsNames[groupsNames.length] = commandGroupsToDisplay.GetText(i);
|
|
}
|
|
}
|
|
callerConsole.WriteLine(T(TLIST_REGIRESTED_CMDS));
|
|
for (i = 0; i < groupsNames.length; i += 1)
|
|
{
|
|
if (groupsNames[i] == none) {
|
|
continue;
|
|
}
|
|
commandNames = _.commands.GetCommandNamesInGroup(groupsNames[i]);
|
|
if (commandNames.length > 0)
|
|
{
|
|
callerConsole.UseColorOnce(_.color.TextSubHeader);
|
|
if (groupsNames[i].IsEmpty()) {
|
|
callerConsole.WriteLine(T(TEMPTY_GROUP));
|
|
}
|
|
else {
|
|
callerConsole.WriteLine(groupsNames[i]);
|
|
}
|
|
PrintCommandsNamesArray(
|
|
commandNames,
|
|
displayAliases);
|
|
_.memory.FreeMany(commandNames);
|
|
} else {
|
|
callerConsole.UseColor(_.color.TextFailure);
|
|
callerConsole.Write(T(TEMPTY_GROUP_BEGIN));
|
|
callerConsole.Write(groupsNames[i]);
|
|
callerConsole.WriteLine(T(TEMPTY_GROUP_END));
|
|
callerConsole.ResetColor();
|
|
}
|
|
}
|
|
_.memory.FreeMany(groupsNames);
|
|
}
|
|
|
|
private final function PrintCommandsNamesArray(
|
|
array<Text> commandsNamesArray,
|
|
bool displayAliases
|
|
) {
|
|
local int i;
|
|
local Command.Data nextData;
|
|
local CommandAPI.CommandConfigInfo nextCommandPair;
|
|
|
|
for (i = 0; i < commandsNamesArray.length; i += 1)
|
|
{
|
|
nextCommandPair = _.commands.ResolveCommandForUser(
|
|
commandsNamesArray[i],
|
|
callerUser);
|
|
if (nextCommandPair.instance != none && !nextCommandPair.usageForbidden) {
|
|
nextData = nextCommandPair.instance.BorrowData();
|
|
callerConsole
|
|
.UseColorOnce(_.color.textEmphasis)
|
|
.Write(commandsNamesArray[i])
|
|
.Write(T(TCOLON_SPACE))
|
|
.WriteLine(nextData.summary);
|
|
if (displayAliases) {
|
|
PrintCommandAliases(commandsNamesArray[i]);
|
|
}
|
|
}
|
|
_.memory.Free(nextCommandPair.instance);
|
|
}
|
|
}
|
|
|
|
private final function PrintCommandAliases(BaseText commandName)
|
|
{
|
|
local CollectionIterator iter;
|
|
local Text commandKey;
|
|
local Text nextSubCommand;
|
|
local ArrayList nextAliasesArray;
|
|
local HashTable subCommandToAliasesMap;
|
|
|
|
if (commandName == none) return;
|
|
if (commandToAliasesMap == none) return;
|
|
|
|
commandKey = commandName.LowerCopy();
|
|
subCommandToAliasesMap = commandToAliasesMap.GetHashTable(commandName);
|
|
commandKey.FreeSelf();
|
|
if (subCommandToAliasesMap == none) {
|
|
return;
|
|
}
|
|
// Display aliases to command itself first
|
|
nextAliasesArray = subCommandToAliasesMap.GetArrayList(T(TEMPTY));
|
|
PrintAliasesArray(commandName, none, nextAliasesArray);
|
|
_.memory.Free(nextAliasesArray);
|
|
// Then aliases to all of its subcommands, in no particular order
|
|
iter = subCommandToAliasesMap.Iterate();
|
|
while (!iter.HasFinished())
|
|
{
|
|
nextSubCommand = Text(iter.Getkey()); // cannot be `none`
|
|
if (nextSubCommand.IsEmpty())
|
|
{
|
|
nextSubCommand.FreeSelf();
|
|
iter.Next();
|
|
continue;
|
|
}
|
|
nextAliasesArray = ArrayList(iter.Get());
|
|
PrintAliasesArray(commandName, nextSubCommand, nextAliasesArray);
|
|
_.memory.Free(nextAliasesArray);
|
|
_.memory.Free(nextSubCommand);
|
|
iter.Next();
|
|
}
|
|
iter.FreeSelf();
|
|
}
|
|
|
|
private final function PrintAliasesArray(
|
|
BaseText commandName,
|
|
BaseText subcommandName,
|
|
ArrayList aliasesArray)
|
|
{
|
|
local int i;
|
|
local Text nextAlias;
|
|
|
|
if (commandName == none) return;
|
|
if (aliasesArray == none) return;
|
|
|
|
callerConsole
|
|
.Write(T(TALIASES_FOR))
|
|
.Write(T(TSPACE))
|
|
.UseColorOnce(_.color.TextEmphasis)
|
|
.Write(commandName);
|
|
if (subcommandName != none)
|
|
{
|
|
callerConsole
|
|
.Write(T(TSPACE))
|
|
.UseColorOnce(_.color.TextEmphasis)
|
|
.Write(subCommandName);
|
|
}
|
|
callerConsole.Write(T(TCOLON_SPACE));
|
|
for (i = 0; i < aliasesArray.GetLength(); i += 1)
|
|
{
|
|
if (i > 0) {
|
|
callerConsole.Write(T(TCOMMA_SPACE));
|
|
}
|
|
nextAlias = aliasesArray.GetText(i);
|
|
callerConsole.UseColorOnce(_.color.TextNeutral).Write(nextAlias);
|
|
nextAlias.FreeSelf();
|
|
}
|
|
callerConsole.WriteBlock();
|
|
}
|
|
|
|
private final function DisplayCommandHelpPages(ArrayList commandList, bool printedSomething) {
|
|
local int i;
|
|
local Text nextUserProvidedName;
|
|
local MutableText referredSubcommand;
|
|
local CommandAPI.CommandConfigInfo nextPair;
|
|
|
|
// If arguments were empty - at least display our own help page
|
|
if (commandList == none) {
|
|
nextPair.instance = self;
|
|
PrintHelpPageFor(usedName, none, nextPair);
|
|
return;
|
|
}
|
|
// Otherwise - print help for specified commands
|
|
for (i = 0; i < commandList.GetLength(); i += 1) {
|
|
nextUserProvidedName = commandList.GetText(i);
|
|
nextPair = GetCommandFromUserProvidedName(
|
|
nextUserProvidedName,
|
|
/*out*/ referredSubcommand);
|
|
if (nextPair.instance != none && !nextPair.usageForbidden) {
|
|
if (printedSomething) {
|
|
callerConsole.WriteLine(T(TSEPARATOR));
|
|
}
|
|
PrintHelpPageFor(
|
|
nextUserProvidedName,
|
|
referredSubcommand,
|
|
nextPair);
|
|
printedSomething = true;
|
|
} else if (nextPair.instance != none) {
|
|
callerConsole.UseColor(_.color.TextFailure);
|
|
callerConsole.Write(T(TNO_COMMAND_BEGIN));
|
|
callerConsole.Write(nextUserProvidedName);
|
|
callerConsole.WriteLine(T(TNO_COMMAND_END));
|
|
callerConsole.ResetColor();
|
|
}
|
|
_.memory.Free(nextPair.instance);
|
|
_.memory.Free(nextUserProvidedName);
|
|
_.memory.Free(referredSubcommand);
|
|
// `referredSubcommand` is passed as an `out` parameter on
|
|
// every iteration, so we need to prevent the possibility of its value
|
|
// being used.
|
|
// NOTE: `nextCommand` and `nextUserProvidedName` are just rewritten.
|
|
referredSubcommand = none;
|
|
}
|
|
}
|
|
|
|
// Returns `Command` based on the name, given by user.
|
|
// `referredSubcommand` is always overwritten (freed if non-`none` value
|
|
// is passed) and is used to return name of the subcommand for returned
|
|
// `Command` that is specified by `nextUserProvidedName` (only relevant for
|
|
// aliases that refer to a particular subcommand).
|
|
private final function CommandAPI.CommandConfigInfo GetCommandFromUserProvidedName(
|
|
BaseText nextUserProvidedName,
|
|
out MutableText referredSubcommand)
|
|
{
|
|
local CommandAPI.CommandConfigInfo result;
|
|
local Text commandAliasValue;
|
|
local MutableText parsedCommandName;
|
|
|
|
// Clear `out` parameter no matter what
|
|
if (referredSubcommand != none) {
|
|
referredSubcommand.FreeSelf();
|
|
referredSubcommand = none;
|
|
}
|
|
// Try getting command using `nextUserProvidedName` as a literal name
|
|
result = _.commands.ResolveCommandForUser(nextUserProvidedName, callerUser);
|
|
if (result.instance != none) {
|
|
return result;
|
|
}
|
|
// On failure - try resolving it as an alias
|
|
commandAliasValue = _.alias.ResolveCommand(nextUserProvidedName);
|
|
ParseCommandNames(commandAliasValue, parsedCommandName, referredSubcommand);
|
|
result = _.commands.ResolveCommandForUser(parsedCommandName, callerUser);
|
|
if ( result.instance == none
|
|
|| !result.instance.IsSubCommandAllowed(referredSubcommand, result.config)) {
|
|
_.memory.Free(result.instance);
|
|
return result;
|
|
}
|
|
// Empty subcommand name from the alias is essentially no subcommand name
|
|
if (referredSubcommand != none && referredSubcommand.IsEmpty()) {
|
|
referredSubcommand.FreeSelf();
|
|
referredSubcommand = none;
|
|
}
|
|
_.memory.Free2(commandAliasValue, parsedCommandName);
|
|
return result;
|
|
}
|
|
|
|
private final function PrintHelpPageFor(
|
|
BaseText commandAlias,
|
|
BaseText referredSubcommand,
|
|
CommandAPI.CommandConfigInfo commandPair
|
|
) {
|
|
local Text commandNameLowerCase, commandNameUpperCase;
|
|
|
|
// Get capitalized command name
|
|
commandNameUpperCase = commandAlias.UpperCopy();
|
|
// Print header: name + basic info
|
|
callerConsole.UseColor(_.color.textHeader)
|
|
.Write(commandNameUpperCase)
|
|
.UseColor(_.color.textDefault);
|
|
commandNameUpperCase.FreeSelf();
|
|
if (commandPair.instance.BorrowData().requiresTarget) {
|
|
callerConsole.WriteLine(T(TCMD_WITH_TARGET));
|
|
}
|
|
else {
|
|
callerConsole.WriteLine(T(TCMD_WITHOUT_TARGET));
|
|
}
|
|
// Print commands and options
|
|
commandNameLowerCase = commandAlias.LowerCopy();
|
|
PrintCommands(commandPair, commandNameLowerCase, referredSubcommand);
|
|
commandNameLowerCase.FreeSelf();
|
|
PrintOptions(commandPair.instance.BorrowData());
|
|
// Clean up
|
|
callerConsole.ResetColor().Flush();
|
|
}
|
|
|
|
private final function PrintCommands(
|
|
CommandAPI.CommandConfigInfo commandPair,
|
|
BaseText commandName,
|
|
BaseText referredSubcommand
|
|
) {
|
|
local int i;
|
|
local array<Command.SubCommand> subCommands;
|
|
|
|
subCommands = commandPair.instance.BorrowData().subCommands;
|
|
for (i = 0; i < subCommands.length; i += 1) {
|
|
if (referredSubcommand == none || referredSubcommand.Compare(subCommands[i].name)) {
|
|
if (commandPair.instance.IsSubCommandAllowed(subCommands[i].name, commandPair.config)) {
|
|
PrintSubCommand(subCommands[i], commandName, referredSubcommand != none);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
private final function PrintSubCommand(
|
|
SubCommand subCommand,
|
|
BaseText commandName,
|
|
bool skipSubcommandName)
|
|
{
|
|
// Command + parameters
|
|
// Command name + sub command name
|
|
callerConsole.UseColor(_.color.textEmphasis)
|
|
.Write(commandName)
|
|
.Write(T(TSPACE));
|
|
if ( !skipSubcommandName
|
|
&& subCommand.name != none
|
|
&& !subCommand.name.IsEmpty())
|
|
{
|
|
callerConsole.Write(subCommand.name).Write(T(TSPACE));
|
|
}
|
|
callerConsole.UseColor(_.color.textDefault);
|
|
// Parameters
|
|
PrintParameters(subCommand.required, subCommand.optional);
|
|
callerConsole.Flush();
|
|
// Description
|
|
if (subCommand.description != none && !subCommand.description.IsEmpty()) {
|
|
callerConsole.WriteBlock(subCommand.description);
|
|
}
|
|
}
|
|
|
|
private final function PrintOptions(Command.Data data)
|
|
{
|
|
local int i;
|
|
local array<Option> options;
|
|
options = data.options;
|
|
if (options.length <= 0) {
|
|
return;
|
|
}
|
|
callerConsole
|
|
.UseColor(_.color.textSubHeader)
|
|
.WriteLine(T(TOPTIONS))
|
|
.UseColor(_.color.textDefault);
|
|
for (i = 0; i < options.length; i += 1) {
|
|
PrintOption(options[i]);
|
|
}
|
|
}
|
|
|
|
private final function PrintOption(Option option)
|
|
{
|
|
local Text shortNameAsText;
|
|
// Option short and long names with added key characters
|
|
shortNameAsText = _.text.FromCharacter(option.shortName);
|
|
callerConsole
|
|
.UseColor(_.color.textEmphasis)
|
|
.Write(T(TKEY)).Write(shortNameAsText) // "-"
|
|
.UseColor(_.color.textDefault)
|
|
.Write(T(TCOMMA_SPACE)) // ", "
|
|
.UseColor(_.color.textEmphasis)
|
|
.Write(T(TDOUBLE_KEY)).Write(option.longName) // "--"
|
|
.UseColor(_.color.textDefault);
|
|
shortNameAsText.FreeSelf();
|
|
// Parameters
|
|
if (option.required.length != 0 || option.optional.length != 0)
|
|
{
|
|
callerConsole.Write(T(TSPACE));
|
|
PrintParameters(option.required, option.optional);
|
|
}
|
|
callerConsole.Flush();
|
|
// Description
|
|
if (option.description != none && !option.description.IsEmpty()) {
|
|
callerConsole.WriteBlock(option.description);
|
|
}
|
|
}
|
|
|
|
private final function PrintParameters(
|
|
array<Parameter> required,
|
|
array<Parameter> optional)
|
|
{
|
|
local int i;
|
|
// Print required
|
|
for (i = 0; i < required.length; i += 1)
|
|
{
|
|
PrintParameter(required[i]);
|
|
if (i < required.length - 1) {
|
|
callerConsole.Write(T(TSPACE));
|
|
}
|
|
}
|
|
if (optional.length <= 0) {
|
|
return;
|
|
}
|
|
// Print optional
|
|
callerConsole.Write(T(TSPACE)).Write(T(TOPEN_BRACKET));
|
|
for (i = 0; i < optional.length; i += 1)
|
|
{
|
|
PrintParameter(optional[i]);
|
|
if (i < optional.length - 1) {
|
|
callerConsole.Write(T(TSPACE));
|
|
}
|
|
}
|
|
callerConsole.Write(T(TCLOSE_BRACKET));
|
|
}
|
|
|
|
private final function PrintParameter(Parameter parameter)
|
|
{
|
|
switch (parameter.type)
|
|
{
|
|
case CPT_Boolean:
|
|
callerConsole.UseColor(_.color.typeBoolean);
|
|
break;
|
|
case CPT_Integer:
|
|
callerConsole.UseColor(_.color.typeNumber);
|
|
break;
|
|
case CPT_Number:
|
|
callerConsole.UseColor(_.color.typeNumber);
|
|
break;
|
|
case CPT_Text:
|
|
case CPT_Remainder:
|
|
callerConsole.UseColor(_.color.typeString);
|
|
break;
|
|
case CPT_Object:
|
|
case CPT_JSON:
|
|
case CPT_Array:
|
|
case CPT_PLAYERS:
|
|
callerConsole.UseColor(_.color.typeLiteral);
|
|
break;
|
|
default:
|
|
callerConsole.UseColor(_.color.textDefault);
|
|
}
|
|
callerConsole.Write(parameter.displayName);
|
|
if (parameter.allowsList) {
|
|
callerConsole.Write(T(TPLUS));
|
|
}
|
|
callerConsole.UseColor(_.color.textDefault);
|
|
}
|
|
|
|
defaultproperties
|
|
{
|
|
TSPACE = 0
|
|
stringConstants(0) = " "
|
|
TPLUS = 1
|
|
stringConstants(1) = "(+)"
|
|
TOPEN_BRACKET = 2
|
|
stringConstants(2) = "["
|
|
TCLOSE_BRACKET = 3
|
|
stringConstants(3) = "]"
|
|
TKEY = 4
|
|
stringConstants(4) = "-"
|
|
TDOUBLE_KEY = 5
|
|
stringConstants(5) = "--"
|
|
TCOMMA_SPACE = 6
|
|
stringConstants(6) = ", "
|
|
TCOLON_SPACE = 7
|
|
stringConstants(7) = ": "
|
|
TINDENT = 8
|
|
stringConstants(8) = " "
|
|
TBOOLEAN = 9
|
|
stringConstants(9) = "boolean"
|
|
TBOOLEAN_TRUE_FALSE = 10
|
|
stringConstants(10) = "true/false"
|
|
TBOOLEAN_ENABLE_DISABLE = 11
|
|
stringConstants(11) = "enable/disable"
|
|
TBOOLEAN_ON_OFF = 12
|
|
stringConstants(12) = "on/off"
|
|
TBOOLEAN_YES_NO = 13
|
|
stringConstants(13) = "yes/no"
|
|
TCMD_WITH_TARGET = 14
|
|
stringConstants(14) = ": This command requires target to be specified."
|
|
TCMD_WITHOUT_TARGET = 15
|
|
stringConstants(15) = ": This command does not require target to be specified."
|
|
TOPTIONS = 16
|
|
stringConstants(16) = "OPTIONS"
|
|
TSEPARATOR = 17
|
|
stringConstants(17) = "============================="
|
|
TLIST_REGIRESTED_CMDS = 18
|
|
stringConstants(18) = "{$TextHeader List of registered commands}"
|
|
TEMPTY_GROUP = 19
|
|
stringConstants(19) = "Empty group"
|
|
TALIASES_FOR = 20
|
|
stringConstants(20) = "Aliases for"
|
|
TEMPTY = 21
|
|
stringConstants(21) = ""
|
|
TDOT = 22
|
|
stringConstants(22) = "."
|
|
TNO_COMMAND_BEGIN = 23
|
|
stringConstants(23) = "Command `"
|
|
TNO_COMMAND_END = 24
|
|
stringConstants(24) = "` not found!"
|
|
TEMPTY_GROUP_BEGIN = 25
|
|
stringConstants(25) = "No commands in group \""
|
|
TEMPTY_GROUP_END = 26
|
|
stringConstants(26) = "\"!"
|
|
preferredName = "help"
|
|
} |