refactor: move ContextExts to own folder, CommandTree / command defs to CommandMeta folder
This commit is contained in:
180
PluralKit.Bot/CommandSystem/Context/ContextEntityArgumentsExt.cs
Normal file
180
PluralKit.Bot/CommandSystem/Context/ContextEntityArgumentsExt.cs
Normal file
@@ -0,0 +1,180 @@
|
||||
using Myriad.Extensions;
|
||||
using Myriad.Types;
|
||||
|
||||
using PluralKit.Bot.Utils;
|
||||
using PluralKit.Core;
|
||||
|
||||
namespace PluralKit.Bot;
|
||||
|
||||
public static class ContextEntityArgumentsExt
|
||||
{
|
||||
public static async Task<User> MatchUser(this Context ctx)
|
||||
{
|
||||
var text = ctx.PeekArgument();
|
||||
if (text.TryParseMention(out var id))
|
||||
return await ctx.Cache.GetOrFetchUser(ctx.Rest, id);
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
public static bool MatchUserRaw(this Context ctx, out ulong id)
|
||||
{
|
||||
id = 0;
|
||||
|
||||
var text = ctx.PeekArgument();
|
||||
if (text.TryParseMention(out var mentionId))
|
||||
id = mentionId;
|
||||
|
||||
return id != 0;
|
||||
}
|
||||
|
||||
public static Task<PKSystem> PeekSystem(this Context ctx) => ctx.MatchSystemInner();
|
||||
|
||||
public static async Task<PKSystem> MatchSystem(this Context ctx)
|
||||
{
|
||||
var system = await ctx.MatchSystemInner();
|
||||
if (system != null) ctx.PopArgument();
|
||||
return system;
|
||||
}
|
||||
|
||||
private static async Task<PKSystem> MatchSystemInner(this Context ctx)
|
||||
{
|
||||
var input = ctx.PeekArgument();
|
||||
|
||||
// System references can take three forms:
|
||||
// - The direct user ID of an account connected to the system
|
||||
// - A @mention of an account connected to the system (<@uid>)
|
||||
// - A system hid
|
||||
|
||||
// Direct IDs and mentions are both handled by the below method:
|
||||
if (input.TryParseMention(out var id))
|
||||
return await ctx.Repository.GetSystemByAccount(id);
|
||||
|
||||
// Finally, try HID parsing
|
||||
var system = await ctx.Repository.GetSystemByHid(input);
|
||||
return system;
|
||||
}
|
||||
|
||||
public static async Task<PKMember> PeekMember(this Context ctx, SystemId? restrictToSystem = null)
|
||||
{
|
||||
var input = ctx.PeekArgument();
|
||||
|
||||
// Member references can have one of three forms, depending on
|
||||
// whether you're in a system or not:
|
||||
// - A member hid
|
||||
// - A textual name of a member *in your own system*
|
||||
// - a textual display name of a member *in your own system*
|
||||
|
||||
// Skip name / display name matching if the user does not have a system
|
||||
// or if they specifically request by-HID matching
|
||||
if (ctx.System != null && !ctx.MatchFlag("id", "by-id"))
|
||||
{
|
||||
// First, try finding by member name in system
|
||||
if (await ctx.Repository.GetMemberByName(ctx.System.Id, input) is PKMember memberByName)
|
||||
return memberByName;
|
||||
|
||||
// And if that fails, we try finding a member with a display name matching the argument from the system
|
||||
if (ctx.System != null &&
|
||||
await ctx.Repository.GetMemberByDisplayName(ctx.System.Id, input) is PKMember memberByDisplayName)
|
||||
return memberByDisplayName;
|
||||
}
|
||||
|
||||
// Finally (or if by-HID lookup is specified), try member HID parsing:
|
||||
if (await ctx.Repository.GetMemberByHid(input, restrictToSystem) is PKMember memberByHid)
|
||||
return memberByHid;
|
||||
|
||||
// We didn't find anything, so we return null.
|
||||
return null;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Attempts to pop a member descriptor from the stack, returning it if present. If a member could not be
|
||||
/// resolved by the next word in the argument stack, does *not* touch the stack, and returns null.
|
||||
/// </summary>
|
||||
public static async Task<PKMember> MatchMember(this Context ctx, SystemId? restrictToSystem = null)
|
||||
{
|
||||
// First, peek a member
|
||||
var member = await ctx.PeekMember(restrictToSystem);
|
||||
|
||||
// If the peek was successful, we've used up the next argument, so we pop that just to get rid of it.
|
||||
if (member != null) ctx.PopArgument();
|
||||
|
||||
// Finally, we return the member value.
|
||||
return member;
|
||||
}
|
||||
|
||||
public static async Task<PKGroup> PeekGroup(this Context ctx, SystemId? restrictToSystem = null)
|
||||
{
|
||||
var input = ctx.PeekArgument();
|
||||
|
||||
// see PeekMember for an explanation of the logic used here
|
||||
|
||||
if (ctx.System != null && !ctx.MatchFlag("id", "by-id"))
|
||||
{
|
||||
if (await ctx.Repository.GetGroupByName(ctx.System.Id, input) is { } byName)
|
||||
return byName;
|
||||
if (await ctx.Repository.GetGroupByDisplayName(ctx.System.Id, input) is { } byDisplayName)
|
||||
return byDisplayName;
|
||||
}
|
||||
|
||||
if (await ctx.Repository.GetGroupByHid(input, restrictToSystem) is { } byHid)
|
||||
return byHid;
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
public static async Task<PKGroup> MatchGroup(this Context ctx, SystemId? restrictToSystem = null)
|
||||
{
|
||||
var group = await ctx.PeekGroup(restrictToSystem);
|
||||
if (group != null) ctx.PopArgument();
|
||||
return group;
|
||||
}
|
||||
|
||||
public static string CreateNotFoundError(this Context ctx, string entity, string input)
|
||||
{
|
||||
var isIDOnlyQuery = ctx.System == null || ctx.MatchFlag("id", "by-id");
|
||||
|
||||
if (isIDOnlyQuery)
|
||||
{
|
||||
if (input.Length == 5)
|
||||
return $"{entity} with ID \"{input}\" not found.";
|
||||
return $"{entity} not found. Note that a {entity.ToLower()} ID is 5 characters long.";
|
||||
}
|
||||
|
||||
if (input.Length == 5)
|
||||
return $"{entity} with ID or name \"{input}\" not found.";
|
||||
return $"{entity} with name \"{input}\" not found. Note that a {entity.ToLower()} ID is 5 characters long.";
|
||||
}
|
||||
|
||||
public static async Task<Channel> MatchChannel(this Context ctx)
|
||||
{
|
||||
if (!MentionUtils.TryParseChannel(ctx.PeekArgument(), out var id))
|
||||
return null;
|
||||
|
||||
if (!(await ctx.Cache.TryGetChannel(id) is Channel channel))
|
||||
return null;
|
||||
|
||||
if (!DiscordUtils.IsValidGuildChannel(channel))
|
||||
return null;
|
||||
|
||||
ctx.PopArgument();
|
||||
return channel;
|
||||
}
|
||||
|
||||
public static async Task<Guild> MatchGuild(this Context ctx)
|
||||
{
|
||||
try
|
||||
{
|
||||
var id = ulong.Parse(ctx.PeekArgument());
|
||||
var guild = await ctx.Cache.TryGetGuild(id);
|
||||
if (guild != null)
|
||||
ctx.PopArgument();
|
||||
|
||||
return guild;
|
||||
}
|
||||
catch (FormatException)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
}
|
||||
}
|
Reference in New Issue
Block a user