@@ -1,4 +1,5 @@ | |||||
using System; | using System; | ||||
using System.Collections.Generic; | |||||
using System.Collections.Immutable; | using System.Collections.Immutable; | ||||
using System.Text; | using System.Text; | ||||
using System.Threading.Tasks; | using System.Threading.Tasks; | ||||
@@ -14,19 +15,32 @@ namespace Discord.Commands | |||||
QuotedParameter | QuotedParameter | ||||
} | } | ||||
/// <summary> | |||||
/// Checks to see if the supplied character is a quotation mark | |||||
/// from either the default " character, or the list of aliases | |||||
/// if they are provided. | |||||
/// </summary> | |||||
/// <param name="c"></param> | |||||
/// <param name="aliases"></param> | |||||
private static bool isQuotationChar(char c, char[] aliases) | |||||
private static bool isOpenQuote(Dictionary<char,char> map, char c) | |||||
{ | { | ||||
if (aliases == null) return c == '\"'; | |||||
return Array.Exists(aliases, x => x == c); | |||||
// determine if the map contains the key for this value | |||||
if(map != null) | |||||
{ | |||||
return map.ContainsKey(c); | |||||
} | |||||
// or if the value is a normal quote " | |||||
return c == '\"'; | |||||
} | |||||
// get the corresponding matching quote for the key | |||||
private static char getMatch(Dictionary<char,char> map, char c) | |||||
{ | |||||
if (map != null) | |||||
{ | |||||
char value; | |||||
if( map.TryGetValue(c, out value)) | |||||
{ | |||||
return value; | |||||
} | |||||
} | |||||
return '\"'; | |||||
} | } | ||||
public static async Task<ParseResult> ParseArgsAsync(CommandInfo command, ICommandContext context, bool ignoreExtraArgs, IServiceProvider services, string input, int startPos) | public static async Task<ParseResult> ParseArgsAsync(CommandInfo command, ICommandContext context, bool ignoreExtraArgs, IServiceProvider services, string input, int startPos) | ||||
{ | { | ||||
ParameterInfo curParam = null; | ParameterInfo curParam = null; | ||||
@@ -37,7 +51,7 @@ namespace Discord.Commands | |||||
var argList = ImmutableArray.CreateBuilder<TypeReaderResult>(); | var argList = ImmutableArray.CreateBuilder<TypeReaderResult>(); | ||||
var paramList = ImmutableArray.CreateBuilder<TypeReaderResult>(); | var paramList = ImmutableArray.CreateBuilder<TypeReaderResult>(); | ||||
bool isEscaping = false; | bool isEscaping = false; | ||||
char c; | |||||
char c, matchQuote = '\0'; | |||||
for (int curPos = startPos; curPos <= endPos; curPos++) | for (int curPos = startPos; curPos <= endPos; curPos++) | ||||
{ | { | ||||
@@ -87,9 +101,11 @@ namespace Discord.Commands | |||||
argBuilder.Append(c); | argBuilder.Append(c); | ||||
continue; | continue; | ||||
} | } | ||||
if (isQuotationChar(c, command._quotationAliases)) | |||||
if(isOpenQuote(command._quotationAliases, c)) | |||||
{ | { | ||||
curPart = ParserPart.QuotedParameter; | curPart = ParserPart.QuotedParameter; | ||||
matchQuote = getMatch(command._quotationAliases, c); | |||||
continue; | continue; | ||||
} | } | ||||
curPart = ParserPart.Parameter; | curPart = ParserPart.Parameter; | ||||
@@ -110,7 +126,9 @@ namespace Discord.Commands | |||||
} | } | ||||
else if (curPart == ParserPart.QuotedParameter) | else if (curPart == ParserPart.QuotedParameter) | ||||
{ | { | ||||
if (isQuotationChar(c, command._quotationAliases)) | |||||
//if (findQuotationChar(c, false, out matchingQuotation)) | |||||
//if( matchingQuotation != null && matchingQuotation.Right == c) | |||||
if(c == matchQuote) | |||||
{ | { | ||||
argString = argBuilder.ToString(); //Remove quotes | argString = argBuilder.ToString(); //Remove quotes | ||||
lastArgEndPos = curPos + 1; | lastArgEndPos = curPos + 1; | ||||
@@ -32,7 +32,7 @@ namespace Discord.Commands | |||||
internal readonly RunMode _defaultRunMode; | internal readonly RunMode _defaultRunMode; | ||||
internal readonly Logger _cmdLogger; | internal readonly Logger _cmdLogger; | ||||
internal readonly LogManager _logManager; | internal readonly LogManager _logManager; | ||||
internal readonly char[] _quotationMarkAliases; | |||||
internal readonly Dictionary<char, char> _quotationMarkAliasMap; | |||||
public IEnumerable<ModuleInfo> Modules => _moduleDefs.Select(x => x); | public IEnumerable<ModuleInfo> Modules => _moduleDefs.Select(x => x); | ||||
public IEnumerable<CommandInfo> Commands => _moduleDefs.SelectMany(x => x.Commands); | public IEnumerable<CommandInfo> Commands => _moduleDefs.SelectMany(x => x.Commands); | ||||
@@ -46,7 +46,7 @@ namespace Discord.Commands | |||||
_ignoreExtraArgs = config.IgnoreExtraArgs; | _ignoreExtraArgs = config.IgnoreExtraArgs; | ||||
_separatorChar = config.SeparatorChar; | _separatorChar = config.SeparatorChar; | ||||
_defaultRunMode = config.DefaultRunMode; | _defaultRunMode = config.DefaultRunMode; | ||||
_quotationMarkAliases = config.QuotationMarkAliases; | |||||
_quotationMarkAliasMap = config.QuotationMarkAliasMap; | |||||
if (_defaultRunMode == RunMode.Default) | if (_defaultRunMode == RunMode.Default) | ||||
throw new InvalidOperationException("The default run mode cannot be set to Default."); | throw new InvalidOperationException("The default run mode cannot be set to Default."); | ||||
@@ -1,4 +1,5 @@ | |||||
namespace Discord.Commands | |||||
using System.Collections.Generic; | |||||
namespace Discord.Commands | |||||
{ | { | ||||
public class CommandServiceConfig | public class CommandServiceConfig | ||||
{ | { | ||||
@@ -16,8 +17,29 @@ | |||||
/// <summary> Determines whether RunMode.Sync commands should push exceptions up to the caller. </summary> | /// <summary> Determines whether RunMode.Sync commands should push exceptions up to the caller. </summary> | ||||
public bool ThrowOnError { get; set; } = true; | public bool ThrowOnError { get; set; } = true; | ||||
/// <summary> List of aliases for string parsing </summary> | |||||
public char[] QuotationMarkAliases { get; set; } = new char[] { '\"', '“', '”', '«', '»', '‹', '›' }; | |||||
/// <summary> Collection of aliases that can wrap strings for command parsing. | |||||
/// represents the opening quotation mark and the value is the corresponding closing mark.</summary> | |||||
public Dictionary<char, char> QuotationMarkAliasMap { get; set; } | |||||
= new Dictionary<char, char>() | |||||
{ | |||||
{'\"', '\"' }, | |||||
{'«', '»' }, | |||||
{'‘', '’' }, | |||||
{'“', '”' }, | |||||
{'„', '‟' }, | |||||
{'‹', '›' }, | |||||
{'‚', '‛' }, | |||||
{'《', '》' }, | |||||
{'〈', '〉' }, | |||||
{'「', '」' }, | |||||
{'『', '』' }, | |||||
{'〝', '〞' }, | |||||
{'﹁', '﹂' }, | |||||
{'﹃', '﹄' }, | |||||
{'"', '"' }, | |||||
{''', ''' }, | |||||
{'「', '」' } | |||||
}; | |||||
/// <summary> Determines whether extra parameters should be ignored. </summary> | /// <summary> Determines whether extra parameters should be ignored. </summary> | ||||
public bool IgnoreExtraArgs { get; set; } = false; | public bool IgnoreExtraArgs { get; set; } = false; | ||||
@@ -20,7 +20,7 @@ namespace Discord.Commands | |||||
private readonly CommandService _commandService; | private readonly CommandService _commandService; | ||||
private readonly Func<ICommandContext, object[], IServiceProvider, CommandInfo, Task> _action; | private readonly Func<ICommandContext, object[], IServiceProvider, CommandInfo, Task> _action; | ||||
internal readonly char[] _quotationAliases; | |||||
internal readonly Dictionary<char,char> _quotationAliases; | |||||
public ModuleInfo Module { get; } | public ModuleInfo Module { get; } | ||||
public string Name { get; } | public string Name { get; } | ||||
@@ -66,7 +66,7 @@ namespace Discord.Commands | |||||
HasVarArgs = builder.Parameters.Count > 0 ? builder.Parameters[builder.Parameters.Count - 1].IsMultiple : false; | HasVarArgs = builder.Parameters.Count > 0 ? builder.Parameters[builder.Parameters.Count - 1].IsMultiple : false; | ||||
_action = builder.Callback; | _action = builder.Callback; | ||||
_quotationAliases = service._quotationMarkAliases; | |||||
_quotationAliases = service._quotationMarkAliasMap; | |||||
_commandService = service; | _commandService = service; | ||||
} | } | ||||