| @@ -1,4 +1,5 @@ | |||
| using System.Diagnostics; | |||
| using System.Runtime.InteropServices; | |||
| namespace Discord.Commands | |||
| { | |||
| @@ -30,9 +30,9 @@ namespace Discord | |||
| IReadOnlyCollection<IEmbed> Embeds { get; } | |||
| /// <summary> Returns a collection of channel ids mentioned in this message. </summary> | |||
| 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; } | |||
| /// <summary> Modifies this message. </summary> | |||
| @@ -23,11 +23,11 @@ namespace Discord | |||
| public IMessageChannel Channel { 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 DateTimeOffset? EditedTimestamp => DateTimeUtils.FromTicks(_editedTimestampTicks); | |||
| @@ -41,9 +41,9 @@ namespace Discord | |||
| if (channel is IGuildChannel) | |||
| { | |||
| MentionedUsers = ImmutableArray.Create<User>(); | |||
| MentionedUsers = ImmutableArray.Create<IUser>(); | |||
| MentionedChannelIds = ImmutableArray.Create<ulong>(); | |||
| MentionedRoleIds = ImmutableArray.Create<ulong>(); | |||
| MentionedRoles = ImmutableArray.Create<IRole>(); | |||
| } | |||
| Update(model, UpdateSource.Creation); | |||
| @@ -106,21 +106,31 @@ namespace Discord | |||
| MentionedUsers = ImmutableArray.Create(mentions); | |||
| } | |||
| else | |||
| MentionedUsers = ImmutableArray.Create<User>(); | |||
| MentionedUsers = ImmutableArray.Create<IUser>(); | |||
| } | |||
| if (model.Content.IsSpecified) | |||
| { | |||
| 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 | |||
| Text = RawText; | |||
| @@ -172,12 +182,6 @@ namespace Discord | |||
| } | |||
| 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.Linq; | |||
| using System.Text.RegularExpressions; | |||
| using System.Threading.Tasks; | |||
| namespace Discord | |||
| { | |||
| @@ -107,7 +108,7 @@ namespace Discord | |||
| 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 => | |||
| { | |||
| @@ -123,58 +124,71 @@ namespace Discord | |||
| } | |||
| 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; | |||
| 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; | |||
| })); | |||
| } | |||
| 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 => | |||
| { | |||
| ulong 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 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; | |||
| 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) | |||
| mentions.Add(role); | |||