Proper fix for #1

This commit is contained in:
Laura Hausmann 2023-01-22 02:08:24 +01:00
parent 2133c73491
commit 82678907ba
Signed by: zotan
GPG key ID: D044E84C5BE01605
2 changed files with 58 additions and 24 deletions

View file

@ -9,15 +9,17 @@ using static tgcli.tgcli;
namespace tgcli { namespace tgcli {
public class Util { public class Util {
public static class Ansi { public static class Ansi {
public const string ResetAll = "\x1B[0m"; public const string ResetAll = "\x1B[0m";
public const string Red = "\x1b[31m"; public const string Red = "\x1b[31m";
public const string Green = "\x1b[32m"; public const string Green = "\x1b[32m";
public const string Yellow = "\x1b[33m"; public const string Yellow = "\x1b[33m";
public const string Blue = "\x1b[34m"; public const string Blue = "\x1b[34m";
public const string Magenta = "\x1b[35m"; public const string Magenta = "\x1b[35m";
public const string Cyan = "\x1b[36m"; public const string Cyan = "\x1b[36m";
public const string Bold = "\x1b[1m"; public const string Bold = "\x1b[1m";
public const string BoldOff = "\x1b[22m"; public const string BoldOff = "\x1b[22m";
public const string Inverse = "\x1b[7m";
public const string InverseOff = "\x1b[27m";
} }
public static User GetUser(long uid) { public static User GetUser(long uid) {
@ -350,7 +352,10 @@ namespace tgcli {
input = input.Replace(Ansi.Magenta, ""); input = input.Replace(Ansi.Magenta, "");
input = input.Replace(Ansi.Red, ""); input = input.Replace(Ansi.Red, "");
input = input.Replace(Ansi.Yellow, ""); input = input.Replace(Ansi.Yellow, "");
input = input.Replace(Ansi.Bold, "");
input = input.Replace(Ansi.BoldOff, ""); input = input.Replace(Ansi.BoldOff, "");
input = input.Replace(Ansi.Inverse, "");
input = input.Replace(Ansi.InverseOff, "");
input = input.Replace(Ansi.ResetAll, ""); input = input.Replace(Ansi.ResetAll, "");
return input.Length; return input.Length;
} }
@ -361,18 +366,46 @@ namespace tgcli {
return output + $"{Ansi.ResetAll}]"; 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) if (maxLen < 2)
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) { public static (string messageBuffer, int relativeCursorPosition) GetViewIntoMessageBuffer(string message, int absoluteCursorPosition, int bufferWidth) {
if (maxLen < 2) const int wraparoundOffsetPre = 2; // number of "untouchable" characters moving the cursor onto will cause a wrap on the right screen edge
maxLen = 2; const int wraparoundOffsetPost = 5; // number of "untouchable" characters moving the cursor onto will cause a wrap on the left screen edge
if (input.Contains("⏎ "))
input = "⏎ " + input.Split("⏎ ").Last(); const int wraparoundOffsetPreW = wraparoundOffsetPre + 1; // offset + 1 (character on the edge), for easier calculations
return input.Length < maxLen ? input : "<" + input.Substring(input.Length - maxLen + 2); 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<Tuple<string, string>> Emojis = new() { public static readonly List<Tuple<string, string>> Emojis = new() {

View file

@ -190,7 +190,8 @@ namespace tgcli {
output += "]"; output += "]";
output += " > "; output += " > ";
var prefixlen = GetActualStringWidth(output); var prefixlen = GetActualStringWidth(output);
output += TruncateMessageStart(currentInputLine, Console.LargestWindowWidth - GetActualStringWidth(output)); var inputLine = GetViewIntoMessageBuffer(currentInputLine, currentInputPos, Console.LargestWindowWidth - prefixlen);
output += inputLine.messageBuffer;
ClearCurrentConsoleLine(); ClearCurrentConsoleLine();
messageQueue.ForEach(p => Console.WriteLine(p + Ansi.ResetAll)); messageQueue.ForEach(p => Console.WriteLine(p + Ansi.ResetAll));
@ -198,7 +199,7 @@ namespace tgcli {
Console.Write("\a"); //ring terminal bell Console.Write("\a"); //ring terminal bell
messageQueue.Clear(); messageQueue.Clear();
Console.Write(output); 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}*")}"; var rest = $"{text}{(msg.EditDate == 0 ? "" : $"{Ansi.Yellow}*")}";
if (msg.InteractionInfo != null && msg.InteractionInfo.Reactions.Any(p => p.Type is ReactionType.ReactionTypeEmoji)) { if (msg.InteractionInfo != null && msg.InteractionInfo.Reactions.Any(p => p.Type is ReactionType.ReactionTypeEmoji)) {
rest = $"{rest} {Ansi.Cyan}<--"; rest = $"{rest} {Ansi.Cyan}<--";
foreach (var reaction in msg.InteractionInfo.Reactions) foreach (var reaction in msg.InteractionInfo.Reactions)
@ -524,11 +525,11 @@ namespace tgcli {
+ $"{text}" + $"{text}"
+ $"{Ansi.Yellow}*"; + $"{Ansi.Yellow}*";
} }
private static string FormatMessage(Update.UpdateMessageUnreadReactions msg) { private static string FormatMessage(Update.UpdateMessageUnreadReactions msg) {
string text; string text;
var message = GetMessage(msg.ChatId, msg.MessageId); var message = GetMessage(msg.ChatId, msg.MessageId);
if (message.Content is MessageContent.MessageText messageText) if (message.Content is MessageContent.MessageText messageText)
text = messageText.Text.Text; text = messageText.Text.Text;
else else
@ -590,12 +591,12 @@ namespace tgcli {
messageQueue.Add(formattedMessage); messageQueue.Add(formattedMessage);
ScreenUpdate(); ScreenUpdate();
} }
public static void AddMessageToQueue(Update.UpdateMessageUnreadReactions msg) { public static void AddMessageToQueue(Update.UpdateMessageUnreadReactions msg) {
//handle muted //handle muted
if (IsMuted(GetChat(msg.ChatId)) && currentChatId != msg.ChatId) if (IsMuted(GetChat(msg.ChatId)) && currentChatId != msg.ChatId)
return; return;
if (!msg.UnreadReactions.Any(p => p.Type is ReactionType.ReactionTypeEmoji)) if (!msg.UnreadReactions.Any(p => p.Type is ReactionType.ReactionTypeEmoji))
return; return;