@@ -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<CommandParameter> Parameters => _parameters; | |||
private CommandParameter[] _parameters; | |||
internal CommandParameter[] _parameters; | |||
private Func<CommandEventArgs, Task> _handler; | |||
@@ -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); | |||
} | |||
} | |||
@@ -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<CommandPart> argList = new List<CommandPart>(); | |||
var expectedArgs = command._parameters; | |||
List<string> argList = new List<string>(); | |||
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; | |||
} | |||
} | |||
} |
@@ -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<char> 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 <command>` 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 | |||
{ | |||