Added support for multiple commands at the same path
This commit is contained in:
@@ -9,14 +9,14 @@ namespace Discord.Commands
|
|||||||
private readonly CommandMap _parent;
|
private readonly CommandMap _parent;
|
||||||
private readonly string _name, _fullName;
|
private readonly string _name, _fullName;
|
||||||
|
|
||||||
private Command _command;
|
private readonly List<Command> _commands;
|
||||||
private readonly Dictionary<string, CommandMap> _items;
|
private readonly Dictionary<string, CommandMap> _items;
|
||||||
private bool _isHidden;
|
private bool _isHidden;
|
||||||
|
|
||||||
public string Name => _name;
|
public string Name => _name;
|
||||||
public string FullName => _fullName;
|
public string FullName => _fullName;
|
||||||
public bool IsHidden => _isHidden;
|
public bool IsHidden => _isHidden;
|
||||||
public Command Command => _command;
|
public IEnumerable<Command> Commands => _commands;
|
||||||
public IEnumerable<CommandMap> SubGroups => _items.Values;
|
public IEnumerable<CommandMap> SubGroups => _items.Values;
|
||||||
/*public IEnumerable<Command> SubCommands => _items.Select(x => x.Value._command).Where(x => x != null);
|
/*public IEnumerable<Command> SubCommands => _items.Select(x => x.Value._command).Where(x => x != null);
|
||||||
public IEnumerable<CommandMap> SubGroups => _items.Select(x => x.Value).Where(x => x._items.Count > 0);*/
|
public IEnumerable<CommandMap> SubGroups => _items.Select(x => x.Value).Where(x => x._items.Count > 0);*/
|
||||||
@@ -27,6 +27,7 @@ namespace Discord.Commands
|
|||||||
_name = name;
|
_name = name;
|
||||||
_fullName = fullName;
|
_fullName = fullName;
|
||||||
_items = new Dictionary<string, CommandMap>();
|
_items = new Dictionary<string, CommandMap>();
|
||||||
|
_commands = new List<Command>();
|
||||||
_isHidden = true;
|
_isHidden = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -48,20 +49,20 @@ namespace Discord.Commands
|
|||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
public Command GetCommand()
|
public IEnumerable<Command> GetCommands()
|
||||||
{
|
{
|
||||||
if (_command != null)
|
if (_commands.Count > 0)
|
||||||
return _command;
|
return _commands;
|
||||||
else if (_parent != null)
|
else if (_parent != null)
|
||||||
return _parent.GetCommand();
|
return _parent.GetCommands();
|
||||||
else
|
else
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
public Command GetCommand(string text)
|
public IEnumerable<Command> GetCommands(string text)
|
||||||
{
|
{
|
||||||
return GetCommand(0, text.Split(' '));
|
return GetCommands(0, text.Split(' '));
|
||||||
}
|
}
|
||||||
public Command GetCommand(int index, string[] parts)
|
public IEnumerable<Command> GetCommands(int index, string[] parts)
|
||||||
{
|
{
|
||||||
if (index != parts.Length)
|
if (index != parts.Length)
|
||||||
{
|
{
|
||||||
@@ -69,14 +70,14 @@ namespace Discord.Commands
|
|||||||
CommandMap nextGroup;
|
CommandMap nextGroup;
|
||||||
if (_items.TryGetValue(nextPart, out nextGroup))
|
if (_items.TryGetValue(nextPart, out nextGroup))
|
||||||
{
|
{
|
||||||
var cmd = nextGroup.GetCommand(index + 1, parts);
|
var cmd = nextGroup.GetCommands(index + 1, parts);
|
||||||
if (cmd != null)
|
if (cmd != null)
|
||||||
return cmd;
|
return cmd;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (_command != null)
|
if (_commands != null)
|
||||||
return _command;
|
return _commands;
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -102,21 +103,26 @@ namespace Discord.Commands
|
|||||||
nextGroup.AddCommand(index + 1, parts, command);
|
nextGroup.AddCommand(index + 1, parts, command);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
_commands.Add(command);
|
||||||
if (_command != null)
|
|
||||||
throw new InvalidOperationException("A command has already been added with this path.");
|
|
||||||
_command = command;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public bool CanRun(User user, Channel channel)
|
public bool CanRun(User user, Channel channel)
|
||||||
{
|
{
|
||||||
if (_command != null && _command.CanRun(user, channel))
|
if (_commands.Count > 0)
|
||||||
return true;
|
|
||||||
foreach (var item in _items)
|
|
||||||
{
|
{
|
||||||
if (item.Value.CanRun(user, channel))
|
foreach (var cmd in _commands)
|
||||||
return true;
|
{
|
||||||
|
if (cmd.CanRun(user, channel))
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (_items.Count > 0)
|
||||||
|
{
|
||||||
|
foreach (var item in _items)
|
||||||
|
{
|
||||||
|
if (item.Value.CanRun(user, channel))
|
||||||
|
return true;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -12,13 +12,13 @@ namespace Discord.Commands
|
|||||||
DoubleQuotedParameter
|
DoubleQuotedParameter
|
||||||
}
|
}
|
||||||
|
|
||||||
public static bool ParseCommand(string input, CommandMap map, out Command command, out int endPos)
|
public static bool ParseCommand(string input, CommandMap map, out IEnumerable<Command> commands, out int endPos)
|
||||||
{
|
{
|
||||||
int startPosition = 0;
|
int startPosition = 0;
|
||||||
int endPosition = 0;
|
int endPosition = 0;
|
||||||
int inputLength = input.Length;
|
int inputLength = input.Length;
|
||||||
bool isEscaped = false;
|
bool isEscaped = false;
|
||||||
command = null;
|
commands = null;
|
||||||
endPos = 0;
|
endPos = 0;
|
||||||
|
|
||||||
if (input == "")
|
if (input == "")
|
||||||
@@ -52,8 +52,8 @@ namespace Discord.Commands
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
command = map.GetCommand(); //Work our way backwards to find a command that matches our input
|
commands = map.GetCommands(); //Work our way backwards to find a command that matches our input
|
||||||
return command != null;
|
return commands != null;
|
||||||
}
|
}
|
||||||
|
|
||||||
//TODO: Check support for escaping
|
//TODO: Check support for escaping
|
||||||
@@ -78,6 +78,8 @@ namespace Discord.Commands
|
|||||||
{
|
{
|
||||||
if (startPosition == endPosition && (parameter == null || parameter.Type != ParameterType.Multiple)) //Is first char of a new arg
|
if (startPosition == endPosition && (parameter == null || parameter.Type != ParameterType.Multiple)) //Is first char of a new arg
|
||||||
{
|
{
|
||||||
|
if (argList.Count >= expectedArgs.Length)
|
||||||
|
return CommandErrorType.BadArgCount; //Too many args
|
||||||
parameter = expectedArgs[argList.Count];
|
parameter = expectedArgs[argList.Count];
|
||||||
if (parameter.Type == ParameterType.Unparsed)
|
if (parameter.Type == ParameterType.Unparsed)
|
||||||
{
|
{
|
||||||
@@ -144,6 +146,7 @@ namespace Discord.Commands
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//Too few args
|
||||||
for (int i = argList.Count; i < expectedArgs.Length; i++)
|
for (int i = argList.Count; i < expectedArgs.Length; i++)
|
||||||
{
|
{
|
||||||
var param = expectedArgs[i];
|
var param = expectedArgs[i];
|
||||||
@@ -158,11 +161,11 @@ namespace Discord.Commands
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (argList.Count > expectedArgs.Length)
|
/*if (argList.Count > expectedArgs.Length)
|
||||||
{
|
{
|
||||||
if (expectedArgs.Length == 0 || expectedArgs[expectedArgs.Length - 1].Type != ParameterType.Multiple)
|
if (expectedArgs.Length == 0 || expectedArgs[expectedArgs.Length - 1].Type != ParameterType.Multiple)
|
||||||
return CommandErrorType.BadArgCount;
|
return CommandErrorType.BadArgCount;
|
||||||
}
|
}*/
|
||||||
|
|
||||||
args = argList.ToArray();
|
args = argList.ToArray();
|
||||||
return null;
|
return null;
|
||||||
|
|||||||
@@ -88,10 +88,10 @@ After:
|
|||||||
}
|
}
|
||||||
|
|
||||||
//Parse command
|
//Parse command
|
||||||
Command command;
|
IEnumerable<Command> commands;
|
||||||
int argPos;
|
int argPos;
|
||||||
CommandParser.ParseCommand(msg, _map, out command, out argPos);
|
CommandParser.ParseCommand(msg, _map, out commands, out argPos);
|
||||||
if (command == null)
|
if (commands == null)
|
||||||
{
|
{
|
||||||
CommandEventArgs errorArgs = new CommandEventArgs(e.Message, null, null);
|
CommandEventArgs errorArgs = new CommandEventArgs(e.Message, null, null);
|
||||||
RaiseCommandError(CommandErrorType.UnknownCommand, errorArgs);
|
RaiseCommandError(CommandErrorType.UnknownCommand, errorArgs);
|
||||||
@@ -99,35 +99,46 @@ After:
|
|||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
//Parse arguments
|
foreach (var command in commands)
|
||||||
string[] args;
|
|
||||||
var error = CommandParser.ParseArgs(msg, argPos, command, out args);
|
|
||||||
if (error != null)
|
|
||||||
{
|
{
|
||||||
var errorArgs = new CommandEventArgs(e.Message, command, null);
|
//Parse arguments
|
||||||
RaiseCommandError(error.Value, errorArgs);
|
string[] args;
|
||||||
|
var error = CommandParser.ParseArgs(msg, argPos, command, out args);
|
||||||
|
if (error != null)
|
||||||
|
{
|
||||||
|
if (error == CommandErrorType.BadArgCount)
|
||||||
|
continue;
|
||||||
|
else
|
||||||
|
{
|
||||||
|
var errorArgs = new CommandEventArgs(e.Message, command, null);
|
||||||
|
RaiseCommandError(error.Value, errorArgs);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
var eventArgs = new CommandEventArgs(e.Message, command, args);
|
||||||
|
|
||||||
|
// Check permissions
|
||||||
|
if (!command.CanRun(eventArgs.User, eventArgs.Channel))
|
||||||
|
{
|
||||||
|
RaiseCommandError(CommandErrorType.BadPermissions, eventArgs);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Run the command
|
||||||
|
try
|
||||||
|
{
|
||||||
|
RaiseRanCommand(eventArgs);
|
||||||
|
await command.Run(eventArgs).ConfigureAwait(false);
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
RaiseCommandError(CommandErrorType.Exception, eventArgs, ex);
|
||||||
|
}
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
var errorArgs2 = new CommandEventArgs(e.Message, null, null);
|
||||||
var eventArgs = new CommandEventArgs(e.Message, command, args);
|
RaiseCommandError(CommandErrorType.BadArgCount, errorArgs2);
|
||||||
|
|
||||||
// Check permissions
|
|
||||||
if (!command.CanRun(eventArgs.User, eventArgs.Channel))
|
|
||||||
{
|
|
||||||
RaiseCommandError(CommandErrorType.BadPermissions, eventArgs);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Run the command
|
|
||||||
try
|
|
||||||
{
|
|
||||||
RaiseRanCommand(eventArgs);
|
|
||||||
await command.Run(eventArgs).ConfigureAwait(false);
|
|
||||||
}
|
|
||||||
catch (Exception ex)
|
|
||||||
{
|
|
||||||
RaiseCommandError(CommandErrorType.Exception, eventArgs, ex);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
@@ -208,9 +219,19 @@ After:
|
|||||||
{
|
{
|
||||||
StringBuilder output = new StringBuilder();
|
StringBuilder output = new StringBuilder();
|
||||||
|
|
||||||
Command cmd = map.Command;
|
IEnumerable<Command> cmds = map.Commands;
|
||||||
if (cmd != null)
|
bool isFirstCmd = true;
|
||||||
ShowCommandHelpInternal(cmd, user, channel, output);
|
if (cmds != null)
|
||||||
|
{
|
||||||
|
foreach (var cmd in cmds)
|
||||||
|
{
|
||||||
|
if (isFirstCmd)
|
||||||
|
isFirstCmd = false;
|
||||||
|
/*else
|
||||||
|
output.AppendLine();*/
|
||||||
|
ShowCommandHelpInternal(cmd, user, channel, output);
|
||||||
|
}
|
||||||
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
output.Append('`');
|
output.Append('`');
|
||||||
@@ -218,12 +239,12 @@ After:
|
|||||||
output.Append("`\n");
|
output.Append("`\n");
|
||||||
}
|
}
|
||||||
|
|
||||||
bool isFirst = true;
|
bool isFirstSubCmd = true;
|
||||||
foreach (var subCmd in map.SubGroups.Where(x => x.CanRun(user, channel) && !x.IsHidden))
|
foreach (var subCmd in map.SubGroups.Where(x => x.CanRun(user, channel) && !x.IsHidden))
|
||||||
{
|
{
|
||||||
if (isFirst)
|
if (isFirstSubCmd)
|
||||||
{
|
{
|
||||||
isFirst = false;
|
isFirstSubCmd = false;
|
||||||
output.AppendLine("Sub Commands: ");
|
output.AppendLine("Sub Commands: ");
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
@@ -235,7 +256,7 @@ After:
|
|||||||
output.Append('`');
|
output.Append('`');
|
||||||
}
|
}
|
||||||
|
|
||||||
if (isFirst)
|
if (isFirstCmd && isFirstSubCmd) //Had no commands and no subcommands
|
||||||
{
|
{
|
||||||
output.Clear();
|
output.Clear();
|
||||||
output.AppendLine("You do not have permission to access this command.");
|
output.AppendLine("You do not have permission to access this command.");
|
||||||
@@ -246,17 +267,14 @@ After:
|
|||||||
public Task ShowCommandHelp(Command command, User user, Channel channel, Channel replyChannel = null)
|
public Task ShowCommandHelp(Command command, User user, Channel channel, Channel replyChannel = null)
|
||||||
{
|
{
|
||||||
StringBuilder output = new StringBuilder();
|
StringBuilder output = new StringBuilder();
|
||||||
ShowCommandHelpInternal(command, user, channel, output);
|
if (!command.CanRun(user, channel))
|
||||||
|
output.AppendLine("You do not have permission to access this command.");
|
||||||
|
else
|
||||||
|
ShowCommandHelpInternal(command, user, channel, output);
|
||||||
return _client.SendMessage(replyChannel ?? channel, output.ToString());
|
return _client.SendMessage(replyChannel ?? channel, output.ToString());
|
||||||
}
|
}
|
||||||
private void ShowCommandHelpInternal(Command command, User user, Channel channel, StringBuilder output)
|
private void ShowCommandHelpInternal(Command command, User user, Channel channel, StringBuilder output)
|
||||||
{
|
{
|
||||||
if (!command.CanRun(user, channel))
|
|
||||||
{
|
|
||||||
output.AppendLine("You do not have permission to access this command.");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
output.Append('`');
|
output.Append('`');
|
||||||
output.Append(command.Text);
|
output.Append(command.Text);
|
||||||
foreach (var param in command.Parameters)
|
foreach (var param in command.Parameters)
|
||||||
|
|||||||
Reference in New Issue
Block a user