mirror of
https://gitlab.com/Kwoth/nadekobot.git
synced 2025-09-11 17:58:26 -04:00
Small refactoring. Finally made use of the type parameter in NadekoTypeReader<T> class
This commit is contained in:
@@ -1,6 +1,5 @@
|
||||
#nullable disable
|
||||
#pragma warning disable
|
||||
#pragma warning disable *
|
||||
// License MIT
|
||||
// Source: https://github.com/i3arnon/ConcurrentHashSet
|
||||
|
||||
|
@@ -11,19 +11,21 @@ namespace NadekoBot.Modules;
|
||||
public abstract class NadekoModule : ModuleBase
|
||||
{
|
||||
protected CultureInfo Culture { get; set; }
|
||||
|
||||
// Injected by Discord.net
|
||||
public IBotStrings Strings { get; set; }
|
||||
public CommandHandler CmdHandler { get; set; }
|
||||
public ILocalization Localization { get; set; }
|
||||
public CommandHandler _cmdHandler { get; set; }
|
||||
public ILocalization _localization { get; set; }
|
||||
public IEmbedBuilderService _eb { get; set; }
|
||||
|
||||
protected string prefix
|
||||
=> CmdHandler.GetPrefix(ctx.Guild);
|
||||
=> _cmdHandler.GetPrefix(ctx.Guild);
|
||||
|
||||
protected ICommandContext ctx
|
||||
=> Context;
|
||||
|
||||
protected override void BeforeExecute(CommandInfo cmd)
|
||||
=> Culture = Localization.GetCultureInfo(ctx.Guild?.Id);
|
||||
protected override void BeforeExecute(CommandInfo command)
|
||||
=> Culture = _localization.GetCultureInfo(ctx.Guild?.Id);
|
||||
|
||||
protected string GetText(in LocStr data)
|
||||
=> Strings.GetText(data, Culture);
|
||||
|
@@ -17,8 +17,8 @@ public static class OptionsParser
|
||||
x.HelpWriter = null;
|
||||
});
|
||||
var res = p.ParseArguments<T>(args);
|
||||
options = res.MapResult(x => x, _ => options);
|
||||
options.NormalizeOptions();
|
||||
return (options, res.Tag == ParserResultType.Parsed);
|
||||
var output = res.MapResult(x => x, _ => options);
|
||||
output.NormalizeOptions();
|
||||
return (output, res.Tag == ParserResultType.Parsed);
|
||||
}
|
||||
}
|
@@ -2,7 +2,7 @@ namespace NadekoBot.Common;
|
||||
|
||||
public readonly struct TypedKey<TData>
|
||||
{
|
||||
public readonly string Key;
|
||||
public string Key { get; }
|
||||
|
||||
public TypedKey(in string key)
|
||||
=> Key = key;
|
||||
|
@@ -37,7 +37,7 @@ public abstract record SmartText
|
||||
var smartEmbedText = JsonConvert.DeserializeObject<SmartEmbedText>(input);
|
||||
|
||||
if (smartEmbedText is null)
|
||||
throw new();
|
||||
throw new FormatException();
|
||||
|
||||
smartEmbedText.NormalizeFields();
|
||||
|
||||
|
@@ -14,20 +14,20 @@ public sealed class CommandTypeReader : NadekoTypeReader<CommandInfo>
|
||||
_cmds = cmds;
|
||||
}
|
||||
|
||||
public override Task<TypeReaderResult> ReadAsync(ICommandContext context, string input)
|
||||
public override ValueTask<TypeReaderResult<CommandInfo>> ReadAsync(ICommandContext ctx, string input)
|
||||
{
|
||||
input = input.ToUpperInvariant();
|
||||
var prefix = _handler.GetPrefix(context.Guild);
|
||||
var prefix = _handler.GetPrefix(ctx.Guild);
|
||||
if (!input.StartsWith(prefix.ToUpperInvariant(), StringComparison.InvariantCulture))
|
||||
return Task.FromResult(TypeReaderResult.FromError(CommandError.ParseFailed, "No such command found."));
|
||||
return new(TypeReaderResult.FromError<CommandInfo>(CommandError.ParseFailed, "No such command found."));
|
||||
|
||||
input = input[prefix.Length..];
|
||||
|
||||
var cmd = _cmds.Commands.FirstOrDefault(c => c.Aliases.Select(a => a.ToUpperInvariant()).Contains(input));
|
||||
if (cmd is null)
|
||||
return Task.FromResult(TypeReaderResult.FromError(CommandError.ParseFailed, "No such command found."));
|
||||
return new(TypeReaderResult.FromError<CommandInfo>(CommandError.ParseFailed, "No such command found."));
|
||||
|
||||
return Task.FromResult(TypeReaderResult.FromSuccess(cmd));
|
||||
return new(TypeReaderResult.FromSuccess(cmd));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -44,19 +44,19 @@ public sealed class CommandOrCrTypeReader : NadekoTypeReader<CommandOrCrInfo>
|
||||
_commandHandler = commandHandler;
|
||||
}
|
||||
|
||||
public override async Task<TypeReaderResult> ReadAsync(ICommandContext context, string input)
|
||||
public override async ValueTask<TypeReaderResult<CommandOrCrInfo>> ReadAsync(ICommandContext ctx, string input)
|
||||
{
|
||||
input = input.ToUpperInvariant();
|
||||
|
||||
if (_exprs.ExpressionExists(context.Guild?.Id, input))
|
||||
if (_exprs.ExpressionExists(ctx.Guild?.Id, input))
|
||||
return TypeReaderResult.FromSuccess(new CommandOrCrInfo(input, CommandOrCrInfo.Type.Custom));
|
||||
|
||||
var cmd = await new CommandTypeReader(_commandHandler, _cmds).ReadAsync(context, input);
|
||||
var cmd = await new CommandTypeReader(_commandHandler, _cmds).ReadAsync(ctx, input);
|
||||
if (cmd.IsSuccess)
|
||||
return TypeReaderResult.FromSuccess(new CommandOrCrInfo(((CommandInfo)cmd.Values.First().Value).Name,
|
||||
CommandOrCrInfo.Type.Normal));
|
||||
|
||||
return TypeReaderResult.FromError(CommandError.ParseFailed, "No such command or cr found.");
|
||||
return TypeReaderResult.FromError<CommandOrCrInfo>(CommandError.ParseFailed, "No such command or cr found.");
|
||||
}
|
||||
}
|
||||
|
||||
|
@@ -3,11 +3,11 @@ namespace NadekoBot.Common.TypeReaders;
|
||||
|
||||
public sealed class EmoteTypeReader : NadekoTypeReader<Emote>
|
||||
{
|
||||
public override Task<TypeReaderResult> ReadAsync(ICommandContext ctx, string input)
|
||||
public override ValueTask<TypeReaderResult<Emote>> ReadAsync(ICommandContext ctx, string input)
|
||||
{
|
||||
if (!Emote.TryParse(input, out var emote))
|
||||
return Task.FromResult(TypeReaderResult.FromError(CommandError.ParseFailed, "Input is not a valid emote"));
|
||||
return new(TypeReaderResult.FromError<Emote>(CommandError.ParseFailed, "Input is not a valid emote"));
|
||||
|
||||
return Task.FromResult(TypeReaderResult.FromSuccess(emote));
|
||||
return new(TypeReaderResult.FromSuccess(emote));
|
||||
}
|
||||
}
|
@@ -10,14 +10,14 @@ public sealed class GuildDateTimeTypeReader : NadekoTypeReader<GuildDateTime>
|
||||
public GuildDateTimeTypeReader(GuildTimezoneService gts)
|
||||
=> _gts = gts;
|
||||
|
||||
public override Task<TypeReaderResult> ReadAsync(ICommandContext context, string input)
|
||||
public override ValueTask<TypeReaderResult<GuildDateTime>> ReadAsync(ICommandContext context, string input)
|
||||
{
|
||||
var gdt = Parse(context.Guild.Id, input);
|
||||
if (gdt is null)
|
||||
return Task.FromResult(TypeReaderResult.FromError(CommandError.ParseFailed,
|
||||
return new(TypeReaderResult.FromError<GuildDateTime>(CommandError.ParseFailed,
|
||||
"Input string is in an incorrect format."));
|
||||
|
||||
return Task.FromResult(TypeReaderResult.FromSuccess(gdt));
|
||||
return new(TypeReaderResult.FromSuccess(gdt));
|
||||
}
|
||||
|
||||
private GuildDateTime Parse(ulong guildId, string input)
|
||||
|
@@ -8,18 +8,17 @@ public sealed class GuildTypeReader : NadekoTypeReader<IGuild>
|
||||
public GuildTypeReader(DiscordSocketClient client)
|
||||
=> _client = client;
|
||||
|
||||
public override Task<TypeReaderResult> ReadAsync(ICommandContext context, string input)
|
||||
public override ValueTask<TypeReaderResult<IGuild>> ReadAsync(ICommandContext context, string input)
|
||||
{
|
||||
input = input.Trim().ToUpperInvariant();
|
||||
var guilds = _client.Guilds;
|
||||
var guild = guilds.FirstOrDefault(g => g.Id.ToString().Trim().ToUpperInvariant() == input)
|
||||
?? //by id
|
||||
guilds.FirstOrDefault(g => g.Name.Trim().ToUpperInvariant() == input); //by name
|
||||
IGuild guild = guilds.FirstOrDefault(g => g.Id.ToString().Trim().ToUpperInvariant() == input) //by id
|
||||
?? guilds.FirstOrDefault(g => g.Name.Trim().ToUpperInvariant() == input); //by name
|
||||
|
||||
if (guild is not null)
|
||||
return Task.FromResult(TypeReaderResult.FromSuccess(guild));
|
||||
return new(TypeReaderResult.FromSuccess(guild));
|
||||
|
||||
return Task.FromResult(
|
||||
TypeReaderResult.FromError(CommandError.ParseFailed, "No guild by that name or Id found"));
|
||||
return new(
|
||||
TypeReaderResult.FromError<IGuild>(CommandError.ParseFailed, "No guild by that name or Id found"));
|
||||
}
|
||||
}
|
@@ -3,17 +3,17 @@ namespace NadekoBot.Common.TypeReaders;
|
||||
|
||||
public sealed class KwumTypeReader : NadekoTypeReader<kwum>
|
||||
{
|
||||
public override Task<TypeReaderResult> ReadAsync(ICommandContext context, string input)
|
||||
public override ValueTask<TypeReaderResult<kwum>> ReadAsync(ICommandContext context, string input)
|
||||
{
|
||||
if (kwum.TryParse(input, out var val))
|
||||
return Task.FromResult(TypeReaderResult.FromSuccess(val));
|
||||
return new(TypeReaderResult.FromSuccess(val));
|
||||
|
||||
return Task.FromResult(TypeReaderResult.FromError(CommandError.ParseFailed, "Input is not a valid kwum"));
|
||||
return new(TypeReaderResult.FromError<kwum>(CommandError.ParseFailed, "Input is not a valid kwum"));
|
||||
}
|
||||
}
|
||||
|
||||
public sealed class SmartTextTypeReader : NadekoTypeReader<SmartText>
|
||||
{
|
||||
public override Task<TypeReaderResult> ReadAsync(ICommandContext ctx, string input)
|
||||
=> Task.FromResult(TypeReaderResult.FromSuccess(SmartText.CreateFrom(input)));
|
||||
public override ValueTask<TypeReaderResult<SmartText>> ReadAsync(ICommandContext ctx, string input)
|
||||
=> new(TypeReaderResult.FromSuccess(SmartText.CreateFrom(input)));
|
||||
}
|
@@ -8,16 +8,16 @@ public sealed class ModuleTypeReader : NadekoTypeReader<ModuleInfo>
|
||||
public ModuleTypeReader(CommandService cmds)
|
||||
=> _cmds = cmds;
|
||||
|
||||
public override Task<TypeReaderResult> ReadAsync(ICommandContext context, string input)
|
||||
public override ValueTask<TypeReaderResult<ModuleInfo>> ReadAsync(ICommandContext context, string input)
|
||||
{
|
||||
input = input.ToUpperInvariant();
|
||||
var module = _cmds.Modules.GroupBy(m => m.GetTopLevelModule())
|
||||
.FirstOrDefault(m => m.Key.Name.ToUpperInvariant() == input)
|
||||
?.Key;
|
||||
if (module is null)
|
||||
return Task.FromResult(TypeReaderResult.FromError(CommandError.ParseFailed, "No such module found."));
|
||||
return new(TypeReaderResult.FromError<ModuleInfo>(CommandError.ParseFailed, "No such module found."));
|
||||
|
||||
return Task.FromResult(TypeReaderResult.FromSuccess(module));
|
||||
return new(TypeReaderResult.FromSuccess(module));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -28,16 +28,16 @@ public sealed class ModuleOrCrTypeReader : NadekoTypeReader<ModuleOrCrInfo>
|
||||
public ModuleOrCrTypeReader(CommandService cmds)
|
||||
=> _cmds = cmds;
|
||||
|
||||
public override Task<TypeReaderResult> ReadAsync(ICommandContext context, string input)
|
||||
public override ValueTask<TypeReaderResult<ModuleOrCrInfo>> ReadAsync(ICommandContext context, string input)
|
||||
{
|
||||
input = input.ToUpperInvariant();
|
||||
var module = _cmds.Modules.GroupBy(m => m.GetTopLevelModule())
|
||||
.FirstOrDefault(m => m.Key.Name.ToUpperInvariant() == input)
|
||||
?.Key;
|
||||
if (module is null && input != "ACTUALEXPRESSIONS")
|
||||
return Task.FromResult(TypeReaderResult.FromError(CommandError.ParseFailed, "No such module found."));
|
||||
return new(TypeReaderResult.FromError<ModuleOrCrInfo>(CommandError.ParseFailed, "No such module found."));
|
||||
|
||||
return Task.FromResult(TypeReaderResult.FromSuccess(new ModuleOrCrInfo { Name = input }));
|
||||
return new(TypeReaderResult.FromSuccess(new ModuleOrCrInfo { Name = input }));
|
||||
}
|
||||
}
|
||||
|
||||
|
@@ -4,8 +4,40 @@ namespace NadekoBot.Common.TypeReaders;
|
||||
[MeansImplicitUse(ImplicitUseTargetFlags.Default | ImplicitUseTargetFlags.WithInheritors)]
|
||||
public abstract class NadekoTypeReader<T> : TypeReader
|
||||
{
|
||||
public abstract Task<TypeReaderResult> ReadAsync(ICommandContext ctx, string input);
|
||||
public abstract ValueTask<TypeReaderResult<T>> ReadAsync(ICommandContext ctx, string input);
|
||||
|
||||
public override Task<TypeReaderResult> ReadAsync(ICommandContext ctx, string input, IServiceProvider services)
|
||||
=> ReadAsync(ctx, input);
|
||||
public override async Task<Discord.Commands.TypeReaderResult> ReadAsync(
|
||||
ICommandContext ctx,
|
||||
string input,
|
||||
IServiceProvider services)
|
||||
=> await ReadAsync(ctx, input);
|
||||
}
|
||||
|
||||
public static class TypeReaderResult
|
||||
{
|
||||
public static TypeReaderResult<T> FromError<T>(CommandError error, string reason)
|
||||
=> Discord.Commands.TypeReaderResult.FromError(error, reason);
|
||||
|
||||
public static TypeReaderResult<T> FromSuccess<T>(in T value)
|
||||
=> Discord.Commands.TypeReaderResult.FromSuccess(value);
|
||||
}
|
||||
|
||||
public readonly struct TypeReaderResult<T>
|
||||
{
|
||||
public bool IsSuccess
|
||||
=> _result.IsSuccess;
|
||||
|
||||
public IReadOnlyCollection<TypeReaderValue> Values
|
||||
=> _result.Values;
|
||||
|
||||
private readonly Discord.Commands.TypeReaderResult _result;
|
||||
|
||||
private TypeReaderResult(in Discord.Commands.TypeReaderResult result)
|
||||
=> _result = result;
|
||||
|
||||
public static implicit operator TypeReaderResult<T>(in Discord.Commands.TypeReaderResult result)
|
||||
=> new(result);
|
||||
|
||||
public static implicit operator Discord.Commands.TypeReaderResult(in TypeReaderResult<T> wrapper)
|
||||
=> wrapper._result;
|
||||
}
|
@@ -8,7 +8,7 @@ namespace NadekoBot.Common.TypeReaders;
|
||||
/// </summary>
|
||||
public sealed class PermissionActionTypeReader : NadekoTypeReader<PermissionAction>
|
||||
{
|
||||
public override Task<TypeReaderResult> ReadAsync(ICommandContext context, string input)
|
||||
public override ValueTask<TypeReaderResult<PermissionAction>> ReadAsync(ICommandContext context, string input)
|
||||
{
|
||||
input = input.ToUpperInvariant();
|
||||
switch (input)
|
||||
@@ -21,7 +21,7 @@ public sealed class PermissionActionTypeReader : NadekoTypeReader<PermissionActi
|
||||
case "ALLOW":
|
||||
case "PERMIT":
|
||||
case "UNBAN":
|
||||
return Task.FromResult(TypeReaderResult.FromSuccess(PermissionAction.Enable));
|
||||
return new(TypeReaderResult.FromSuccess(PermissionAction.Enable));
|
||||
case "0":
|
||||
case "F":
|
||||
case "FALSE":
|
||||
@@ -30,9 +30,9 @@ public sealed class PermissionActionTypeReader : NadekoTypeReader<PermissionActi
|
||||
case "DISABLED":
|
||||
case "DISALLOW":
|
||||
case "BAN":
|
||||
return Task.FromResult(TypeReaderResult.FromSuccess(PermissionAction.Disable));
|
||||
return new(TypeReaderResult.FromSuccess(PermissionAction.Disable));
|
||||
default:
|
||||
return Task.FromResult(TypeReaderResult.FromError(CommandError.ParseFailed,
|
||||
return new(TypeReaderResult.FromError<PermissionAction>(CommandError.ParseFailed,
|
||||
"Did not receive a valid boolean value"));
|
||||
}
|
||||
}
|
||||
|
@@ -5,7 +5,7 @@ namespace NadekoBot.Common.TypeReaders;
|
||||
|
||||
public sealed class Rgba32TypeReader : NadekoTypeReader<Color>
|
||||
{
|
||||
public override async Task<TypeReaderResult> ReadAsync(ICommandContext context, string input)
|
||||
public override async ValueTask<TypeReaderResult<Color>> ReadAsync(ICommandContext context, string input)
|
||||
{
|
||||
await Task.Yield();
|
||||
|
||||
@@ -16,7 +16,7 @@ public sealed class Rgba32TypeReader : NadekoTypeReader<Color>
|
||||
}
|
||||
catch
|
||||
{
|
||||
return TypeReaderResult.FromError(CommandError.ParseFailed, "Parameter is not a valid color hex.");
|
||||
return TypeReaderResult.FromError<Color>(CommandError.ParseFailed, "Parameter is not a valid color hex.");
|
||||
}
|
||||
}
|
||||
}
|
@@ -18,12 +18,10 @@ public sealed class ShmartNumberTypeReader : NadekoTypeReader<ShmartNumber>
|
||||
_gambling = gambling;
|
||||
}
|
||||
|
||||
public override async Task<TypeReaderResult> ReadAsync(ICommandContext context, string input)
|
||||
public override ValueTask<TypeReaderResult<ShmartNumber>> ReadAsync(ICommandContext context, string input)
|
||||
{
|
||||
await Task.Yield();
|
||||
|
||||
if (string.IsNullOrWhiteSpace(input))
|
||||
return TypeReaderResult.FromError(CommandError.ParseFailed, "Input is empty.");
|
||||
return new(TypeReaderResult.FromError<ShmartNumber>(CommandError.ParseFailed, "Input is empty."));
|
||||
|
||||
var i = input.Trim().ToUpperInvariant();
|
||||
|
||||
@@ -32,17 +30,17 @@ public sealed class ShmartNumberTypeReader : NadekoTypeReader<ShmartNumber>
|
||||
//can't add m because it will conflict with max atm
|
||||
|
||||
if (TryHandlePercentage(context, i, out var num))
|
||||
return TypeReaderResult.FromSuccess(new ShmartNumber(num, i));
|
||||
return new(TypeReaderResult.FromSuccess(new ShmartNumber(num, i)));
|
||||
try
|
||||
{
|
||||
var expr = new Expression(i, EvaluateOptions.IgnoreCase);
|
||||
expr.EvaluateParameter += (str, ev) => EvaluateParam(str, ev, context);
|
||||
var lon = (long)decimal.Parse(expr.Evaluate().ToString());
|
||||
return TypeReaderResult.FromSuccess(new ShmartNumber(lon, input));
|
||||
return new(TypeReaderResult.FromSuccess(new ShmartNumber(lon, input)));
|
||||
}
|
||||
catch (Exception)
|
||||
{
|
||||
return TypeReaderResult.FromError(CommandError.ParseFailed, $"Invalid input: {input}");
|
||||
return ValueTask.FromResult(TypeReaderResult.FromError<Common.ShmartNumber>(CommandError.ParseFailed, $"Invalid input: {input}"));
|
||||
}
|
||||
}
|
||||
|
||||
|
@@ -5,18 +5,18 @@ namespace NadekoBot.Common.TypeReaders;
|
||||
|
||||
public sealed class StoopidTimeTypeReader : NadekoTypeReader<StoopidTime>
|
||||
{
|
||||
public override Task<TypeReaderResult> ReadAsync(ICommandContext context, string input)
|
||||
public override ValueTask<TypeReaderResult<StoopidTime>> ReadAsync(ICommandContext context, string input)
|
||||
{
|
||||
if (string.IsNullOrWhiteSpace(input))
|
||||
return Task.FromResult(TypeReaderResult.FromError(CommandError.Unsuccessful, "Input is empty."));
|
||||
return new(TypeReaderResult.FromError<StoopidTime>(CommandError.Unsuccessful, "Input is empty."));
|
||||
try
|
||||
{
|
||||
var time = StoopidTime.FromInput(input);
|
||||
return Task.FromResult(TypeReaderResult.FromSuccess(time));
|
||||
return new(TypeReaderResult.FromSuccess(time));
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
return Task.FromResult(TypeReaderResult.FromError(CommandError.Exception, ex.Message));
|
||||
return new(TypeReaderResult.FromError<StoopidTime>(CommandError.Exception, ex.Message));
|
||||
}
|
||||
}
|
||||
}
|
@@ -1,6 +1,7 @@
|
||||
#nullable disable
|
||||
namespace NadekoBot.Common.Yml;
|
||||
|
||||
[AttributeUsage(AttributeTargets.Property)]
|
||||
public class CommentAttribute : Attribute
|
||||
{
|
||||
public string Comment { get; }
|
||||
|
@@ -10,7 +10,7 @@ public class CommentGatheringTypeInspector : TypeInspectorSkeleton
|
||||
private readonly ITypeInspector _innerTypeDescriptor;
|
||||
|
||||
public CommentGatheringTypeInspector(ITypeInspector innerTypeDescriptor)
|
||||
=> _innerTypeDescriptor = innerTypeDescriptor ?? throw new ArgumentNullException("innerTypeDescriptor");
|
||||
=> _innerTypeDescriptor = innerTypeDescriptor ?? throw new ArgumentNullException(nameof(innerTypeDescriptor));
|
||||
|
||||
public override IEnumerable<IPropertyDescriptor> GetProperties(Type type, object container)
|
||||
=> _innerTypeDescriptor.GetProperties(type, container).Select(d => new CommentsPropertyDescriptor(d));
|
||||
|
Reference in New Issue
Block a user