Browse Source

change quotation mark parsing to use a map of matching pairs

pull/943/head
Chris Johnston 7 years ago
parent
commit
3e54e6fa04
4 changed files with 61 additions and 21 deletions
  1. +32
    -14
      src/Discord.Net.Commands/CommandParser.cs
  2. +2
    -2
      src/Discord.Net.Commands/CommandService.cs
  3. +25
    -3
      src/Discord.Net.Commands/CommandServiceConfig.cs
  4. +2
    -2
      src/Discord.Net.Commands/Info/CommandInfo.cs

+ 32
- 14
src/Discord.Net.Commands/CommandParser.cs View File

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


+ 2
- 2
src/Discord.Net.Commands/CommandService.cs View File

@@ -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.");




+ 25
- 3
src/Discord.Net.Commands/CommandServiceConfig.cs View File

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


+ 2
- 2
src/Discord.Net.Commands/Info/CommandInfo.cs View File

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




Loading…
Cancel
Save