@@ -3,15 +3,24 @@ using System; | |||||
namespace Discord.Commands | namespace Discord.Commands | ||||
{ | { | ||||
/// <summary> Provides aliases for a command. </summary> | /// <summary> Provides aliases for a command. </summary> | ||||
[AttributeUsage(AttributeTargets.Class | AttributeTargets.Method)] | |||||
[AttributeUsage(AttributeTargets.Class | AttributeTargets.Method, AllowMultiple=true)] | |||||
public class AliasAttribute : Attribute | public class AliasAttribute : Attribute | ||||
{ | { | ||||
/// <summary> The type to be applied to this alias group <summary> | |||||
public AliasType Type { get; } | |||||
/// <summary> The aliases which have been defined for the command. </summary> | /// <summary> The aliases which have been defined for the command. </summary> | ||||
public string[] Aliases { get; } | public string[] Aliases { get; } | ||||
/// <summary> Creates a new <see cref="AliasAttribute"/> with the given aliases. </summary> | /// <summary> Creates a new <see cref="AliasAttribute"/> with the given aliases. </summary> | ||||
public AliasAttribute(params string[] aliases) | public AliasAttribute(params string[] aliases) | ||||
{ | { | ||||
Type = AliasType.Relative; | |||||
Aliases = aliases; | |||||
} | |||||
/// <summary> Creates a new <see cref="AliasAttribute"/> with the given aliases. </summary> | |||||
public AliasAttribute(AliasType type, params string[] aliases) | |||||
{ | |||||
Type = type; | |||||
Aliases = aliases; | Aliases = aliases; | ||||
} | } | ||||
} | } | ||||
@@ -0,0 +1,8 @@ | |||||
namespace Discord.Commands | |||||
{ | |||||
public enum AliasType | |||||
{ | |||||
Relative, | |||||
Absolute | |||||
} | |||||
} |
@@ -1,9 +1,9 @@ | |||||
using System; | using System; | ||||
namespace Discord.Commands { | |||||
[AttributeUsage(AttributeTargets.Property)] | |||||
public class DontInjectAttribute : Attribute { | |||||
} | |||||
namespace Discord.Commands | |||||
{ | |||||
[AttributeUsage(AttributeTargets.Property)] | |||||
public class DontInjectAttribute : Attribute | |||||
{ | |||||
} | |||||
} | } |
@@ -9,7 +9,7 @@ namespace Discord.Commands.Builders | |||||
{ | { | ||||
private readonly List<PreconditionAttribute> _preconditions; | private readonly List<PreconditionAttribute> _preconditions; | ||||
private readonly List<ParameterBuilder> _parameters; | private readonly List<ParameterBuilder> _parameters; | ||||
private readonly List<string> _aliases; | |||||
private readonly List<string> _relativeAliases, _absoluteAliases; | |||||
public ModuleBuilder Module { get; } | public ModuleBuilder Module { get; } | ||||
internal Func<ICommandContext, object[], IDependencyMap, Task> Callback { get; set; } | internal Func<ICommandContext, object[], IDependencyMap, Task> Callback { get; set; } | ||||
@@ -22,7 +22,8 @@ namespace Discord.Commands.Builders | |||||
public IReadOnlyList<PreconditionAttribute> Preconditions => _preconditions; | public IReadOnlyList<PreconditionAttribute> Preconditions => _preconditions; | ||||
public IReadOnlyList<ParameterBuilder> Parameters => _parameters; | public IReadOnlyList<ParameterBuilder> Parameters => _parameters; | ||||
public IReadOnlyList<string> Aliases => _aliases; | |||||
public IReadOnlyList<string> RelativeAliases => _relativeAliases; | |||||
public IReadOnlyList<string> AbsoluteAliases => _absoluteAliases; | |||||
//Automatic | //Automatic | ||||
internal CommandBuilder(ModuleBuilder module) | internal CommandBuilder(ModuleBuilder module) | ||||
@@ -31,7 +32,8 @@ namespace Discord.Commands.Builders | |||||
_preconditions = new List<PreconditionAttribute>(); | _preconditions = new List<PreconditionAttribute>(); | ||||
_parameters = new List<ParameterBuilder>(); | _parameters = new List<ParameterBuilder>(); | ||||
_aliases = new List<string>(); | |||||
_relativeAliases = new List<string>(); | |||||
_absoluteAliases = new List<string>(); | |||||
} | } | ||||
//User-defined | //User-defined | ||||
internal CommandBuilder(ModuleBuilder module, string primaryAlias, Func<ICommandContext, object[], IDependencyMap, Task> callback) | internal CommandBuilder(ModuleBuilder module, string primaryAlias, Func<ICommandContext, object[], IDependencyMap, Task> callback) | ||||
@@ -41,7 +43,7 @@ namespace Discord.Commands.Builders | |||||
Discord.Preconditions.NotNull(callback, nameof(callback)); | Discord.Preconditions.NotNull(callback, nameof(callback)); | ||||
Callback = callback; | Callback = callback; | ||||
_aliases.Add(primaryAlias); | |||||
_relativeAliases.Add(primaryAlias); | |||||
} | } | ||||
public CommandBuilder WithName(string name) | public CommandBuilder WithName(string name) | ||||
@@ -70,13 +72,22 @@ namespace Discord.Commands.Builders | |||||
return this; | return this; | ||||
} | } | ||||
public CommandBuilder AddAliases(params string[] aliases) | |||||
public CommandBuilder AddAliases(AliasType type, params string[] aliases) | |||||
{ | { | ||||
for (int i = 0; i < aliases.Length; i++) | for (int i = 0; i < aliases.Length; i++) | ||||
{ | { | ||||
var alias = aliases[i] ?? ""; | var alias = aliases[i] ?? ""; | ||||
if (!_aliases.Contains(alias)) | |||||
_aliases.Add(alias); | |||||
switch (type) | |||||
{ | |||||
case AliasType.Relative: | |||||
if (!_relativeAliases.Contains(alias)) | |||||
_relativeAliases.Add(alias); | |||||
break; | |||||
case AliasType.Absolute: | |||||
if (!_absoluteAliases.Contains(alias)) | |||||
_absoluteAliases.Add(alias); | |||||
break; | |||||
} | |||||
} | } | ||||
return this; | return this; | ||||
} | } | ||||
@@ -111,7 +122,7 @@ namespace Discord.Commands.Builders | |||||
{ | { | ||||
//Default name to first alias | //Default name to first alias | ||||
if (Name == null) | if (Name == null) | ||||
Name = _aliases[0]; | |||||
Name = _relativeAliases[0]; | |||||
if (_parameters.Count > 0) | if (_parameters.Count > 0) | ||||
{ | { | ||||
@@ -9,7 +9,7 @@ namespace Discord.Commands.Builders | |||||
private readonly List<CommandBuilder> _commands; | private readonly List<CommandBuilder> _commands; | ||||
private readonly List<ModuleBuilder> _submodules; | private readonly List<ModuleBuilder> _submodules; | ||||
private readonly List<PreconditionAttribute> _preconditions; | private readonly List<PreconditionAttribute> _preconditions; | ||||
private readonly List<string> _aliases; | |||||
private readonly List<string> _relativeAliases, _absoluteAliases; | |||||
public CommandService Service { get; } | public CommandService Service { get; } | ||||
public ModuleBuilder Parent { get; } | public ModuleBuilder Parent { get; } | ||||
@@ -20,7 +20,8 @@ namespace Discord.Commands.Builders | |||||
public IReadOnlyList<CommandBuilder> Commands => _commands; | public IReadOnlyList<CommandBuilder> Commands => _commands; | ||||
public IReadOnlyList<ModuleBuilder> Modules => _submodules; | public IReadOnlyList<ModuleBuilder> Modules => _submodules; | ||||
public IReadOnlyList<PreconditionAttribute> Preconditions => _preconditions; | public IReadOnlyList<PreconditionAttribute> Preconditions => _preconditions; | ||||
public IReadOnlyList<string> Aliases => _aliases; | |||||
public IReadOnlyList<string> RelativeAliases => _relativeAliases; | |||||
public IReadOnlyList<string> AbsoluteAliases => _absoluteAliases; | |||||
//Automatic | //Automatic | ||||
internal ModuleBuilder(CommandService service, ModuleBuilder parent) | internal ModuleBuilder(CommandService service, ModuleBuilder parent) | ||||
@@ -31,7 +32,8 @@ namespace Discord.Commands.Builders | |||||
_commands = new List<CommandBuilder>(); | _commands = new List<CommandBuilder>(); | ||||
_submodules = new List<ModuleBuilder>(); | _submodules = new List<ModuleBuilder>(); | ||||
_preconditions = new List<PreconditionAttribute>(); | _preconditions = new List<PreconditionAttribute>(); | ||||
_aliases = new List<string>(); | |||||
_relativeAliases = new List<string>(); | |||||
_absoluteAliases = new List<string>(); | |||||
} | } | ||||
//User-defined | //User-defined | ||||
internal ModuleBuilder(CommandService service, ModuleBuilder parent, string primaryAlias) | internal ModuleBuilder(CommandService service, ModuleBuilder parent, string primaryAlias) | ||||
@@ -39,7 +41,7 @@ namespace Discord.Commands.Builders | |||||
{ | { | ||||
Discord.Preconditions.NotNull(primaryAlias, nameof(primaryAlias)); | Discord.Preconditions.NotNull(primaryAlias, nameof(primaryAlias)); | ||||
_aliases = new List<string> { primaryAlias }; | |||||
_relativeAliases = new List<string> { primaryAlias }; | |||||
} | } | ||||
public ModuleBuilder WithName(string name) | public ModuleBuilder WithName(string name) | ||||
@@ -58,13 +60,22 @@ namespace Discord.Commands.Builders | |||||
return this; | return this; | ||||
} | } | ||||
public ModuleBuilder AddAliases(params string[] aliases) | |||||
public ModuleBuilder AddAliases(AliasType type, params string[] aliases) | |||||
{ | { | ||||
for (int i = 0; i < aliases.Length; i++) | for (int i = 0; i < aliases.Length; i++) | ||||
{ | { | ||||
var alias = aliases[i] ?? ""; | var alias = aliases[i] ?? ""; | ||||
if (!_aliases.Contains(alias)) | |||||
_aliases.Add(alias); | |||||
switch (type) | |||||
{ | |||||
case AliasType.Relative: | |||||
if (!_relativeAliases.Contains(alias)) | |||||
_relativeAliases.Add(alias); | |||||
break; | |||||
case AliasType.Absolute: | |||||
if (!_absoluteAliases.Contains(alias)) | |||||
_absoluteAliases.Add(alias); | |||||
break; | |||||
} | |||||
} | } | ||||
return this; | return this; | ||||
} | } | ||||
@@ -106,7 +117,7 @@ namespace Discord.Commands.Builders | |||||
{ | { | ||||
//Default name to first alias | //Default name to first alias | ||||
if (Name == null) | if (Name == null) | ||||
Name = _aliases[0]; | |||||
Name = _relativeAliases[0]; | |||||
return new ModuleInfo(this, service, parent); | return new ModuleInfo(this, service, parent); | ||||
} | } | ||||
@@ -89,20 +89,23 @@ namespace Discord.Commands | |||||
else if (attribute is RemarksAttribute) | else if (attribute is RemarksAttribute) | ||||
builder.Remarks = (attribute as RemarksAttribute).Text; | builder.Remarks = (attribute as RemarksAttribute).Text; | ||||
else if (attribute is AliasAttribute) | else if (attribute is AliasAttribute) | ||||
builder.AddAliases((attribute as AliasAttribute).Aliases); | |||||
{ | |||||
var aliasAttr = attribute as AliasAttribute; | |||||
builder.AddAliases(aliasAttr.Type, aliasAttr.Aliases); | |||||
} | |||||
else if (attribute is GroupAttribute) | else if (attribute is GroupAttribute) | ||||
{ | { | ||||
var groupAttr = attribute as GroupAttribute; | var groupAttr = attribute as GroupAttribute; | ||||
builder.Name = builder.Name ?? groupAttr.Prefix; | builder.Name = builder.Name ?? groupAttr.Prefix; | ||||
builder.AddAliases(groupAttr.Prefix); | |||||
builder.AddAliases(AliasType.Relative, groupAttr.Prefix); | |||||
} | } | ||||
else if (attribute is PreconditionAttribute) | else if (attribute is PreconditionAttribute) | ||||
builder.AddPrecondition(attribute as PreconditionAttribute); | builder.AddPrecondition(attribute as PreconditionAttribute); | ||||
} | } | ||||
//Check for unspecified info | //Check for unspecified info | ||||
if (builder.Aliases.Count == 0) | |||||
builder.AddAliases(""); | |||||
if (builder.RelativeAliases.Count == 0) | |||||
builder.AddAliases(AliasType.Relative, ""); | |||||
if (builder.Name == null) | if (builder.Name == null) | ||||
builder.Name = typeInfo.Name; | builder.Name = typeInfo.Name; | ||||
@@ -127,7 +130,7 @@ namespace Discord.Commands | |||||
if (attribute is CommandAttribute) | if (attribute is CommandAttribute) | ||||
{ | { | ||||
var cmdAttr = attribute as CommandAttribute; | var cmdAttr = attribute as CommandAttribute; | ||||
builder.AddAliases(cmdAttr.Text); | |||||
builder.AddAliases(AliasType.Relative, cmdAttr.Text); | |||||
builder.RunMode = cmdAttr.RunMode; | builder.RunMode = cmdAttr.RunMode; | ||||
builder.Name = builder.Name ?? cmdAttr.Text; | builder.Name = builder.Name ?? cmdAttr.Text; | ||||
} | } | ||||
@@ -140,7 +143,10 @@ namespace Discord.Commands | |||||
else if (attribute is RemarksAttribute) | else if (attribute is RemarksAttribute) | ||||
builder.Remarks = (attribute as RemarksAttribute).Text; | builder.Remarks = (attribute as RemarksAttribute).Text; | ||||
else if (attribute is AliasAttribute) | else if (attribute is AliasAttribute) | ||||
builder.AddAliases((attribute as AliasAttribute).Aliases); | |||||
{ | |||||
var aliasAttr = attribute as AliasAttribute; | |||||
builder.AddAliases(aliasAttr.Type, aliasAttr.Aliases); | |||||
} | |||||
else if (attribute is PreconditionAttribute) | else if (attribute is PreconditionAttribute) | ||||
builder.AddPrecondition(attribute as PreconditionAttribute); | builder.AddPrecondition(attribute as PreconditionAttribute); | ||||
} | } | ||||
@@ -43,7 +43,7 @@ namespace Discord.Commands | |||||
Priority = builder.Priority; | Priority = builder.Priority; | ||||
Aliases = module.Aliases | Aliases = module.Aliases | ||||
.Permutate(builder.Aliases, (first, second) => | |||||
.Permutate(builder.RelativeAliases, (first, second) => | |||||
{ | { | ||||
if (first == "") | if (first == "") | ||||
return second; | return second; | ||||
@@ -52,6 +52,7 @@ namespace Discord.Commands | |||||
else | else | ||||
return first + service._separatorChar + second; | return first + service._separatorChar + second; | ||||
}) | }) | ||||
.Concat(builder.AbsoluteAliases) | |||||
.Select(x => service._caseSensitive ? x : x.ToLowerInvariant()) | .Select(x => service._caseSensitive ? x : x.ToLowerInvariant()) | ||||
.ToImmutableArray(); | .ToImmutableArray(); | ||||
@@ -38,28 +38,33 @@ namespace Discord.Commands | |||||
private static IEnumerable<string> BuildAliases(ModuleBuilder builder, CommandService service) | private static IEnumerable<string> BuildAliases(ModuleBuilder builder, CommandService service) | ||||
{ | { | ||||
var result = builder.Aliases.ToList(); | |||||
var builderQueue = new Queue<ModuleBuilder>(); | |||||
var result = builder.RelativeAliases.ToList(); | |||||
var builderQueue = new Stack<ModuleBuilder>(); | |||||
var parent = builder; | var parent = builder; | ||||
while ((parent = parent.Parent) != null) | while ((parent = parent.Parent) != null) | ||||
builderQueue.Enqueue(parent); | |||||
builderQueue.Push(parent); | |||||
while (builderQueue.Count > 0) | while (builderQueue.Count > 0) | ||||
{ | { | ||||
var level = builderQueue.Dequeue(); | |||||
var level = builderQueue.Pop(); | |||||
// permute in reverse because we want to *prefix* our aliases | // permute in reverse because we want to *prefix* our aliases | ||||
result = level.Aliases.Permutate(result, (first, second) => | |||||
{ | |||||
if (first == "") | |||||
return second; | |||||
else if (second == "") | |||||
return first; | |||||
else | |||||
return first + service._separatorChar + second; | |||||
}).ToList(); | |||||
result = result | |||||
.Permutate(level.RelativeAliases, (first, second) => | |||||
{ | |||||
if (first == "") | |||||
return second; | |||||
else if (second == "") | |||||
return first; | |||||
else | |||||
return first + service._separatorChar + second; | |||||
}) | |||||
.Concat(level.AbsoluteAliases) | |||||
.ToList(); | |||||
} | } | ||||
result = result.Concat(builder.AbsoluteAliases).ToList(); | |||||
return result; | return result; | ||||
} | } | ||||
@@ -13,7 +13,6 @@ namespace Discord.WebSocket | |||||
public override ushort DiscriminatorValue { get; internal set; } | public override ushort DiscriminatorValue { get; internal set; } | ||||
public override string AvatarId { get; internal set; } | public override string AvatarId { get; internal set; } | ||||
internal override SocketPresence Presence { get { return new SocketPresence(UserStatus.Offline, null); } set { } } | internal override SocketPresence Presence { get { return new SocketPresence(UserStatus.Offline, null); } set { } } | ||||
internal override SocketGlobalUser GlobalUser { get { throw new NotSupportedException(); } } | internal override SocketGlobalUser GlobalUser { get { throw new NotSupportedException(); } } | ||||
internal SocketSimpleUser(DiscordSocketClient discord, ulong id) | internal SocketSimpleUser(DiscordSocketClient discord, ulong id) | ||||