Refactor
This commit is contained in:
parent
65d8141d18
commit
f3372f39e4
|
@ -10,45 +10,43 @@ public class PagedMessageInput {
|
|||
[InlineData(218)]
|
||||
[InlineData(219)]
|
||||
[InlineData(289)]
|
||||
public void Test1(int offset) {
|
||||
public void TestGetPagedMessageInput(int offset) {
|
||||
const string testMessage =
|
||||
"this is a test string please ignore 1, this is a test string please ignore 2, this is a test string please ignore 3, this is a test string please ignore 4, this is a test string please ignore 5, this is a test string please ignore 6, this is a test string please ignore 7, this is a test str.";
|
||||
const int testBufferWidth = 80;
|
||||
Assert.Equal(ReferenceMethods.GetViewIntoMessageBuffer(testMessage, offset, testBufferWidth),
|
||||
Util.GetViewIntoMessageBuffer(testMessage, offset, testBufferWidth));
|
||||
Assert.Equal(ReferenceMethods.GetPagedMessageInputLine(testMessage, offset, testBufferWidth), Util.GetPagedMessageInputLine(testMessage, offset, testBufferWidth));
|
||||
}
|
||||
|
||||
private static class ReferenceMethods {
|
||||
internal 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
|
||||
internal static (string messageBuffer, int relCursorPos) GetPagedMessageInputLine(string message, int absCursorPos, int bufferWidth) {
|
||||
const int wrapOffsetPre = 2; // number of "untouchable" characters moving the cursor onto will cause a wrap on the right screen edge
|
||||
const int wrapOffsetPost = 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
|
||||
const int wrapOffsetPreI = wrapOffsetPre + 1; // offset + 1 (character on the edge), for easier calculations
|
||||
const int wrapOffsetPostI = wrapOffsetPost + 1; // offset + 1 (character on the edge), for easier calculations
|
||||
|
||||
if (absoluteCursorPosition > message.Length)
|
||||
throw new ArgumentOutOfRangeException();
|
||||
if (absCursorPos > message.Length)
|
||||
throw new ArgumentOutOfRangeException(nameof(absCursorPos), "Cursor position exceeds message length");
|
||||
|
||||
if (message.Length < bufferWidth)
|
||||
return (message, absoluteCursorPosition);
|
||||
return (message, absCursorPos);
|
||||
|
||||
if (absoluteCursorPosition < bufferWidth - wraparoundOffsetPre - 1)
|
||||
return (Util.TruncateString(message, bufferWidth, $"{Util.Ansi.Inverse}>{Util.Ansi.InverseOff}"), absoluteCursorPosition);
|
||||
if (absCursorPos < bufferWidth - wrapOffsetPre - 1)
|
||||
return (Util.TruncateString(message, bufferWidth, $"{Util.Ansi.Inverse}>{Util.Ansi.InverseOff}"), absCursorPos);
|
||||
|
||||
// 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;
|
||||
var finalMessage = message[(bufferWidth - wrapOffsetPreI - wrapOffsetPost)..];
|
||||
var finalCursorPos = absCursorPos - bufferWidth + wrapOffsetPreI + wrapOffsetPostI;
|
||||
|
||||
// successive wraps
|
||||
// repeat above steps (but counting 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;
|
||||
while (finalCursorPos >= bufferWidth - wrapOffsetPreI) {
|
||||
finalMessage = finalMessage[(bufferWidth - wrapOffsetPreI - wrapOffsetPostI)..];
|
||||
finalCursorPos = finalCursorPos - bufferWidth + wrapOffsetPreI + wrapOffsetPostI;
|
||||
}
|
||||
|
||||
finalMessage = Util.TruncateString(finalMessage, bufferWidth - 1, $"{Util.Ansi.Inverse}>{Util.Ansi.InverseOff}");
|
||||
|
|
|
@ -219,7 +219,7 @@ public static class Util {
|
|||
}
|
||||
else {
|
||||
if (key.Key == ConsoleKey.Backspace && pass.Length > 0) {
|
||||
pass = pass.Substring(0, (pass.Length - 1));
|
||||
pass = pass[..^1];
|
||||
Console.Write("\b \b");
|
||||
}
|
||||
else if (key.Key == ConsoleKey.Enter) {
|
||||
|
@ -238,9 +238,7 @@ public static class Util {
|
|||
|
||||
Emojis.ForEach(em => message = message.Replace(em.Item1, em.Item2));
|
||||
client.ExecuteAsync(new SendMessage {
|
||||
ChatId = chatId,
|
||||
InputMessageContent = new InputMessageContent.InputMessageText { Text = new FormattedText { Text = message } },
|
||||
ReplyToMessageId = replyTo,
|
||||
ChatId = chatId, InputMessageContent = new InputMessageContent.InputMessageText { Text = new FormattedText { Text = message } }, ReplyToMessageId = replyTo,
|
||||
});
|
||||
currentUserRead = false;
|
||||
}
|
||||
|
@ -271,8 +269,7 @@ public static class Util {
|
|||
var results = client.ExecuteAsync(new SearchChats { Query = query, Limit = 5 }).Result;
|
||||
|
||||
return query.StartsWith("@")
|
||||
? results.ChatIds.First(p => GetChat(p).Type is ChatType.ChatTypePrivate type
|
||||
&& GetUser(type.UserId).Usernames.ActiveUsernames.Contains(query[1..]))
|
||||
? results.ChatIds.First(p => GetChat(p).Type is ChatType.ChatTypePrivate type && GetUser(type.UserId).Usernames.ActiveUsernames.Contains(query[1..]))
|
||||
: results.ChatIds.First(p => !(GetChat(p).Type is ChatType.ChatTypeSecret));
|
||||
}
|
||||
catch {
|
||||
|
@ -369,31 +366,31 @@ public static class Util {
|
|||
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) + truncateMarker;
|
||||
return input.Length <= maxLen ? input : input[..(maxLen - 1)] + truncateMarker;
|
||||
}
|
||||
|
||||
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
|
||||
public static (string messageBuffer, int relCursorPos) GetPagedMessageInputLine(string message, int absCursorPos, int bufferWidth) {
|
||||
const int wrapdOffsetPre = 2; // number of "untouchable" characters moving the cursor onto will cause a wrap on the right screen edge
|
||||
const int wrapOffsetPost = 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
|
||||
const int wrapOffsetPreI = wrapdOffsetPre + 1; // offset + 1 (indicator on the edge), for easier calculations
|
||||
const int wrapOffsetPostI = wrapOffsetPost + 1; // offset + 1 (indicator on the edge), for easier calculations
|
||||
|
||||
if (absoluteCursorPosition > message.Length)
|
||||
throw new ArgumentOutOfRangeException(nameof(absoluteCursorPosition), "Cursor position exceeds message length");
|
||||
if (absCursorPos > message.Length)
|
||||
throw new ArgumentOutOfRangeException(nameof(absCursorPos), "Cursor position exceeds message length");
|
||||
|
||||
if (message.Length < bufferWidth) // entire message fits in buffer
|
||||
return (message, absoluteCursorPosition); // return input as-is
|
||||
if (message.Length < bufferWidth) // entire message fits in buffer
|
||||
return (message, absCursorPos); // return input as-is
|
||||
|
||||
if (absoluteCursorPosition < bufferWidth - wraparoundOffsetPre - 1) // message is longer than buffer but we're on the first page
|
||||
return (TruncateString(message, bufferWidth, $"{Ansi.Inverse}>{Ansi.InverseOff}"), absoluteCursorPosition); // return input as-is but truncated and with a > indicator
|
||||
if (absCursorPos < bufferWidth - wrapdOffsetPre - 1) // message is longer than buffer but we're on the first page
|
||||
return (TruncateString(message, bufferWidth, $"{Ansi.Inverse}>{Ansi.InverseOff}"), absCursorPos); // return input as-is but truncated and with a > indicator
|
||||
|
||||
var wraparounds = (absoluteCursorPosition - wraparoundOffsetPostW) / (bufferWidth - wraparoundOffsetPreW - wraparoundOffsetPostW);
|
||||
var finalCursorPos = absoluteCursorPosition - bufferWidth + wraparoundOffsetPreW + wraparoundOffsetPostW * wraparounds;
|
||||
finalCursorPos %= bufferWidth - wraparoundOffsetPreW;
|
||||
var wraps = (absCursorPos - wrapOffsetPostI) / (bufferWidth - wrapOffsetPreI - wrapOffsetPostI); // black magic
|
||||
var finalCursorPos = absCursorPos - bufferWidth + wrapOffsetPreI + wrapOffsetPostI * wraps; // respect the special case of the first page & add one post offset per wrap
|
||||
finalCursorPos %= bufferWidth - wrapOffsetPreI; // make sure the final cursor position is within the acceptable range (between zero and bufWidth - wrapOffsetPreI)
|
||||
|
||||
var messageOffset = (bufferWidth - wraparoundOffsetPreW - wraparoundOffsetPostW) * wraparounds + 1; // +1 to account for the first wrap not having a < indicator
|
||||
var finalMessage = message[messageOffset..];
|
||||
var messageOffset = (bufferWidth - wrapOffsetPreI - wrapOffsetPostI) * wraps + 1; // +1 to account for the first wrap not having a < indicator
|
||||
var finalMessage = message[messageOffset..]; // we only care about the message starting from the current page
|
||||
|
||||
finalMessage = TruncateString(finalMessage, bufferWidth - 1, $"{Ansi.Inverse}>{Ansi.InverseOff}"); // replace the last character with a > indicator if required
|
||||
|
||||
|
@ -413,8 +410,8 @@ public static class Util {
|
|||
};
|
||||
|
||||
public static void InsertToInputLine(string strToInsert) {
|
||||
var part1 = currentInputLine.Substring(0, currentInputPos);
|
||||
var part2 = currentInputLine.Substring(currentInputPos);
|
||||
var part1 = currentInputLine[..currentInputPos];
|
||||
var part2 = currentInputLine[currentInputPos..];
|
||||
currentInputLine = part1 + strToInsert + part2;
|
||||
currentInputPos += strToInsert.Length;
|
||||
}
|
||||
|
@ -425,14 +422,14 @@ public static class Util {
|
|||
}
|
||||
|
||||
public static void RemoveFromInputLine(bool word = false) {
|
||||
var part1 = currentInputLine.Substring(0, currentInputPos);
|
||||
var part1 = currentInputLine[..currentInputPos];
|
||||
var oldlen = part1.Length;
|
||||
var part2 = currentInputLine.Substring(currentInputPos);
|
||||
var part2 = currentInputLine[currentInputPos..];
|
||||
if (word) {
|
||||
var lastIndex = part1.TrimEnd().LastIndexOf(" ", StringComparison.Ordinal);
|
||||
if (lastIndex < 0)
|
||||
lastIndex = 0;
|
||||
part1 = part1.Substring(0, lastIndex);
|
||||
part1 = part1[..lastIndex];
|
||||
if (lastIndex != 0)
|
||||
part1 += " ";
|
||||
//if (part1.EndsWith("⏎"))
|
||||
|
@ -445,18 +442,18 @@ public static class Util {
|
|||
return;
|
||||
}
|
||||
|
||||
currentInputLine = part1.Substring(0, part1.Length - 1) + part2;
|
||||
currentInputLine = part1[..^1] + part2;
|
||||
currentInputPos--;
|
||||
}
|
||||
|
||||
public static void RemoveFromInputLineForward(bool word = false) {
|
||||
var part1 = currentInputLine.Substring(0, currentInputPos);
|
||||
var part2 = currentInputLine.Substring(currentInputPos).TrimStart();
|
||||
var part1 = currentInputLine[..currentInputPos];
|
||||
var part2 = currentInputLine[currentInputPos..].TrimStart();
|
||||
if (word) {
|
||||
var index = part2.IndexOf(" ", StringComparison.Ordinal);
|
||||
if (index < 0)
|
||||
index = part2.Length - 1;
|
||||
part2 = part2.Substring(index + 1);
|
||||
part2 = part2[(index + 1)..];
|
||||
if (index != 0)
|
||||
part2 = " " + part2;
|
||||
//if (part2.StartsWith("⏎"))
|
||||
|
@ -466,7 +463,7 @@ public static class Util {
|
|||
return;
|
||||
}
|
||||
|
||||
currentInputLine = part1 + part2.Substring(1);
|
||||
currentInputLine = part1 + part2[1..];
|
||||
}
|
||||
|
||||
public static readonly List<ConsoleKey> SpecialKeys = new() {
|
||||
|
|
|
@ -190,8 +190,8 @@ public static class tgcli {
|
|||
else
|
||||
output += "]";
|
||||
output += " > ";
|
||||
var prefixlen = GetActualStringWidth(output);
|
||||
var inputLine = GetViewIntoMessageBuffer(currentInputLine, currentInputPos, Console.LargestWindowWidth - prefixlen);
|
||||
var prefixlen = GetActualStringWidth(output);
|
||||
var inputLine = GetPagedMessageInputLine(currentInputLine, currentInputPos, Console.LargestWindowWidth - prefixlen);
|
||||
output += inputLine.messageBuffer;
|
||||
|
||||
ClearCurrentConsoleLine();
|
||||
|
@ -200,7 +200,7 @@ public static class tgcli {
|
|||
Console.Write("\a"); //ring terminal bell
|
||||
messageQueue.Clear();
|
||||
Console.Write(output);
|
||||
Console.Write($"\u001b[{inputLine.relativeCursorPosition + prefixlen + 1}G");
|
||||
Console.Write($"\u001b[{inputLine.relCursorPos + prefixlen + 1}G");
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -212,7 +212,7 @@ public static class tgcli {
|
|||
ScreenUpdate();
|
||||
break;
|
||||
case ConsoleKey.Enter when currentInputLine.StartsWith("/"): {
|
||||
var command = currentInputLine.Substring(1);
|
||||
var command = currentInputLine[1..];
|
||||
SetInputLine("");
|
||||
HandleCommand(command);
|
||||
ScreenUpdate();
|
||||
|
@ -257,7 +257,7 @@ public static class tgcli {
|
|||
if (currentInputPos == 0)
|
||||
break;
|
||||
|
||||
var part1 = currentInputLine.Substring(0, currentInputPos);
|
||||
var part1 = currentInputLine[..currentInputPos];
|
||||
var lastIndex = part1.TrimEnd().LastIndexOf(" ", StringComparison.Ordinal);
|
||||
if (lastIndex < 0)
|
||||
lastIndex = 0;
|
||||
|
|
Loading…
Reference in a new issue