diff --git a/src/Discord.Net.Commands/Command.cs b/src/Discord.Net.Commands/Command.cs index bc1013245..15ad98b95 100644 --- a/src/Discord.Net.Commands/Command.cs +++ b/src/Discord.Net.Commands/Command.cs @@ -32,7 +32,7 @@ namespace Discord.Commands public string Text { get; } public int? MinArgs { get; private set; } public int? MaxArgs { get; private set; } - public int MinPerms { get; internal set; } + public int MinPermissions { get; internal set; } public bool IsHidden { get; internal set; } public string Description { get; internal set; } @@ -40,7 +40,7 @@ namespace Discord.Commands private string[] _aliases; public IEnumerable Parameters => _parameters; - private CommandParameter[] _parameters; + internal CommandParameter[] _parameters; private Func _handler; diff --git a/src/Discord.Net.Commands/CommandBuilder.cs b/src/Discord.Net.Commands/CommandBuilder.cs index 34a77f1c8..dd8035dc7 100644 --- a/src/Discord.Net.Commands/CommandBuilder.cs +++ b/src/Discord.Net.Commands/CommandBuilder.cs @@ -38,7 +38,7 @@ namespace Discord.Commands { if (_isClosed) throw new Exception($"No parameters may be added after a {nameof(ParameterType.Multiple)} or {nameof(ParameterType.Unparsed)} parameter."); - if (!_allowRequired && type != ParameterType.Required) + if (!_allowRequired && type == ParameterType.Required) throw new Exception($"{nameof(ParameterType.Required)} parameters may not be added after an optional one"); _params.Add(new CommandParameter(name, type)); @@ -57,7 +57,7 @@ namespace Discord.Commands public CommandBuilder MinPermissions(int level) { - _command.MinPerms = level; + _command.MinPermissions = level; return this; } @@ -125,7 +125,7 @@ namespace Discord.Commands public CommandBuilder CreateCommand(string cmd) { var command = new Command(CommandBuilder.AppendPrefix(_prefix, cmd)); - command.MinPerms = _defaultMinPermissions; + command.MinPermissions = _defaultMinPermissions; return new CommandBuilder(_plugin, command, _prefix); } } diff --git a/src/Discord.Net.Commands/CommandParser.cs b/src/Discord.Net.Commands/CommandParser.cs index 08241eb1b..14af9f550 100644 --- a/src/Discord.Net.Commands/CommandParser.cs +++ b/src/Discord.Net.Commands/CommandParser.cs @@ -2,19 +2,6 @@ namespace Discord.Commands { - public class CommandPart - { - public string Value { get; } - public int Index { get; } - - internal CommandPart(string value, int index) - { - Value = value; - Index = index; - } - } - - //TODO: Check support for escaping internal static class CommandParser { private enum CommandParserPart @@ -69,23 +56,40 @@ namespace Discord.Commands return command != null; } - public static bool ParseArgs(string input, int startPos, Command command, out CommandPart[] args) + //TODO: Check support for escaping + public static CommandErrorType? ParseArgs(string input, int startPos, Command command, out string[] args) { CommandParserPart currentPart = CommandParserPart.None; int startPosition = startPos; int endPosition = startPos; int inputLength = input.Length; bool isEscaped = false; - List argList = new List(); + + var expectedArgs = command._parameters; + List argList = new List(); + CommandParameter parameter = null; args = null; if (input == "") - return false; + return CommandErrorType.InvalidInput; while (endPosition < inputLength) { - char currentChar = input[endPosition++]; + if (startPosition == endPosition && (parameter == null || parameter.Type != ParameterType.Multiple)) //Is first char of a new arg + { + if (argList.Count == command.MaxArgs) + return CommandErrorType.BadArgCount; + + parameter = command._parameters[argList.Count]; + if (parameter.Type == ParameterType.Unparsed) + { + argList.Add(input.Substring(startPosition)); + break; + } + } + + char currentChar = input[endPosition++]; if (isEscaped) isEscaped = false; else if (currentChar == '\\') @@ -113,7 +117,7 @@ namespace Discord.Commands else { currentPart = CommandParserPart.None; - argList.Add(new CommandPart(temp, startPosition)); + argList.Add(temp); startPosition = endPosition; } } @@ -123,28 +127,31 @@ namespace Discord.Commands { string temp = input.Substring(startPosition, endPosition - startPosition - 1); currentPart = CommandParserPart.None; - argList.Add(new CommandPart(temp, startPosition)); + argList.Add(temp); startPosition = endPosition; } else if (endPosition >= inputLength) - return false; + return CommandErrorType.InvalidInput; break; case CommandParserPart.DoubleQuotedParameter: if ((!isEscaped && currentChar == '\"')) { string temp = input.Substring(startPosition, endPosition - startPosition - 1); currentPart = CommandParserPart.None; - argList.Add(new CommandPart(temp, startPosition)); + argList.Add(temp); startPosition = endPosition; } else if (endPosition >= inputLength) - return false; + return CommandErrorType.InvalidInput; break; } } + if (argList.Count < command.MinArgs) + return CommandErrorType.BadArgCount; + args = argList.ToArray(); - return true; + return null; } } } diff --git a/src/Discord.Net.Commands/CommandsPlugin.cs b/src/Discord.Net.Commands/CommandsPlugin.cs index 1f5e5d450..e77210e5f 100644 --- a/src/Discord.Net.Commands/CommandsPlugin.cs +++ b/src/Discord.Net.Commands/CommandsPlugin.cs @@ -18,7 +18,11 @@ namespace Discord.Commands internal CommandMap Map => _map; private readonly CommandMap _map; - public char ComamndChar { get { return _commandChars[0]; } set { _commandChars = new char[] { value }; } } + public char? ComamndChar + { + get { return _commandChars.Length > 0 ? _commandChars[0] : (char?)null; } + set { _commandChars = value != null ? new char[] { value.Value } : new char[0]; } + } public IEnumerable CommandChars { get { return _commandChars; } set { _commandChars = value.ToArray(); } } private char[] _commandChars; @@ -54,16 +58,20 @@ namespace Discord.Commands if (e.Args == null) { int permissions = getPermissions(e.User); + StringBuilder output = new StringBuilder(); output.AppendLine("These are the commands you can use:"); output.Append("`"); - output.Append(string.Join(", ", _commands.Select(x => permissions >= x.MinPerms && !x.IsHidden))); + output.Append(string.Join(", ", _commands.Select(x => permissions >= x.MinPermissions && !x.IsHidden))); output.Append("`"); - if (_commandChars.Length == 1) - output.AppendLine($"\nYou can use `{_commandChars[0]}` to call a command."); - else - output.AppendLine($"\nYou can use `{string.Join(" ", CommandChars.Take(_commandChars.Length - 1))}` and `{_commandChars.Last()}` to call a command."); + if (_commandChars.Length > 0) + { + if (_commandChars.Length == 1) + output.AppendLine($"\nYou can use `{_commandChars[0]}` to call a command."); + else + output.AppendLine($"\nYou can use `{string.Join(" ", CommandChars.Take(_commandChars.Length - 1))}` and `{_commandChars.Last()}` to call a command."); + } output.AppendLine("`help ` can tell you more about how to use a command."); @@ -84,17 +92,17 @@ namespace Discord.Commands client.MessageReceived += async (s, e) => { - // This will need to be changed once a built in help command is made if (_commands.Count == 0) return; if (e.Message.IsAuthor) return; string msg = e.Message.Text; if (msg.Length == 0) return; + //Check for command char if one is provided if (_commandChars.Length > 0) { bool isPrivate = e.Message.Channel.IsPrivate; - bool hasCommandChar = CommandChars.Contains(msg[0]); + bool hasCommandChar = _commandChars.Contains(msg[0]); if (hasCommandChar) msg = msg.Substring(1); @@ -116,34 +124,27 @@ namespace Discord.Commands } else { + int userPermissions = _getPermissions != null ? _getPermissions(e.Message.User) : 0; + //Parse arguments - CommandPart[] args; - if (!CommandParser.ParseArgs(msg, argPos, command, out args)) + string[] args; + var error = CommandParser.ParseArgs(msg, argPos, command, out args); + if (error != null) { - CommandEventArgs errorArgs = new CommandEventArgs(e.Message, null, null, null); - RaiseCommandError(CommandErrorType.InvalidInput, errorArgs); + var errorArgs = new CommandEventArgs(e.Message, command, userPermissions, null); + RaiseCommandError(error.Value, errorArgs); return; } - int argCount = args.Length; - - //Get information for the rest of the steps - int userPermissions = _getPermissions != null ? _getPermissions(e.Message.User) : 0; - var eventArgs = new CommandEventArgs(e.Message, command, userPermissions, args.Select(x => x.Value).ToArray()); + + var eventArgs = new CommandEventArgs(e.Message, command, userPermissions, args); // Check permissions - if (userPermissions < command.MinPerms) + if (userPermissions < command.MinPermissions) { RaiseCommandError(CommandErrorType.BadPermissions, eventArgs); return; } - //Check arg count - if (argCount < command.MinArgs) - { - RaiseCommandError(CommandErrorType.BadArgCount, eventArgs); - return; - } - // Run the command try {