Implemented new CommandMap
This commit is contained in:
@@ -14,8 +14,8 @@ namespace Discord.Commands
|
|||||||
{
|
{
|
||||||
private readonly SemaphoreSlim _moduleLock;
|
private readonly SemaphoreSlim _moduleLock;
|
||||||
private readonly ConcurrentDictionary<object, Module> _modules;
|
private readonly ConcurrentDictionary<object, Module> _modules;
|
||||||
private readonly ConcurrentDictionary<string, List<Command>> _map;
|
|
||||||
private readonly ConcurrentDictionary<Type, TypeReader> _typeReaders;
|
private readonly ConcurrentDictionary<Type, TypeReader> _typeReaders;
|
||||||
|
private readonly CommandMap _map;
|
||||||
|
|
||||||
public IEnumerable<Module> Modules => _modules.Select(x => x.Value);
|
public IEnumerable<Module> Modules => _modules.Select(x => x.Value);
|
||||||
public IEnumerable<Command> Commands => _modules.SelectMany(x => x.Value.Commands);
|
public IEnumerable<Command> Commands => _modules.SelectMany(x => x.Value.Commands);
|
||||||
@@ -24,7 +24,7 @@ namespace Discord.Commands
|
|||||||
{
|
{
|
||||||
_moduleLock = new SemaphoreSlim(1, 1);
|
_moduleLock = new SemaphoreSlim(1, 1);
|
||||||
_modules = new ConcurrentDictionary<object, Module>();
|
_modules = new ConcurrentDictionary<object, Module>();
|
||||||
_map = new ConcurrentDictionary<string, List<Command>>();
|
_map = new CommandMap();
|
||||||
_typeReaders = new ConcurrentDictionary<Type, TypeReader>
|
_typeReaders = new ConcurrentDictionary<Type, TypeReader>
|
||||||
{
|
{
|
||||||
[typeof(string)] = new GenericTypeReader((m, s) => Task.FromResult(TypeReaderResult.FromSuccess(s))),
|
[typeof(string)] = new GenericTypeReader((m, s) => Task.FromResult(TypeReaderResult.FromSuccess(s))),
|
||||||
@@ -160,11 +160,7 @@ namespace Discord.Commands
|
|||||||
_modules[moduleInstance] = loadedModule;
|
_modules[moduleInstance] = loadedModule;
|
||||||
|
|
||||||
foreach (var cmd in loadedModule.Commands)
|
foreach (var cmd in loadedModule.Commands)
|
||||||
{
|
_map.AddCommand(cmd);
|
||||||
var list = _map.GetOrAdd(cmd.Text, _ => new List<Command>());
|
|
||||||
lock (list)
|
|
||||||
list.Add(cmd);
|
|
||||||
}
|
|
||||||
|
|
||||||
return loadedModule;
|
return loadedModule;
|
||||||
}
|
}
|
||||||
@@ -222,14 +218,7 @@ namespace Discord.Commands
|
|||||||
if (_modules.TryRemove(module, out unloadedModule))
|
if (_modules.TryRemove(module, out unloadedModule))
|
||||||
{
|
{
|
||||||
foreach (var cmd in unloadedModule.Commands)
|
foreach (var cmd in unloadedModule.Commands)
|
||||||
{
|
_map.RemoveCommand(cmd);
|
||||||
List<Command> list;
|
|
||||||
if (_map.TryGetValue(cmd.Text, out list))
|
|
||||||
{
|
|
||||||
lock (list)
|
|
||||||
list.Remove(cmd);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
@@ -240,35 +229,10 @@ namespace Discord.Commands
|
|||||||
public SearchResult Search(IMessage message, string input)
|
public SearchResult Search(IMessage message, string input)
|
||||||
{
|
{
|
||||||
string lowerInput = input.ToLowerInvariant();
|
string lowerInput = input.ToLowerInvariant();
|
||||||
|
var matches = _map.GetCommands(input).ToImmutableArray();
|
||||||
ImmutableArray<Command>.Builder matches = null;
|
|
||||||
List<Command> group;
|
|
||||||
int pos = -1;
|
|
||||||
|
|
||||||
while (true)
|
|
||||||
{
|
|
||||||
pos = input.IndexOf(' ', pos + 1);
|
|
||||||
string cmdText = pos == -1 ? input : input.Substring(0, pos);
|
|
||||||
if (!_map.TryGetValue(cmdText, out group))
|
|
||||||
break;
|
|
||||||
|
|
||||||
lock (group)
|
|
||||||
{
|
|
||||||
if (matches == null)
|
|
||||||
matches = ImmutableArray.CreateBuilder<Command>(group.Count);
|
|
||||||
for (int i = 0; i < group.Count; i++)
|
|
||||||
matches.Add(group[i]);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (pos == -1)
|
|
||||||
{
|
|
||||||
pos = input.Length;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (matches != null)
|
if (matches.Length > 0)
|
||||||
return SearchResult.FromSuccess(input, matches.ToImmutable());
|
return SearchResult.FromSuccess(input, matches);
|
||||||
else
|
else
|
||||||
return SearchResult.FromError(CommandError.UnknownCommand, "Unknown command.");
|
return SearchResult.FromError(CommandError.UnknownCommand, "Unknown command.");
|
||||||
}
|
}
|
||||||
|
|||||||
76
src/Discord.Net.Commands/Map/CommandMap.cs
Normal file
76
src/Discord.Net.Commands/Map/CommandMap.cs
Normal file
@@ -0,0 +1,76 @@
|
|||||||
|
using System.Collections.Concurrent;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Collections.Immutable;
|
||||||
|
using System.Linq;
|
||||||
|
|
||||||
|
namespace Discord.Commands
|
||||||
|
{
|
||||||
|
internal class CommandMap
|
||||||
|
{
|
||||||
|
private readonly ConcurrentDictionary<string, CommandMapNode> _nodes;
|
||||||
|
|
||||||
|
public CommandMap()
|
||||||
|
{
|
||||||
|
_nodes = new ConcurrentDictionary<string, CommandMapNode>();
|
||||||
|
}
|
||||||
|
|
||||||
|
public void AddCommand(Command command)
|
||||||
|
{
|
||||||
|
string text = command.Text;
|
||||||
|
int nextSpace = text.IndexOf(' ');
|
||||||
|
string name;
|
||||||
|
|
||||||
|
lock (this)
|
||||||
|
{
|
||||||
|
if (nextSpace == -1)
|
||||||
|
name = command.Text;
|
||||||
|
else
|
||||||
|
name = command.Text.Substring(0, nextSpace);
|
||||||
|
var nextNode = _nodes.GetOrAdd(name, x => new CommandMapNode(x));
|
||||||
|
nextNode.AddCommand(nextSpace == -1 ? "" : text, nextSpace + 1, command);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
public void RemoveCommand(Command command)
|
||||||
|
{
|
||||||
|
string text = command.Text;
|
||||||
|
int nextSpace = text.IndexOf(' ');
|
||||||
|
string name;
|
||||||
|
|
||||||
|
lock (this)
|
||||||
|
{
|
||||||
|
if (nextSpace == -1)
|
||||||
|
name = command.Text;
|
||||||
|
else
|
||||||
|
name = command.Text.Substring(0, nextSpace);
|
||||||
|
|
||||||
|
CommandMapNode nextNode;
|
||||||
|
if (_nodes.TryGetValue(name, out nextNode))
|
||||||
|
{
|
||||||
|
nextNode.AddCommand(nextSpace == -1 ? "" : text, nextSpace + 1, command);
|
||||||
|
if (nextNode.IsEmpty)
|
||||||
|
_nodes.TryRemove(name, out nextNode);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public IEnumerable<Command> GetCommands(string text)
|
||||||
|
{
|
||||||
|
int nextSpace = text.IndexOf(' ');
|
||||||
|
string name;
|
||||||
|
|
||||||
|
lock (this)
|
||||||
|
{
|
||||||
|
if (nextSpace == -1)
|
||||||
|
name = text;
|
||||||
|
else
|
||||||
|
name = text.Substring(0, nextSpace);
|
||||||
|
|
||||||
|
CommandMapNode nextNode;
|
||||||
|
if (_nodes.TryGetValue(name, out nextNode))
|
||||||
|
return nextNode.GetCommands(text, nextSpace + 1);
|
||||||
|
else
|
||||||
|
return Enumerable.Empty<Command>();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
95
src/Discord.Net.Commands/Map/CommandMapNode.cs
Normal file
95
src/Discord.Net.Commands/Map/CommandMapNode.cs
Normal file
@@ -0,0 +1,95 @@
|
|||||||
|
using System.Collections.Concurrent;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Collections.Immutable;
|
||||||
|
|
||||||
|
namespace Discord.Commands
|
||||||
|
{
|
||||||
|
internal class CommandMapNode
|
||||||
|
{
|
||||||
|
private readonly ConcurrentDictionary<string, CommandMapNode> _nodes;
|
||||||
|
private readonly string _name;
|
||||||
|
private ImmutableArray<Command> _commands;
|
||||||
|
|
||||||
|
public bool IsEmpty => _commands.Length == 0 && _nodes.Count == 0;
|
||||||
|
|
||||||
|
public CommandMapNode(string name)
|
||||||
|
{
|
||||||
|
_name = name;
|
||||||
|
_nodes = new ConcurrentDictionary<string, CommandMapNode>();
|
||||||
|
_commands = ImmutableArray.Create<Command>();
|
||||||
|
}
|
||||||
|
|
||||||
|
public void AddCommand(string text, int index, Command command)
|
||||||
|
{
|
||||||
|
int nextSpace = text.IndexOf(' ', index);
|
||||||
|
string name;
|
||||||
|
|
||||||
|
lock (this)
|
||||||
|
{
|
||||||
|
if (text == "")
|
||||||
|
_commands = _commands.Add(command);
|
||||||
|
else
|
||||||
|
{
|
||||||
|
if (nextSpace == -1)
|
||||||
|
name = text.Substring(index);
|
||||||
|
else
|
||||||
|
name = text.Substring(index, nextSpace - index);
|
||||||
|
|
||||||
|
var nextNode = _nodes.GetOrAdd(name, x => new CommandMapNode(x));
|
||||||
|
nextNode.AddCommand(nextSpace == -1 ? "" : text, nextSpace + 1, command);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
public void RemoveCommand(string text, int index, Command command)
|
||||||
|
{
|
||||||
|
int nextSpace = text.IndexOf(' ', index);
|
||||||
|
string name;
|
||||||
|
|
||||||
|
lock (this)
|
||||||
|
{
|
||||||
|
if (text == "")
|
||||||
|
_commands = _commands.Remove(command);
|
||||||
|
else
|
||||||
|
{
|
||||||
|
if (nextSpace == -1)
|
||||||
|
name = text.Substring(index);
|
||||||
|
else
|
||||||
|
name = text.Substring(index, nextSpace - index);
|
||||||
|
|
||||||
|
CommandMapNode nextNode;
|
||||||
|
if (_nodes.TryGetValue(name, out nextNode))
|
||||||
|
{
|
||||||
|
nextNode.RemoveCommand(nextSpace == -1 ? "" : text, nextSpace + 1, command);
|
||||||
|
if (nextNode.IsEmpty)
|
||||||
|
_nodes.TryRemove(name, out nextNode);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public IEnumerable<Command> GetCommands(string text, int index)
|
||||||
|
{
|
||||||
|
int nextSpace = text.IndexOf(' ', index);
|
||||||
|
string name;
|
||||||
|
|
||||||
|
var commands = _commands;
|
||||||
|
for (int i = 0; i < commands.Length; i++)
|
||||||
|
yield return _commands[i];
|
||||||
|
|
||||||
|
if (text != "")
|
||||||
|
{
|
||||||
|
if (nextSpace == -1)
|
||||||
|
name = text.Substring(index);
|
||||||
|
else
|
||||||
|
name = text.Substring(index, nextSpace - index);
|
||||||
|
|
||||||
|
CommandMapNode nextNode;
|
||||||
|
if (_nodes.TryGetValue(name, out nextNode))
|
||||||
|
{
|
||||||
|
foreach (var cmd in nextNode.GetCommands(nextSpace == -1 ? "" : text, nextSpace + 1))
|
||||||
|
yield return cmd;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user