From 3e54e6fa044fa683cd9168bb0ccef972476613d0 Mon Sep 17 00:00:00 2001 From: Chris Johnston Date: Sun, 28 Jan 2018 16:41:09 -0800 Subject: [PATCH] change quotation mark parsing to use a map of matching pairs --- src/Discord.Net.Commands/CommandParser.cs | 46 +++++++++++++------ src/Discord.Net.Commands/CommandService.cs | 4 +- .../CommandServiceConfig.cs | 28 +++++++++-- src/Discord.Net.Commands/Info/CommandInfo.cs | 4 +- 4 files changed, 61 insertions(+), 21 deletions(-) diff --git a/src/Discord.Net.Commands/CommandParser.cs b/src/Discord.Net.Commands/CommandParser.cs index 96b946444..bc535ff74 100644 --- a/src/Discord.Net.Commands/CommandParser.cs +++ b/src/Discord.Net.Commands/CommandParser.cs @@ -1,4 +1,5 @@ using System; +using System.Collections.Generic; using System.Collections.Immutable; using System.Text; using System.Threading.Tasks; @@ -14,19 +15,32 @@ namespace Discord.Commands QuotedParameter } - /// - /// 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. - /// - /// - /// - private static bool isQuotationChar(char c, char[] aliases) + private static bool isOpenQuote(Dictionary 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 map, char c) + { + if (map != null) + { + char value; + if( map.TryGetValue(c, out value)) + { + return value; + } + } + + return '\"'; } - + public static async Task ParseArgsAsync(CommandInfo command, ICommandContext context, bool ignoreExtraArgs, IServiceProvider services, string input, int startPos) { ParameterInfo curParam = null; @@ -37,7 +51,7 @@ namespace Discord.Commands var argList = ImmutableArray.CreateBuilder(); var paramList = ImmutableArray.CreateBuilder(); bool isEscaping = false; - char c; + char c, matchQuote = '\0'; for (int curPos = startPos; curPos <= endPos; curPos++) { @@ -87,9 +101,11 @@ namespace Discord.Commands argBuilder.Append(c); continue; } - if (isQuotationChar(c, command._quotationAliases)) + + if(isOpenQuote(command._quotationAliases, c)) { curPart = ParserPart.QuotedParameter; + matchQuote = getMatch(command._quotationAliases, c); continue; } curPart = ParserPart.Parameter; @@ -110,7 +126,9 @@ namespace Discord.Commands } 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 lastArgEndPos = curPos + 1; diff --git a/src/Discord.Net.Commands/CommandService.cs b/src/Discord.Net.Commands/CommandService.cs index 67d721dbb..02f1da5c3 100644 --- a/src/Discord.Net.Commands/CommandService.cs +++ b/src/Discord.Net.Commands/CommandService.cs @@ -32,7 +32,7 @@ namespace Discord.Commands internal readonly RunMode _defaultRunMode; internal readonly Logger _cmdLogger; internal readonly LogManager _logManager; - internal readonly char[] _quotationMarkAliases; + internal readonly Dictionary _quotationMarkAliasMap; public IEnumerable Modules => _moduleDefs.Select(x => x); public IEnumerable Commands => _moduleDefs.SelectMany(x => x.Commands); @@ -46,7 +46,7 @@ namespace Discord.Commands _ignoreExtraArgs = config.IgnoreExtraArgs; _separatorChar = config.SeparatorChar; _defaultRunMode = config.DefaultRunMode; - _quotationMarkAliases = config.QuotationMarkAliases; + _quotationMarkAliasMap = config.QuotationMarkAliasMap; if (_defaultRunMode == RunMode.Default) throw new InvalidOperationException("The default run mode cannot be set to Default."); diff --git a/src/Discord.Net.Commands/CommandServiceConfig.cs b/src/Discord.Net.Commands/CommandServiceConfig.cs index 3985a39a7..6de61f939 100644 --- a/src/Discord.Net.Commands/CommandServiceConfig.cs +++ b/src/Discord.Net.Commands/CommandServiceConfig.cs @@ -1,4 +1,5 @@ -namespace Discord.Commands +using System.Collections.Generic; +namespace Discord.Commands { public class CommandServiceConfig { @@ -16,8 +17,29 @@ /// Determines whether RunMode.Sync commands should push exceptions up to the caller. public bool ThrowOnError { get; set; } = true; - /// List of aliases for string parsing - public char[] QuotationMarkAliases { get; set; } = new char[] { '\"', '“', '”', '«', '»', '‹', '›' }; + /// Collection of aliases that can wrap strings for command parsing. + /// represents the opening quotation mark and the value is the corresponding closing mark. + public Dictionary QuotationMarkAliasMap { get; set; } + = new Dictionary() + { + {'\"', '\"' }, + {'«', '»' }, + {'‘', '’' }, + {'“', '”' }, + {'„', '‟' }, + {'‹', '›' }, + {'‚', '‛' }, + {'《', '》' }, + {'〈', '〉' }, + {'「', '」' }, + {'『', '』' }, + {'〝', '〞' }, + {'﹁', '﹂' }, + {'﹃', '﹄' }, + {'"', '"' }, + {''', ''' }, + {'「', '」' } + }; /// Determines whether extra parameters should be ignored. public bool IgnoreExtraArgs { get; set; } = false; diff --git a/src/Discord.Net.Commands/Info/CommandInfo.cs b/src/Discord.Net.Commands/Info/CommandInfo.cs index 781a0212f..4dee863b5 100644 --- a/src/Discord.Net.Commands/Info/CommandInfo.cs +++ b/src/Discord.Net.Commands/Info/CommandInfo.cs @@ -20,7 +20,7 @@ namespace Discord.Commands private readonly CommandService _commandService; private readonly Func _action; - internal readonly char[] _quotationAliases; + internal readonly Dictionary _quotationAliases; public ModuleInfo Module { 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; _action = builder.Callback; - _quotationAliases = service._quotationMarkAliases; + _quotationAliases = service._quotationMarkAliasMap; _commandService = service; }