@@ -1,4 +1,5 @@ | |||||
using System.Diagnostics; | using System.Diagnostics; | ||||
using System.Runtime.InteropServices; | |||||
namespace Discord.Commands | namespace Discord.Commands | ||||
{ | { | ||||
@@ -30,9 +30,9 @@ namespace Discord | |||||
IReadOnlyCollection<IEmbed> Embeds { get; } | IReadOnlyCollection<IEmbed> Embeds { get; } | ||||
/// <summary> Returns a collection of channel ids mentioned in this message. </summary> | /// <summary> Returns a collection of channel ids mentioned in this message. </summary> | ||||
IReadOnlyCollection<ulong> MentionedChannelIds { get; } | IReadOnlyCollection<ulong> MentionedChannelIds { get; } | ||||
/// <summary> Returns a collection of role ids mentioned in this message. </summary> | |||||
IReadOnlyCollection<ulong> MentionedRoleIds { get; } | |||||
/// <summary> Returns a collection of user ids mentioned in this message. </summary> | |||||
/// <summary> Returns a collection of roles mentioned in this message. </summary> | |||||
IReadOnlyCollection<IRole> MentionedRoles { get; } | |||||
/// <summary> Returns a collection of users mentioned in this message. </summary> | |||||
IReadOnlyCollection<IUser> MentionedUsers { get; } | IReadOnlyCollection<IUser> MentionedUsers { get; } | ||||
/// <summary> Modifies this message. </summary> | /// <summary> Modifies this message. </summary> | ||||
@@ -23,11 +23,11 @@ namespace Discord | |||||
public IMessageChannel Channel { get; } | public IMessageChannel Channel { get; } | ||||
public IUser Author { get; } | public IUser Author { get; } | ||||
public ImmutableArray<Attachment> Attachments { get; private set; } | |||||
public ImmutableArray<Embed> Embeds { get; private set; } | |||||
public ImmutableArray<ulong> MentionedChannelIds { get; private set; } | |||||
public ImmutableArray<ulong> MentionedRoleIds { get; private set; } | |||||
public ImmutableArray<User> MentionedUsers { get; private set; } | |||||
public IReadOnlyCollection<Attachment> Attachments { get; private set; } | |||||
public IReadOnlyCollection<IEmbed> Embeds { get; private set; } | |||||
public IReadOnlyCollection<ulong> MentionedChannelIds { get; private set; } | |||||
public IReadOnlyCollection<IRole> MentionedRoles { get; private set; } | |||||
public IReadOnlyCollection<IUser> MentionedUsers { get; private set; } | |||||
public override DiscordClient Discord => (Channel as Entity<ulong>).Discord; | public override DiscordClient Discord => (Channel as Entity<ulong>).Discord; | ||||
public DateTimeOffset? EditedTimestamp => DateTimeUtils.FromTicks(_editedTimestampTicks); | public DateTimeOffset? EditedTimestamp => DateTimeUtils.FromTicks(_editedTimestampTicks); | ||||
@@ -41,9 +41,9 @@ namespace Discord | |||||
if (channel is IGuildChannel) | if (channel is IGuildChannel) | ||||
{ | { | ||||
MentionedUsers = ImmutableArray.Create<User>(); | |||||
MentionedUsers = ImmutableArray.Create<IUser>(); | |||||
MentionedChannelIds = ImmutableArray.Create<ulong>(); | MentionedChannelIds = ImmutableArray.Create<ulong>(); | ||||
MentionedRoleIds = ImmutableArray.Create<ulong>(); | |||||
MentionedRoles = ImmutableArray.Create<IRole>(); | |||||
} | } | ||||
Update(model, UpdateSource.Creation); | Update(model, UpdateSource.Creation); | ||||
@@ -106,21 +106,31 @@ namespace Discord | |||||
MentionedUsers = ImmutableArray.Create(mentions); | MentionedUsers = ImmutableArray.Create(mentions); | ||||
} | } | ||||
else | else | ||||
MentionedUsers = ImmutableArray.Create<User>(); | |||||
MentionedUsers = ImmutableArray.Create<IUser>(); | |||||
} | } | ||||
if (model.Content.IsSpecified) | if (model.Content.IsSpecified) | ||||
{ | { | ||||
RawText = model.Content.Value; | RawText = model.Content.Value; | ||||
if (Channel is IGuildChannel) | |||||
if (guildChannel != null) | |||||
{ | { | ||||
Text = MentionUtils.CleanUserMentions(RawText, MentionedUsers); | |||||
MentionedChannelIds = MentionUtils.GetChannelMentions(RawText); | |||||
var mentionedRoleIds = MentionUtils.GetRoleMentions(RawText); | |||||
if (_isMentioningEveryone) | |||||
mentionedRoleIds = mentionedRoleIds.Add(guildChannel.Guild.EveryoneRole.Id); | |||||
MentionedRoleIds = mentionedRoleIds; | |||||
var orderedMentionedUsers = ImmutableArray.CreateBuilder<IUser>(5); | |||||
Text = MentionUtils.CleanUserMentions(RawText, Channel.IsAttached ? Channel : null, MentionedUsers, orderedMentionedUsers); | |||||
MentionedUsers = orderedMentionedUsers.ToImmutable(); | |||||
var roles = ImmutableArray.CreateBuilder<IRole>(5); | |||||
Text = MentionUtils.CleanRoleMentions(Text, guildChannel.Guild, roles); | |||||
MentionedRoles = roles.ToImmutable(); | |||||
if (guildChannel.IsAttached) //It's too expensive to do a channel lookup in REST mode | |||||
{ | |||||
var channelIds = ImmutableArray.CreateBuilder<ulong>(5); | |||||
Text = MentionUtils.CleanChannelMentions(Text, guildChannel.Guild, channelIds); | |||||
MentionedChannelIds = channelIds.ToImmutable(); | |||||
} | |||||
else | |||||
MentionedChannelIds = MentionUtils.GetChannelMentions(RawText); | |||||
} | } | ||||
else | else | ||||
Text = RawText; | Text = RawText; | ||||
@@ -172,12 +182,6 @@ namespace Discord | |||||
} | } | ||||
public override string ToString() => Text; | public override string ToString() => Text; | ||||
private string DebuggerDisplay => $"{Author}: {Text}{(Attachments.Length > 0 ? $" [{Attachments.Length} Attachments]" : "")}"; | |||||
IReadOnlyCollection<Attachment> IMessage.Attachments => Attachments; | |||||
IReadOnlyCollection<IEmbed> IMessage.Embeds => Embeds; | |||||
IReadOnlyCollection<ulong> IMessage.MentionedChannelIds => MentionedChannelIds; | |||||
IReadOnlyCollection<ulong> IMessage.MentionedRoleIds => MentionedRoleIds; | |||||
IReadOnlyCollection<IUser> IMessage.MentionedUsers => MentionedUsers; | |||||
private string DebuggerDisplay => $"{Author}: {Text}{(Attachments.Count > 0 ? $" [{Attachments.Count} Attachments]" : "")}"; | |||||
} | } | ||||
} | } |
@@ -4,6 +4,7 @@ using System.Collections.Immutable; | |||||
using System.Globalization; | using System.Globalization; | ||||
using System.Linq; | using System.Linq; | ||||
using System.Text.RegularExpressions; | using System.Text.RegularExpressions; | ||||
using System.Threading.Tasks; | |||||
namespace Discord | namespace Discord | ||||
{ | { | ||||
@@ -107,7 +108,7 @@ namespace Discord | |||||
return builder; | return builder; | ||||
} | } | ||||
internal static string CleanUserMentions(string text, ImmutableArray<User> mentions) | |||||
/*internal static string CleanUserMentions(string text, ImmutableArray<User> mentions) | |||||
{ | { | ||||
return _userRegex.Replace(text, new MatchEvaluator(e => | return _userRegex.Replace(text, new MatchEvaluator(e => | ||||
{ | { | ||||
@@ -123,58 +124,71 @@ namespace Discord | |||||
} | } | ||||
return e.Value; | return e.Value; | ||||
})); | })); | ||||
} | |||||
internal static string CleanUserMentions<T>(string text, IReadOnlyDictionary<ulong, T> users, ImmutableArray<T>.Builder mentions = null) | |||||
where T : IGuildUser | |||||
}*/ | |||||
internal static string CleanUserMentions(string text, IMessageChannel channel, IReadOnlyCollection<IUser> fallbackUsers, ImmutableArray<IUser>.Builder mentions = null) | |||||
{ | { | ||||
return _channelRegex.Replace(text, new MatchEvaluator(e => | |||||
return _userRegex.Replace(text, new MatchEvaluator(e => | |||||
{ | { | ||||
ulong id; | ulong id; | ||||
if (ulong.TryParse(e.Groups[1].Value, NumberStyles.None, CultureInfo.InvariantCulture, out id)) | if (ulong.TryParse(e.Groups[1].Value, NumberStyles.None, CultureInfo.InvariantCulture, out id)) | ||||
{ | { | ||||
T user; | |||||
if (users.TryGetValue(id, out user)) | |||||
IUser user = null; | |||||
if (channel != null) | |||||
user = channel.GetUserAsync(id).GetAwaiter().GetResult() as IUser; | |||||
if (user == null) | |||||
{ | |||||
foreach (var fallbackUser in fallbackUsers) | |||||
{ | |||||
if (fallbackUser.Id == id) | |||||
{ | |||||
user = fallbackUser; | |||||
break; | |||||
} | |||||
} | |||||
} | |||||
if (user != null) | |||||
{ | { | ||||
if (users != null) | |||||
mentions.Add(user); | |||||
if (e.Value[2] == '!' && user.Nickname != null) | |||||
return '@' + user.Nickname; | |||||
else | |||||
return '@' + user.Username; | |||||
mentions.Add(user); | |||||
if (e.Value[2] == '!') | |||||
{ | |||||
var guildUser = user as IGuildUser; | |||||
if (guildUser != null && guildUser.Nickname != null) | |||||
return '@' + guildUser.Nickname; | |||||
} | |||||
return '@' + user.Username; | |||||
} | } | ||||
} | } | ||||
return e.Value; | return e.Value; | ||||
})); | })); | ||||
} | } | ||||
internal static string CleanChannelMentions<T>(string text, IReadOnlyDictionary<ulong, T> channels, ImmutableArray<T>.Builder mentions = null) | |||||
where T : IGuildChannel | |||||
internal static string CleanChannelMentions(string text, IGuild guild, ImmutableArray<ulong>.Builder mentions = null) | |||||
{ | { | ||||
return _channelRegex.Replace(text, new MatchEvaluator(e => | return _channelRegex.Replace(text, new MatchEvaluator(e => | ||||
{ | { | ||||
ulong id; | ulong id; | ||||
if (ulong.TryParse(e.Groups[1].Value, NumberStyles.None, CultureInfo.InvariantCulture, out id)) | if (ulong.TryParse(e.Groups[1].Value, NumberStyles.None, CultureInfo.InvariantCulture, out id)) | ||||
{ | { | ||||
T channel; | |||||
if (channels.TryGetValue(id, out channel)) | |||||
var channel = guild.GetChannelAsync(id).GetAwaiter().GetResult() as IGuildChannel; | |||||
if (channel != null) | |||||
{ | { | ||||
if (channels != null) | |||||
mentions.Add(channel); | |||||
if (mentions != null) | |||||
mentions.Add(channel.Id); | |||||
return '#' + channel.Name; | return '#' + channel.Name; | ||||
} | } | ||||
} | } | ||||
return e.Value; | return e.Value; | ||||
})); | })); | ||||
} | } | ||||
internal static string CleanRoleMentions<T>(string text, IReadOnlyDictionary<ulong, T> roles, ImmutableArray<T>.Builder mentions = null) | |||||
where T : IRole | |||||
internal static string CleanRoleMentions(string text, IGuild guild, ImmutableArray<IRole>.Builder mentions = null) | |||||
{ | { | ||||
return _channelRegex.Replace(text, new MatchEvaluator(e => | |||||
return _roleRegex.Replace(text, new MatchEvaluator(e => | |||||
{ | { | ||||
ulong id; | ulong id; | ||||
if (ulong.TryParse(e.Groups[1].Value, NumberStyles.None, CultureInfo.InvariantCulture, out id)) | if (ulong.TryParse(e.Groups[1].Value, NumberStyles.None, CultureInfo.InvariantCulture, out id)) | ||||
{ | { | ||||
T role; | |||||
if (roles.TryGetValue(id, out role)) | |||||
var role = guild.GetRole(id); | |||||
if (role != null) | |||||
{ | { | ||||
if (mentions != null) | if (mentions != null) | ||||
mentions.Add(role); | mentions.Add(role); | ||||