diff --git a/src/NadekoBot/_Extensions/Extensions.cs b/src/NadekoBot/_Extensions/Extensions.cs index 06e872b1..1f915f25 100644 --- a/src/NadekoBot/_Extensions/Extensions.cs +++ b/src/NadekoBot/_Extensions/Extensions.cs @@ -32,8 +32,8 @@ namespace NadekoBot.Extensions public static async Task SendFileAsync(this IGuildUser user, Stream fileStream, string fileName, string caption = null, bool isTTS = false) => await (await user.CreateDMChannelAsync().ConfigureAwait(false)).SendFileAsync(fileStream, fileName, caption, isTTS).ConfigureAwait(false); - - public static async Task Reply(this IUserMessage msg, string content) => + + public static async Task Reply(this IUserMessage msg, string content) => await msg.Channel.SendMessageAsync(content).ConfigureAwait(false); public static bool IsAuthor(this IUserMessage msg) => @@ -41,39 +41,76 @@ namespace NadekoBot.Extensions public static IEnumerable Members(this IRole role) => NadekoBot.Client.GetGuild(role.GuildId)?.GetUsers().Where(u => u.Roles.Contains(role)) ?? Enumerable.Empty(); - - public static async Task ReplyLong(this IUserMessage msg, string content, string breakOn = "\n", string addToEnd = "", string addToStart = "") + + public static async Task ReplyLong(this IUserMessage msg, string content, string[] breakOn = null, string addToEnd = "", string addToStart = "") { - - if (content.Length < 2000) return new[] { await msg.Channel.SendMessageAsync(content).ConfigureAwait(false) }; + if (content.Length == 0) return null; + var characterLimit = 1750; + if (content.Length < characterLimit) return new[] { await msg.Channel.SendMessageAsync(content).ConfigureAwait(false) }; + if (breakOn == null) breakOn = new[] { "\n", " ", " " }; var list = new List(); - - var temp = Regex.Split(content, breakOn).Select(x => x += breakOn).ToList(); - string toolong; - //while ((toolong = temp.FirstOrDefault(x => x.Length > 2000)) != null) - //{ - // more desperate measures == split on whitespace? - //} - - StringBuilder builder = new StringBuilder(); - //make this less crappy to look at, maybe it's bugged - for (int i = 0; i < temp.Count; i++) + var splitItems = new List(); + foreach (var breaker in breakOn) { - var addition = temp[i]; - //we append - - if (builder.Length == 0 && i != 0) builder.Append(addToStart + addition); - else builder.Append(addition); - - //Check if the next would have room - if (i + 1 >= temp.Count || temp[i + 1].Length + builder.Length + addToEnd.Length > 2000) + if (splitItems.Count == 0) + { + splitItems = content.Split(new[] { breaker }, StringSplitOptions.RemoveEmptyEntries).Select(x => x += breaker).ToList(); + } + else + { + for (int i = 0; i < splitItems.Count; i++) + { + + var temp = splitItems[i]; + if (temp.Length > characterLimit) + { + var splitDeep = temp.Split(new[] { breaker }, StringSplitOptions.RemoveEmptyEntries).Select(x => x += breaker); + splitItems.RemoveAt(i); + splitItems.InsertRange(i, splitDeep); + } + } + } + if (splitItems.All(s => s.Length < characterLimit)) break; + } + //We remove any entries that are larger than 2000 chars + if (splitItems.Any(s => s.Length >= characterLimit)) + { + splitItems = splitItems.Where(s => s.Length < characterLimit).ToList(); + } + //ensured every item can be sent (if individually) + var firstItem = true; + Queue buildItems = new Queue(); + StringBuilder builder = new StringBuilder(); + + while (buildItems.Count > 0) + { + if (builder.Length == 0) + { + //first item to add + if (!firstItem) + builder.Append(addToStart); + else + firstItem = false; + builder.Append(buildItems.Dequeue()); + } else + { + builder.Append(buildItems.Dequeue()); + } + if (buildItems.Count == 0) { - if (i + 1 < temp.Count) builder.Append(addToEnd); list.Add(await msg.Channel.SendMessageAsync(builder.ToString())); builder.Clear(); + } else + { + var peeked = buildItems.Peek(); + if (builder.Length + peeked.Length + addToEnd.Length > characterLimit) + { + builder.Append(addToEnd); + list.Add(await msg.Channel.SendMessageAsync(builder.ToString())); + builder.Clear(); + } } } - return list.ToArray(); }