Added support for multiple commands at the same path

This commit is contained in:
RogueException
2015-11-10 15:04:05 -04:00
parent e7e2a85c3a
commit d9759abf4c
3 changed files with 98 additions and 71 deletions

View File

@@ -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;
} }

View File

@@ -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;

View File

@@ -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)