From 82678907ba73d0682ac18c98f5fd3a19164fcde5 Mon Sep 17 00:00:00 2001 From: Laura Hausmann Date: Sun, 22 Jan 2023 02:08:24 +0100 Subject: [PATCH] Proper fix for #1 --- tgcli/Util.cs | 67 +++++++++++++++++++++++++++++++++++++------------- tgcli/tgcli.cs | 15 +++++------ 2 files changed, 58 insertions(+), 24 deletions(-) diff --git a/tgcli/Util.cs b/tgcli/Util.cs index cd09573..861c90c 100644 --- a/tgcli/Util.cs +++ b/tgcli/Util.cs @@ -9,15 +9,17 @@ using static tgcli.tgcli; namespace tgcli { public class Util { public static class Ansi { - public const string ResetAll = "\x1B[0m"; - public const string Red = "\x1b[31m"; - public const string Green = "\x1b[32m"; - public const string Yellow = "\x1b[33m"; - public const string Blue = "\x1b[34m"; - public const string Magenta = "\x1b[35m"; - public const string Cyan = "\x1b[36m"; - public const string Bold = "\x1b[1m"; - public const string BoldOff = "\x1b[22m"; + public const string ResetAll = "\x1B[0m"; + public const string Red = "\x1b[31m"; + public const string Green = "\x1b[32m"; + public const string Yellow = "\x1b[33m"; + public const string Blue = "\x1b[34m"; + public const string Magenta = "\x1b[35m"; + public const string Cyan = "\x1b[36m"; + public const string Bold = "\x1b[1m"; + public const string BoldOff = "\x1b[22m"; + public const string Inverse = "\x1b[7m"; + public const string InverseOff = "\x1b[27m"; } public static User GetUser(long uid) { @@ -350,7 +352,10 @@ namespace tgcli { input = input.Replace(Ansi.Magenta, ""); input = input.Replace(Ansi.Red, ""); input = input.Replace(Ansi.Yellow, ""); + input = input.Replace(Ansi.Bold, ""); input = input.Replace(Ansi.BoldOff, ""); + input = input.Replace(Ansi.Inverse, ""); + input = input.Replace(Ansi.InverseOff, ""); input = input.Replace(Ansi.ResetAll, ""); return input.Length; } @@ -361,18 +366,46 @@ namespace tgcli { return output + $"{Ansi.ResetAll}]"; } - public static string TruncateString(string input, int maxLen) { + public static string TruncateString(string input, int maxLen, string truncateMarker = "~") { if (maxLen < 2) maxLen = 2; - return input.Length <= maxLen ? input : input.Substring(0, maxLen - 1) + "~"; + return input.Length <= maxLen ? input : input.Substring(0, maxLen - 1) + truncateMarker; } - public static string TruncateMessageStart(string input, int maxLen) { - if (maxLen < 2) - maxLen = 2; - if (input.Contains("⏎ ")) - input = "⏎ " + input.Split("⏎ ").Last(); - return input.Length < maxLen ? input : "<" + input.Substring(input.Length - maxLen + 2); + public static (string messageBuffer, int relativeCursorPosition) GetViewIntoMessageBuffer(string message, int absoluteCursorPosition, int bufferWidth) { + const int wraparoundOffsetPre = 2; // number of "untouchable" characters moving the cursor onto will cause a wrap on the right screen edge + const int wraparoundOffsetPost = 5; // number of "untouchable" characters moving the cursor onto will cause a wrap on the left screen edge + + const int wraparoundOffsetPreW = wraparoundOffsetPre + 1; // offset + 1 (character on the edge), for easier calculations + const int wraparoundOffsetPostW = wraparoundOffsetPost + 1; // offset + 1 (character on the edge), for easier calculations + + if (absoluteCursorPosition > message.Length) + throw new ArgumentOutOfRangeException(); + + if (message.Length < bufferWidth) + return (message, absoluteCursorPosition); + + if (absoluteCursorPosition < bufferWidth - wraparoundOffsetPre - 1) + return (TruncateString(message, bufferWidth, $"{Ansi.Inverse}>{Ansi.InverseOff}"), absoluteCursorPosition); + + // now we can be sure the message needs at least one wrap + + // first wrap + // get rid of the content shown on the zeroth wrap, which is buf width minus wraparoundPreW (respects > character on screen edge) + var finalMessage = message[(bufferWidth - wraparoundOffsetPreW - wraparoundOffsetPost)..]; + var finalCursorPos = absoluteCursorPosition - bufferWidth + wraparoundOffsetPreW + wraparoundOffsetPostW; + + // successive wraps + // repeat above steps (but respective of the new < character) until the string fits into the buffer + // it fits into the buffer when cursorPos >= bufferwidth minus wraparound (this time respecting > character absent on first wrap) + while (finalCursorPos >= bufferWidth - wraparoundOffsetPreW) { + finalMessage = finalMessage[(bufferWidth - wraparoundOffsetPreW - wraparoundOffsetPostW)..]; + finalCursorPos = finalCursorPos - bufferWidth + wraparoundOffsetPreW + wraparoundOffsetPostW; + } + + finalMessage = TruncateString(finalMessage, bufferWidth - 1, $"{Ansi.Inverse}>{Ansi.InverseOff}"); + + return ($"{Ansi.Inverse}<{Ansi.InverseOff}" + finalMessage, finalCursorPos); } public static readonly List> Emojis = new() { diff --git a/tgcli/tgcli.cs b/tgcli/tgcli.cs index 9f6769a..1fb380c 100644 --- a/tgcli/tgcli.cs +++ b/tgcli/tgcli.cs @@ -190,7 +190,8 @@ namespace tgcli { output += "]"; output += " > "; var prefixlen = GetActualStringWidth(output); - output += TruncateMessageStart(currentInputLine, Console.LargestWindowWidth - GetActualStringWidth(output)); + var inputLine = GetViewIntoMessageBuffer(currentInputLine, currentInputPos, Console.LargestWindowWidth - prefixlen); + output += inputLine.messageBuffer; ClearCurrentConsoleLine(); messageQueue.ForEach(p => Console.WriteLine(p + Ansi.ResetAll)); @@ -198,7 +199,7 @@ namespace tgcli { Console.Write("\a"); //ring terminal bell messageQueue.Clear(); Console.Write(output); - Console.Write($"\u001b[{Math.Min(currentInputPos + prefixlen + 1, Console.LargestWindowWidth)}G"); + Console.Write($"\u001b[{inputLine.relativeCursorPosition + prefixlen + 1}G"); } } @@ -450,7 +451,7 @@ namespace tgcli { } var rest = $"{text}{(msg.EditDate == 0 ? "" : $"{Ansi.Yellow}*")}"; - + if (msg.InteractionInfo != null && msg.InteractionInfo.Reactions.Any(p => p.Type is ReactionType.ReactionTypeEmoji)) { rest = $"{rest} {Ansi.Cyan}<--"; foreach (var reaction in msg.InteractionInfo.Reactions) @@ -524,11 +525,11 @@ namespace tgcli { + $"{text}" + $"{Ansi.Yellow}*"; } - + private static string FormatMessage(Update.UpdateMessageUnreadReactions msg) { string text; - var message = GetMessage(msg.ChatId, msg.MessageId); + var message = GetMessage(msg.ChatId, msg.MessageId); if (message.Content is MessageContent.MessageText messageText) text = messageText.Text.Text; else @@ -590,12 +591,12 @@ namespace tgcli { messageQueue.Add(formattedMessage); ScreenUpdate(); } - + public static void AddMessageToQueue(Update.UpdateMessageUnreadReactions msg) { //handle muted if (IsMuted(GetChat(msg.ChatId)) && currentChatId != msg.ChatId) return; - + if (!msg.UnreadReactions.Any(p => p.Type is ReactionType.ReactionTypeEmoji)) return;