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