| @@ -20,6 +20,7 @@ namespace Discord.Commands | |||||
| private readonly CommandMap _map; | private readonly CommandMap _map; | ||||
| internal readonly RunMode _defaultRunMode; | internal readonly RunMode _defaultRunMode; | ||||
| internal readonly string _nodeSeparator; | |||||
| 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); | ||||
| @@ -30,7 +31,6 @@ namespace Discord.Commands | |||||
| _moduleLock = new SemaphoreSlim(1, 1); | _moduleLock = new SemaphoreSlim(1, 1); | ||||
| _typedModuleDefs = new ConcurrentDictionary<Type, ModuleInfo>(); | _typedModuleDefs = new ConcurrentDictionary<Type, ModuleInfo>(); | ||||
| _moduleDefs = new ConcurrentBag<ModuleInfo>(); | _moduleDefs = new ConcurrentBag<ModuleInfo>(); | ||||
| _map = new CommandMap(); | |||||
| _typeReaders = new ConcurrentDictionary<Type, TypeReader> | _typeReaders = new ConcurrentDictionary<Type, TypeReader> | ||||
| { | { | ||||
| [typeof(bool)] = new SimpleTypeReader<bool>(), | [typeof(bool)] = new SimpleTypeReader<bool>(), | ||||
| @@ -68,6 +68,8 @@ namespace Discord.Commands | |||||
| [typeof(IGuildUser)] = new UserTypeReader<IGuildUser>(), | [typeof(IGuildUser)] = new UserTypeReader<IGuildUser>(), | ||||
| }; | }; | ||||
| _defaultRunMode = config.DefaultRunMode; | _defaultRunMode = config.DefaultRunMode; | ||||
| _nodeSeparator = config.NodeSeparator; | |||||
| _map = new CommandMap(this); | |||||
| } | } | ||||
| //Modules | //Modules | ||||
| @@ -4,5 +4,7 @@ | |||||
| { | { | ||||
| /// <summary> The default RunMode commands should have, if one is not specified on the Command attribute or builder. </summary> | /// <summary> The default RunMode commands should have, if one is not specified on the Command attribute or builder. </summary> | ||||
| public RunMode DefaultRunMode { get; set; } = RunMode.Mixed; | public RunMode DefaultRunMode { get; set; } = RunMode.Mixed; | ||||
| /// <summary> What character should be used between command nodes</summary> | |||||
| public string NodeSeparator { get; set; } = " "; | |||||
| } | } | ||||
| } | } | ||||
| @@ -42,7 +42,7 @@ namespace Discord.Commands | |||||
| // both command and module provide aliases | // both command and module provide aliases | ||||
| if (module.Aliases.Count > 0 && builder.Aliases.Count > 0) | if (module.Aliases.Count > 0 && builder.Aliases.Count > 0) | ||||
| Aliases = module.Aliases.Permutate(builder.Aliases, (first, second) => second != null ? first + " " + second : first).ToImmutableArray(); | |||||
| Aliases = module.Aliases.Permutate(builder.Aliases, (first, second) => second != null ? first + service._nodeSeparator + second : first).ToImmutableArray(); | |||||
| // only module provides aliases | // only module provides aliases | ||||
| else if (module.Aliases.Count > 0) | else if (module.Aliases.Count > 0) | ||||
| Aliases = module.Aliases.ToImmutableArray(); | Aliases = module.Aliases.ToImmutableArray(); | ||||
| @@ -7,9 +7,9 @@ namespace Discord.Commands | |||||
| private readonly CommandMapNode _root; | private readonly CommandMapNode _root; | ||||
| private static readonly string[] _blankAliases = new[] { "" }; | private static readonly string[] _blankAliases = new[] { "" }; | ||||
| public CommandMap() | |||||
| public CommandMap(CommandService service) | |||||
| { | { | ||||
| _root = new CommandMapNode(""); | |||||
| _root = new CommandMapNode("", service); | |||||
| } | } | ||||
| public void AddCommand(CommandInfo command) | public void AddCommand(CommandInfo command) | ||||
| @@ -7,25 +7,25 @@ namespace Discord.Commands | |||||
| { | { | ||||
| internal class CommandMapNode | internal class CommandMapNode | ||||
| { | { | ||||
| private static readonly char[] _whitespaceChars = new char[] { ' ', '\r', '\n' }; | |||||
| private readonly ConcurrentDictionary<string, CommandMapNode> _nodes; | private readonly ConcurrentDictionary<string, CommandMapNode> _nodes; | ||||
| private readonly string _name; | private readonly string _name; | ||||
| private readonly object _lockObj = new object(); | private readonly object _lockObj = new object(); | ||||
| private readonly CommandService _service; | |||||
| private ImmutableArray<CommandInfo> _commands; | private ImmutableArray<CommandInfo> _commands; | ||||
| public bool IsEmpty => _commands.Length == 0 && _nodes.Count == 0; | public bool IsEmpty => _commands.Length == 0 && _nodes.Count == 0; | ||||
| public CommandMapNode(string name) | |||||
| public CommandMapNode(string name, CommandService service) | |||||
| { | { | ||||
| _name = name; | _name = name; | ||||
| _nodes = new ConcurrentDictionary<string, CommandMapNode>(); | _nodes = new ConcurrentDictionary<string, CommandMapNode>(); | ||||
| _commands = ImmutableArray.Create<CommandInfo>(); | _commands = ImmutableArray.Create<CommandInfo>(); | ||||
| _service = service; | |||||
| } | } | ||||
| public void AddCommand(string text, int index, CommandInfo command) | public void AddCommand(string text, int index, CommandInfo command) | ||||
| { | { | ||||
| int nextSpace = NextWhitespace(text, index); | |||||
| int nextSpace = NextSeparator(text, index); | |||||
| string name; | string name; | ||||
| lock (_lockObj) | lock (_lockObj) | ||||
| @@ -43,14 +43,14 @@ namespace Discord.Commands | |||||
| else | else | ||||
| name = text.Substring(index, nextSpace - index); | name = text.Substring(index, nextSpace - index); | ||||
| var nextNode = _nodes.GetOrAdd(name, x => new CommandMapNode(x)); | |||||
| var nextNode = _nodes.GetOrAdd(name, x => new CommandMapNode(x, _service)); | |||||
| nextNode.AddCommand(nextSpace == -1 ? "" : text, nextSpace + 1, command); | nextNode.AddCommand(nextSpace == -1 ? "" : text, nextSpace + 1, command); | ||||
| } | } | ||||
| } | } | ||||
| } | } | ||||
| public void RemoveCommand(string text, int index, CommandInfo command) | public void RemoveCommand(string text, int index, CommandInfo command) | ||||
| { | { | ||||
| int nextSpace = NextWhitespace(text, index); | |||||
| int nextSpace = NextSeparator(text, index); | |||||
| string name; | string name; | ||||
| lock (_lockObj) | lock (_lockObj) | ||||
| @@ -77,7 +77,7 @@ namespace Discord.Commands | |||||
| public IEnumerable<CommandInfo> GetCommands(string text, int index) | public IEnumerable<CommandInfo> GetCommands(string text, int index) | ||||
| { | { | ||||
| int nextSpace = NextWhitespace(text, index); | |||||
| int nextSpace = NextSeparator(text, index); | |||||
| string name; | string name; | ||||
| var commands = _commands; | var commands = _commands; | ||||
| @@ -100,15 +100,12 @@ namespace Discord.Commands | |||||
| } | } | ||||
| } | } | ||||
| private static int NextWhitespace(string text, int startIndex) | |||||
| private int NextSeparator(string text, int startIndex) | |||||
| { | { | ||||
| int lowest = int.MaxValue; | int lowest = int.MaxValue; | ||||
| for (int i = 0; i < _whitespaceChars.Length; i++) | |||||
| { | |||||
| int index = text.IndexOf(_whitespaceChars[i], startIndex); | |||||
| if (index != -1 && index < lowest) | |||||
| int index = text.IndexOf(_service._nodeSeparator, startIndex); | |||||
| if (index != -1 && index < lowest) | |||||
| lowest = index; | lowest = index; | ||||
| } | |||||
| return (lowest != int.MaxValue) ? lowest : -1; | return (lowest != int.MaxValue) ? lowest : -1; | ||||
| } | } | ||||
| } | } | ||||