| @@ -32,7 +32,7 @@ namespace Discord.Commands | |||||
| public string Text { get; } | public string Text { get; } | ||||
| public int? MinArgs { get; private set; } | public int? MinArgs { get; private set; } | ||||
| public int? MaxArgs { 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 bool IsHidden { get; internal set; } | ||||
| public string Description { get; internal set; } | public string Description { get; internal set; } | ||||
| @@ -40,7 +40,7 @@ namespace Discord.Commands | |||||
| private string[] _aliases; | private string[] _aliases; | ||||
| public IEnumerable<CommandParameter> Parameters => _parameters; | public IEnumerable<CommandParameter> Parameters => _parameters; | ||||
| private CommandParameter[] _parameters; | |||||
| internal CommandParameter[] _parameters; | |||||
| private Func<CommandEventArgs, Task> _handler; | private Func<CommandEventArgs, Task> _handler; | ||||
| @@ -38,7 +38,7 @@ namespace Discord.Commands | |||||
| { | { | ||||
| if (_isClosed) | if (_isClosed) | ||||
| throw new Exception($"No parameters may be added after a {nameof(ParameterType.Multiple)} or {nameof(ParameterType.Unparsed)} parameter."); | 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"); | throw new Exception($"{nameof(ParameterType.Required)} parameters may not be added after an optional one"); | ||||
| _params.Add(new CommandParameter(name, type)); | _params.Add(new CommandParameter(name, type)); | ||||
| @@ -57,7 +57,7 @@ namespace Discord.Commands | |||||
| public CommandBuilder MinPermissions(int level) | public CommandBuilder MinPermissions(int level) | ||||
| { | { | ||||
| _command.MinPerms = level; | |||||
| _command.MinPermissions = level; | |||||
| return this; | return this; | ||||
| } | } | ||||
| @@ -125,7 +125,7 @@ namespace Discord.Commands | |||||
| public CommandBuilder CreateCommand(string cmd) | public CommandBuilder CreateCommand(string cmd) | ||||
| { | { | ||||
| var command = new Command(CommandBuilder.AppendPrefix(_prefix, cmd)); | var command = new Command(CommandBuilder.AppendPrefix(_prefix, cmd)); | ||||
| command.MinPerms = _defaultMinPermissions; | |||||
| command.MinPermissions = _defaultMinPermissions; | |||||
| return new CommandBuilder(_plugin, command, _prefix); | return new CommandBuilder(_plugin, command, _prefix); | ||||
| } | } | ||||
| } | } | ||||
| @@ -2,19 +2,6 @@ | |||||
| namespace Discord.Commands | 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 | internal static class CommandParser | ||||
| { | { | ||||
| private enum CommandParserPart | private enum CommandParserPart | ||||
| @@ -69,23 +56,40 @@ namespace Discord.Commands | |||||
| return command != null; | 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; | CommandParserPart currentPart = CommandParserPart.None; | ||||
| int startPosition = startPos; | int startPosition = startPos; | ||||
| int endPosition = startPos; | int endPosition = startPos; | ||||
| int inputLength = input.Length; | int inputLength = input.Length; | ||||
| bool isEscaped = false; | bool isEscaped = false; | ||||
| List<CommandPart> argList = new List<CommandPart>(); | |||||
| var expectedArgs = command._parameters; | |||||
| List<string> argList = new List<string>(); | |||||
| CommandParameter parameter = null; | |||||
| args = null; | args = null; | ||||
| if (input == "") | if (input == "") | ||||
| return false; | |||||
| return CommandErrorType.InvalidInput; | |||||
| while (endPosition < inputLength) | 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) | if (isEscaped) | ||||
| isEscaped = false; | isEscaped = false; | ||||
| else if (currentChar == '\\') | else if (currentChar == '\\') | ||||
| @@ -113,7 +117,7 @@ namespace Discord.Commands | |||||
| else | else | ||||
| { | { | ||||
| currentPart = CommandParserPart.None; | currentPart = CommandParserPart.None; | ||||
| argList.Add(new CommandPart(temp, startPosition)); | |||||
| argList.Add(temp); | |||||
| startPosition = endPosition; | startPosition = endPosition; | ||||
| } | } | ||||
| } | } | ||||
| @@ -123,28 +127,31 @@ namespace Discord.Commands | |||||
| { | { | ||||
| string temp = input.Substring(startPosition, endPosition - startPosition - 1); | string temp = input.Substring(startPosition, endPosition - startPosition - 1); | ||||
| currentPart = CommandParserPart.None; | currentPart = CommandParserPart.None; | ||||
| argList.Add(new CommandPart(temp, startPosition)); | |||||
| argList.Add(temp); | |||||
| startPosition = endPosition; | startPosition = endPosition; | ||||
| } | } | ||||
| else if (endPosition >= inputLength) | else if (endPosition >= inputLength) | ||||
| return false; | |||||
| return CommandErrorType.InvalidInput; | |||||
| break; | break; | ||||
| case CommandParserPart.DoubleQuotedParameter: | case CommandParserPart.DoubleQuotedParameter: | ||||
| if ((!isEscaped && currentChar == '\"')) | if ((!isEscaped && currentChar == '\"')) | ||||
| { | { | ||||
| string temp = input.Substring(startPosition, endPosition - startPosition - 1); | string temp = input.Substring(startPosition, endPosition - startPosition - 1); | ||||
| currentPart = CommandParserPart.None; | currentPart = CommandParserPart.None; | ||||
| argList.Add(new CommandPart(temp, startPosition)); | |||||
| argList.Add(temp); | |||||
| startPosition = endPosition; | startPosition = endPosition; | ||||
| } | } | ||||
| else if (endPosition >= inputLength) | else if (endPosition >= inputLength) | ||||
| return false; | |||||
| return CommandErrorType.InvalidInput; | |||||
| break; | break; | ||||
| } | } | ||||
| } | } | ||||
| if (argList.Count < command.MinArgs) | |||||
| return CommandErrorType.BadArgCount; | |||||
| args = argList.ToArray(); | args = argList.ToArray(); | ||||
| return true; | |||||
| return null; | |||||
| } | } | ||||
| } | } | ||||
| } | } | ||||
| @@ -18,7 +18,11 @@ namespace Discord.Commands | |||||
| internal CommandMap Map => _map; | internal CommandMap Map => _map; | ||||
| private readonly CommandMap _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<char> CommandChars { get { return _commandChars; } set { _commandChars = value.ToArray(); } } | public IEnumerable<char> CommandChars { get { return _commandChars; } set { _commandChars = value.ToArray(); } } | ||||
| private char[] _commandChars; | private char[] _commandChars; | ||||
| @@ -54,16 +58,20 @@ namespace Discord.Commands | |||||
| if (e.Args == null) | if (e.Args == null) | ||||
| { | { | ||||
| int permissions = getPermissions(e.User); | int permissions = getPermissions(e.User); | ||||
| StringBuilder output = new StringBuilder(); | StringBuilder output = new StringBuilder(); | ||||
| output.AppendLine("These are the commands you can use:"); | output.AppendLine("These are the commands you can use:"); | ||||
| output.Append("`"); | 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("`"); | 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 <command>` can tell you more about how to use a command."); | output.AppendLine("`help <command>` can tell you more about how to use a command."); | ||||
| @@ -84,17 +92,17 @@ namespace Discord.Commands | |||||
| client.MessageReceived += async (s, e) => | 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 (_commands.Count == 0) return; | ||||
| if (e.Message.IsAuthor) return; | if (e.Message.IsAuthor) return; | ||||
| string msg = e.Message.Text; | string msg = e.Message.Text; | ||||
| if (msg.Length == 0) return; | if (msg.Length == 0) return; | ||||
| //Check for command char if one is provided | |||||
| if (_commandChars.Length > 0) | if (_commandChars.Length > 0) | ||||
| { | { | ||||
| bool isPrivate = e.Message.Channel.IsPrivate; | bool isPrivate = e.Message.Channel.IsPrivate; | ||||
| bool hasCommandChar = CommandChars.Contains(msg[0]); | |||||
| bool hasCommandChar = _commandChars.Contains(msg[0]); | |||||
| if (hasCommandChar) | if (hasCommandChar) | ||||
| msg = msg.Substring(1); | msg = msg.Substring(1); | ||||
| @@ -116,34 +124,27 @@ namespace Discord.Commands | |||||
| } | } | ||||
| else | else | ||||
| { | { | ||||
| int userPermissions = _getPermissions != null ? _getPermissions(e.Message.User) : 0; | |||||
| //Parse arguments | //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; | 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 | // Check permissions | ||||
| if (userPermissions < command.MinPerms) | |||||
| if (userPermissions < command.MinPermissions) | |||||
| { | { | ||||
| RaiseCommandError(CommandErrorType.BadPermissions, eventArgs); | RaiseCommandError(CommandErrorType.BadPermissions, eventArgs); | ||||
| return; | return; | ||||
| } | } | ||||
| //Check arg count | |||||
| if (argCount < command.MinArgs) | |||||
| { | |||||
| RaiseCommandError(CommandErrorType.BadArgCount, eventArgs); | |||||
| return; | |||||
| } | |||||
| // Run the command | // Run the command | ||||
| try | try | ||||
| { | { | ||||