| @@ -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 | |||
| } | |||
| /// <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) | |||
| { | |||
| ParameterInfo curParam = null; | |||
| @@ -37,7 +51,7 @@ namespace Discord.Commands | |||
| var argList = ImmutableArray.CreateBuilder<TypeReaderResult>(); | |||
| var paramList = ImmutableArray.CreateBuilder<TypeReaderResult>(); | |||
| 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; | |||
| @@ -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<char, char> _quotationMarkAliasMap; | |||
| public IEnumerable<ModuleInfo> Modules => _moduleDefs.Select(x => x); | |||
| public IEnumerable<CommandInfo> 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."); | |||
| @@ -1,4 +1,5 @@ | |||
| namespace Discord.Commands | |||
| using System.Collections.Generic; | |||
| namespace Discord.Commands | |||
| { | |||
| public class CommandServiceConfig | |||
| { | |||
| @@ -16,8 +17,29 @@ | |||
| /// <summary> Determines whether RunMode.Sync commands should push exceptions up to the caller. </summary> | |||
| 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> | |||
| public bool IgnoreExtraArgs { get; set; } = false; | |||
| @@ -20,7 +20,7 @@ namespace Discord.Commands | |||
| private readonly CommandService _commandService; | |||
| private readonly Func<ICommandContext, object[], IServiceProvider, CommandInfo, Task> _action; | |||
| internal readonly char[] _quotationAliases; | |||
| internal readonly Dictionary<char,char> _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; | |||
| } | |||