forked from EllieBotDevs/elliebot
91 lines
3.1 KiB
C#
91 lines
3.1 KiB
C#
|
#nullable disable
|
|||
|
using EllieBot.Db.Models;
|
|||
|
using System.Runtime.CompilerServices;
|
|||
|
|
|||
|
namespace EllieBot.Modules.EllieExpressions;
|
|||
|
|
|||
|
public static class EllieExpressionExtensions
|
|||
|
{
|
|||
|
private static string ResolveTriggerString(this string str, DiscordSocketClient client)
|
|||
|
=> str.Replace("%bot.mention%", client.CurrentUser.Mention, StringComparison.Ordinal);
|
|||
|
|
|||
|
public static async Task<IUserMessage> Send(
|
|||
|
this EllieExpression cr,
|
|||
|
IUserMessage ctx,
|
|||
|
IReplacementService repSvc,
|
|||
|
DiscordSocketClient client,
|
|||
|
IMessageSenderService sender)
|
|||
|
{
|
|||
|
var channel = cr.DmResponse ? await ctx.Author.CreateDMChannelAsync() : ctx.Channel;
|
|||
|
|
|||
|
var trigger = cr.Trigger.ResolveTriggerString(client);
|
|||
|
var substringIndex = trigger.Length;
|
|||
|
if (cr.ContainsAnywhere)
|
|||
|
{
|
|||
|
var pos = ctx.Content.AsSpan().GetWordPosition(trigger);
|
|||
|
if (pos == WordPosition.Start)
|
|||
|
substringIndex += 1;
|
|||
|
else if (pos == WordPosition.End)
|
|||
|
substringIndex = ctx.Content.Length;
|
|||
|
else if (pos == WordPosition.Middle)
|
|||
|
substringIndex += ctx.Content.IndexOf(trigger, StringComparison.InvariantCulture);
|
|||
|
}
|
|||
|
|
|||
|
var canMentionEveryone = (ctx.Author as IGuildUser)?.GuildPermissions.MentionEveryone ?? true;
|
|||
|
|
|||
|
var repCtx = new ReplacementContext(client: client,
|
|||
|
guild: (ctx.Channel as ITextChannel)?.Guild as SocketGuild,
|
|||
|
channel: ctx.Channel,
|
|||
|
user: ctx.Author
|
|||
|
)
|
|||
|
.WithOverride("%target%",
|
|||
|
() => canMentionEveryone
|
|||
|
? ctx.Content[substringIndex..].Trim()
|
|||
|
: ctx.Content[substringIndex..].Trim().SanitizeMentions(true));
|
|||
|
|
|||
|
var text = SmartText.CreateFrom(cr.Response);
|
|||
|
text = await repSvc.ReplaceAsync(text, repCtx);
|
|||
|
|
|||
|
return await sender.Response(channel).Text(text).Sanitize(false).SendAsync();
|
|||
|
}
|
|||
|
|
|||
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
|||
|
public static WordPosition GetWordPosition(this ReadOnlySpan<char> str, in ReadOnlySpan<char> word)
|
|||
|
{
|
|||
|
var wordIndex = str.IndexOf(word, StringComparison.OrdinalIgnoreCase);
|
|||
|
if (wordIndex == -1)
|
|||
|
return WordPosition.None;
|
|||
|
|
|||
|
if (wordIndex == 0)
|
|||
|
{
|
|||
|
if (word.Length < str.Length && str.IsValidWordDivider(word.Length))
|
|||
|
return WordPosition.Start;
|
|||
|
}
|
|||
|
else if (wordIndex + word.Length == str.Length)
|
|||
|
{
|
|||
|
if (str.IsValidWordDivider(wordIndex - 1))
|
|||
|
return WordPosition.End;
|
|||
|
}
|
|||
|
else if (str.IsValidWordDivider(wordIndex - 1) && str.IsValidWordDivider(wordIndex + word.Length))
|
|||
|
return WordPosition.Middle;
|
|||
|
|
|||
|
return WordPosition.None;
|
|||
|
}
|
|||
|
|
|||
|
private static bool IsValidWordDivider(this in ReadOnlySpan<char> str, int index)
|
|||
|
{
|
|||
|
var ch = str[index];
|
|||
|
if (ch is >= 'a' and <= 'z' or >= 'A' and <= 'Z' or >= '1' and <= '9')
|
|||
|
return false;
|
|||
|
|
|||
|
return true;
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
public enum WordPosition
|
|||
|
{
|
|||
|
None,
|
|||
|
Start,
|
|||
|
Middle,
|
|||
|
End
|
|||
|
}
|