mirror of
https://github.com/microsoft/terminal.git
synced 2025-12-11 04:38:24 -06:00
Fix remaining buffer serialization bugs (#17182)
It may be more accurate to say: "Fix _known_ remaining buffer serialization bugs", but I'll try to be positive about my code. Initially, the buffer is initialized with the default attributes, but once it begins to scroll, newly scrolled in rows are initialized with the current attributes. This means we need to set the current attributes to those of the upcoming row before the row comes up. This is related to #17074. ## Validation Steps Performed * Persist and restore a buffer 10 times * All previous "Restore" status messages look correct ✅ * The escape sequences in the buffer file look correct ✅
This commit is contained in:
parent
c52dca40d2
commit
d4faf98455
@ -2559,6 +2559,7 @@ void TextBuffer::Serialize(const wchar_t* destination) const
|
|||||||
TextColor previousBg;
|
TextColor previousBg;
|
||||||
TextColor previousUl;
|
TextColor previousUl;
|
||||||
uint16_t previousHyperlinkId = 0;
|
uint16_t previousHyperlinkId = 0;
|
||||||
|
bool delayedLineBreak = false;
|
||||||
|
|
||||||
// This iterates through each row. The exit condition is at the end
|
// This iterates through each row. The exit condition is at the end
|
||||||
// of the for() loop so that we can properly handle file flushing.
|
// of the for() loop so that we can properly handle file flushing.
|
||||||
@ -2578,9 +2579,11 @@ void TextBuffer::Serialize(const wchar_t* destination) const
|
|||||||
}
|
}
|
||||||
|
|
||||||
const auto& runs = row.Attributes().runs();
|
const auto& runs = row.Attributes().runs();
|
||||||
auto it = runs.begin();
|
const auto beg = runs.begin();
|
||||||
const auto end = runs.end();
|
const auto end = runs.end();
|
||||||
|
auto it = beg;
|
||||||
const auto last = end - 1;
|
const auto last = end - 1;
|
||||||
|
const auto lastCharX = row.MeasureRight();
|
||||||
til::CoordType oldX = 0;
|
til::CoordType oldX = 0;
|
||||||
|
|
||||||
for (; it != end; ++it)
|
for (; it != end; ++it)
|
||||||
@ -2760,24 +2763,55 @@ void TextBuffer::Serialize(const wchar_t* destination) const
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
auto newX = oldX + it->length;
|
// Initially, the buffer is initialized with the default attributes, but once it begins to scroll,
|
||||||
// Trim whitespace with default attributes from the end of each line.
|
// newly scrolled in rows are initialized with the current attributes. This means we need to set
|
||||||
if (it == last && it->value == TextAttribute{})
|
// the current attributes to those of the upcoming row before the row comes up. Or inversely:
|
||||||
|
// We let the row come up, let it set its attributes and only then print the newline.
|
||||||
|
if (delayedLineBreak)
|
||||||
{
|
{
|
||||||
// This can result in oldX > newX, but that's okay because GetText()
|
buffer.append(L"\r\n");
|
||||||
// is robust against that and returns an empty string.
|
delayedLineBreak = false;
|
||||||
newX = row.MeasureRight();
|
}
|
||||||
|
|
||||||
|
auto newX = oldX + it->length;
|
||||||
|
|
||||||
|
// Since our text buffer doesn't store the original input text, the information over the amount of trailing
|
||||||
|
// whitespaces was lost. If we don't do anything here then a row that just says "Hello" would be serialized
|
||||||
|
// to "Hello ...". If the user restores the buffer dump with a different window size,
|
||||||
|
// this would result in some fairly ugly reflow. This code attempts to at least trim trailing whitespaces.
|
||||||
|
//
|
||||||
|
// As mentioned above for `delayedLineBreak`, rows are initialized with their first attribute, BUT
|
||||||
|
// only if the viewport has begun to scroll. Otherwise, they're initialized with the default attributes.
|
||||||
|
// In other words, we can only skip \x1b[K = Erase in Line, if both the first/last attribute are the default attribute.
|
||||||
|
static constexpr TextAttribute defaultAttr;
|
||||||
|
const auto trimTrailingWhitespaces = it == last && lastCharX < newX;
|
||||||
|
const auto clearToEndOfLine = trimTrailingWhitespaces && beg->value != defaultAttr || beg->value != defaultAttr;
|
||||||
|
|
||||||
|
if (trimTrailingWhitespaces)
|
||||||
|
{
|
||||||
|
newX = lastCharX;
|
||||||
}
|
}
|
||||||
|
|
||||||
buffer.append(row.GetText(oldX, newX));
|
buffer.append(row.GetText(oldX, newX));
|
||||||
|
|
||||||
|
if (clearToEndOfLine)
|
||||||
|
{
|
||||||
|
buffer.append(L"\x1b[K");
|
||||||
|
}
|
||||||
|
|
||||||
oldX = newX;
|
oldX = newX;
|
||||||
}
|
}
|
||||||
|
|
||||||
const auto moreRowsRemaining = currentRow < lastRowWithText;
|
const auto moreRowsRemaining = currentRow < lastRowWithText;
|
||||||
|
delayedLineBreak = !row.WasWrapForced();
|
||||||
|
|
||||||
if (!row.WasWrapForced() || !moreRowsRemaining)
|
if (!moreRowsRemaining)
|
||||||
{
|
{
|
||||||
buffer.append(L"\r\n");
|
if (previousHyperlinkId)
|
||||||
|
{
|
||||||
|
buffer.append(L"\x1b]8;;\x1b\\");
|
||||||
|
}
|
||||||
|
buffer.append(L"\x1b[m\r\n");
|
||||||
}
|
}
|
||||||
|
|
||||||
if (buffer.size() >= writeThreshold || !moreRowsRemaining)
|
if (buffer.size() >= writeThreshold || !moreRowsRemaining)
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user