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 {
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<Tuple<string, string>> Emojis = new() {

View file

@ -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;