Skip to content

Manually copy trailing attributes on a resize#12637

Merged
25 commits merged intomainfrom
dev/migrie/b/32-attempt-2
Mar 21, 2022
Merged

Manually copy trailing attributes on a resize#12637
25 commits merged intomainfrom
dev/migrie/b/32-attempt-2

Conversation

@zadjii-msft
Copy link
Member

@zadjii-msft zadjii-msft commented Mar 7, 2022

THE WHITE WHALE

This is a fairly naive fix for this bug. It's not terribly performant,
but neither is resize in the first place.

When the buffer gets resized, typically we only copy the text up to the
MeasureRight point, the last printable char in the row. Then we'd just
use the last char's attributes to fill the remainder of the row.

Instead, this PR changes how reflow behaves when it gets to the end of
the row. After we finish copying text, then manually walk through the
attributes at the end of the row, and copy them over. This ensures that
cells that just have a colored space in them get copied into the new
buffer as well, and we don't just blat the last character's attributes
into the rest of the row. We'll do a similar thing once we get to the
last printable char in the buffer, copying the remaining attributes.

This could DEFINITELY be more performant. I think this current
implementation walks the attrs on every cell, then appends the new
attrs to the new ATTR_ROW. That could be optimized by just using the
actual iterator. The copy after the last printable char bit is also
especially bad in this regard. That could likely be a blind copy - I
just wanted to get this into the world.

Finally, we now copy the final attributes to the correct buffer: the new
one. We used to copy them to the old buffer, which we were about to
destroy.

Validation

I'll add more gifs in the morning, not enough time to finish spinning a
release Terminal build with this tonight.

Closes #32 🎉🎉🎉🎉🎉🎉🎉🎉🎉
Closes #12567

@ghost ghost added Area-Output Related to output processing (inserting text into buffer, retrieving buffer text, etc.) Area-Rendering Text rendering, emoji, complex glyph & font-fallback issues Impact-Visual It look bad. Issue-Bug It either shouldn't be doing this or needs an investigation. Priority-1 A description (P1) Priority-3 A description (P3) Product-Conhost For issues in the Console codebase labels Mar 7, 2022
@github-actions

This comment was marked as resolved.

@DHowett
Copy link
Member

DHowett commented Mar 9, 2022

What if we resize down to the righthand edge of a color and then back to the left. Does it expand that color to the edge forever?

@zadjii-msft
Copy link
Member Author

What if we resize down to the righthand edge of a color and then back to the left. Does it expand that color to the edge forever?

Yea, that does. So that's the same as it was before:
gh-32-last-color-expands-000

That could probably be fixed by the proposed "'bookend' with default attrs at the end of the attrs from the pre-resize buffer" idea, which I haven't tested. In that case, resizing down to the white w above would work as expected, then resizing back out would have default attrs.

@j4james
Copy link
Collaborator

j4james commented Mar 10, 2022

I think I quite like it the way you have it now actually. This way if you've cleared the screen with a different background color, it should retain that color for the full width when you resize (or so I assume). But I don't think the default bookend idea would be bad either - both have their pros and cons.

It's also worth noting that Gnome Terminal seems to treat cells with non-default attributes as wrappable content (even when they're just spaces). But that behaves quite weirdly when you've cleared the screen with a non-default color. I'm not a fan of that approach myself, but I don't think it's unreasonable either.

@lhecker
Copy link
Member

lhecker commented Mar 10, 2022

BTW regarding performance: This PR increases the CPU cost of TextBuffer::Reflow by about 18% if my 120x9001 buffer is full with enwik8. About half of the cost is due to InsertCharacter however, which is a bit silly anyways and can be improved by doing batch-insertions. I'm not concerned about this change from that POV.

@DHowett
Copy link
Member

DHowett commented Mar 10, 2022

@msftbot make sure @miniksa signs off

@ghost ghost added the AutoMerge Marked for automatic merge by the bot when requirements are met label Mar 10, 2022
@ghost
Copy link

ghost commented Mar 10, 2022

Hello @DHowett!

Because you've given me some instructions on how to help merge this pull request, I'll be modifying my merge approach. Here's how I understand your requirements for merging this pull request:

  • I'll only merge this pull request if it's approved by @miniksa

If this doesn't seem right to you, you can tell me to cancel these instructions and use the auto-merge policy that has been configured for this repository. Try telling me "forget everything I just told you".

@DHowett
Copy link
Member

DHowett commented Mar 10, 2022

That could be optimized by just using the actual iterator.

How expensive would you estimate doing it this way would be? Code-time-wise?

@zadjii-msft
Copy link
Member Author

How expensive would you estimate doing it this way would be? Code-time-wise?

I could probably spend half a day sanity checking if that would take half a day or many days and bail if it's too hard. After {the esb bug, the nav view one, the win11 backports, the ppt} in the queue.

@zadjii-msft
Copy link
Member Author

How expensive would you estimate doing it this way would be? Code-time-wise?

I could probably spend half a day sanity checking if that would take half a day or many days and bail if it's too hard.

I did this - thank you for bringing 61b0697 into my life. That's so so SO much faster.

Copy link
Member

@DHowett DHowett left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'll unmark after some questions :)

const auto glyph = row.GetCharRow().GlyphAt(iOldCol);
const auto dbcsAttr = row.GetCharRow().DbcsAttrAt(iOldCol);
const auto textAttr = row.GetAttrRow().GetAttrByColumn(iOldCol);
const auto glyph = chars->Char();
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hopefully this doesn't cause any trouble with DBCS. It might be worth just smoke testing that -- fill a buffer with U+30AB KATAKANA LETTER KA (カ) and size it around to make sure it reflows properly.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

gh-12637-dbcs

if (iRight < cOldColsTotal && !row.WasWrapForced())
{
if (iRight == cOldCursorPos.X && iOldRow == cOldCursorPos.Y)
if (!fFoundCursorPos && (iRight == cOldCursorPos.X && iOldRow == cOldCursorPos.Y))
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Unrelated condition change -- scary? I guess as long as the reflow tests still pass...

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It actually did end up being related. Because we're now also copying the trailing attrs, there was a case where we'd copy the attrs to the end of the row, but then set the new cursor position to the last column of the row the cursor was on.

(it may not be relevant anymore, but it's not more wrong.)


// Finish copying buffer attributes to remaining rows below the last
// printable character. This is to fix the `color 2f` scenario, where you
// change the buffer colors then resize and everything below the past
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
// change the buffer colors then resize and everything below the past
// change the buffer colors then resize and everything below the last

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

this comment suggests we'll have to inbox this change to fix COLOR

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

yea, we would.

{
auto iter = TestUtils::VerifyLineContains(tb, { 0, row }, L'#', greenAttrs, 1u);
TestUtils::VerifyLineContains(iter, L' ', (afterResize ? greenAttrs : actualDefaultAttrs), static_cast<size_t>(width - 1));
TestUtils::VerifyLineContains(iter, L' ', (actualDefaultAttrs), static_cast<size_t>(width - 1));
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Confirming: this test was coded around the bad behavior, right?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yea.

LOG_IF_FAILED(SetViewportOrigin(false, coordCursorHeightDiff, true));

_textBuffer->SetCurrentAttributes(oldPrimaryAttributes);
newTextBuffer->SetCurrentAttributes(oldPrimaryAttributes);
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

HUH. This seems like an unrelated but important bug fix

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

yea this was mentioned here: #12567 (comment) and in the previous reply

// there are also 3 B's wrapped in spaces, and finally 5 trailing spaces.
Log::Comment(L"========== Checking the buffer state (after) ==========");
verifyBuffer(si.GetTextBuffer(), til::rect{ si.GetViewport().ToInclusive() }, false);
}
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Do we need a test for the "copied the attributes after the last printable character" case?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

meh, I could write one

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'll sign, but I would like to see that ^

@ghost ghost added Needs-Author-Feedback The original author of the issue/PR needs to come back and respond to something and removed Needs-Author-Feedback The original author of the issue/PR needs to come back and respond to something labels Mar 16, 2022
@DHowett
Copy link
Member

DHowett commented Mar 17, 2022

Test harness is crashing -- not sure if it is this PR's fault

Error: TAEF: [HRESULT 0x800706BE] A failure occurred while running a test operation: 'SelectionInputTests::ClassSetup'. (The process hosting the test code was unexpectedly terminated with exit code 0x0000DEAD while invoking a test operation.)

@DHowett
Copy link
Member

DHowett commented Mar 18, 2022

Test failure is not from this PR, and is addressed in #17274

@miniksa
Copy link
Member

miniksa commented Mar 18, 2022

Fix the test, of course. But otherwise, I'm happy.

@DHowett
Copy link
Member

DHowett commented Mar 21, 2022

Image from PR body

gh-32-did-I-do-it

@DHowett DHowett added AutoMerge Marked for automatic merge by the bot when requirements are met and removed AutoMerge Marked for automatic merge by the bot when requirements are met labels Mar 21, 2022
@ghost
Copy link

ghost commented Mar 21, 2022

Hello @DHowett!

Because this pull request has the AutoMerge label, I will be glad to assist with helping to merge this pull request once all check-in policies pass.

p.s. you can customize the way I help with merging this pull request, such as holding this pull request until a specific person approves. Simply @mention me (@msftbot) and give me an instruction to get started! Learn more here.

@ghost ghost merged commit 855e136 into main Mar 21, 2022
@ghost ghost deleted the dev/migrie/b/32-attempt-2 branch March 21, 2022 17:02
DHowett pushed a commit that referenced this pull request Mar 28, 2022
## THE WHITE WHALE

This is a fairly naive fix for this bug. It's not terribly performant,
but neither is resize in the first place.

When the buffer gets resized, typically we only copy the text up to the
`MeasureRight` point, the last printable char in the row. Then we'd just
use the last char's attributes to fill the remainder of the row.

Instead, this PR changes how reflow behaves when it gets to the end of
the row. After we finish copying text, then manually walk through the
attributes at the end of the row, and copy them over. This ensures that
cells that just have a colored space in them get copied into the new
buffer as well, and we don't just blat the last character's attributes
into the rest of the row. We'll do a similar thing once we get to the
last printable char in the buffer, copying the remaining attributes.

This could DEFINITELY be more performant. I think this current
implementation walks the attrs _on every cell_, then appends the new
attrs to the new ATTR_ROW. That could be optimized by just using the
actual iterator. The copy after the last printable char bit is also
especially bad in this regard. That could likely be a blind copy - I
just wanted to get this into the world.

Finally, we now copy the final attributes to the correct buffer: the new
one.  We used to copy them to the _old_ buffer, which we were about to
destroy.

## Validation

I'll add more gifs in the morning, not enough time to finish spinning a
release Terminal build with this tonight.

Closes #32 🎉🎉🎉🎉🎉🎉🎉🎉🎉
Closes #12567

(cherry picked from commit 855e136)
DHowett pushed a commit that referenced this pull request Mar 28, 2022
## THE WHITE WHALE

This is a fairly naive fix for this bug. It's not terribly performant,
but neither is resize in the first place.

When the buffer gets resized, typically we only copy the text up to the
`MeasureRight` point, the last printable char in the row. Then we'd just
use the last char's attributes to fill the remainder of the row.

Instead, this PR changes how reflow behaves when it gets to the end of
the row. After we finish copying text, then manually walk through the
attributes at the end of the row, and copy them over. This ensures that
cells that just have a colored space in them get copied into the new
buffer as well, and we don't just blat the last character's attributes
into the rest of the row. We'll do a similar thing once we get to the
last printable char in the buffer, copying the remaining attributes.

This could DEFINITELY be more performant. I think this current
implementation walks the attrs _on every cell_, then appends the new
attrs to the new ATTR_ROW. That could be optimized by just using the
actual iterator. The copy after the last printable char bit is also
especially bad in this regard. That could likely be a blind copy - I
just wanted to get this into the world.

Finally, we now copy the final attributes to the correct buffer: the new
one.  We used to copy them to the _old_ buffer, which we were about to
destroy.

## Validation

I'll add more gifs in the morning, not enough time to finish spinning a
release Terminal build with this tonight.

Closes #32 🎉🎉🎉🎉🎉🎉🎉🎉🎉
Closes #12567

(cherry picked from commit 855e136)
@ghost
Copy link

ghost commented Apr 19, 2022

🎉Windows Terminal v1.12.1098 has been released which incorporates this pull request.:tada:

Handy links:

@ghost
Copy link

ghost commented Apr 19, 2022

🎉Windows Terminal Preview v1.13.1098 has been released which incorporates this pull request.:tada:

Handy links:

DHowett pushed a commit that referenced this pull request Jun 24, 2022
## THE WHITE WHALE

This is a fairly naive fix for this bug. It's not terribly performant,
but neither is resize in the first place.

When the buffer gets resized, typically we only copy the text up to the
`MeasureRight` point, the last printable char in the row. Then we'd just
use the last char's attributes to fill the remainder of the row.

Instead, this PR changes how reflow behaves when it gets to the end of
the row. After we finish copying text, then manually walk through the
attributes at the end of the row, and copy them over. This ensures that
cells that just have a colored space in them get copied into the new
buffer as well, and we don't just blat the last character's attributes
into the rest of the row. We'll do a similar thing once we get to the
last printable char in the buffer, copying the remaining attributes.

This could DEFINITELY be more performant. I think this current
implementation walks the attrs _on every cell_, then appends the new
attrs to the new ATTR_ROW. That could be optimized by just using the
actual iterator. The copy after the last printable char bit is also
especially bad in this regard. That could likely be a blind copy - I
just wanted to get this into the world.

Finally, we now copy the final attributes to the correct buffer: the new
one.  We used to copy them to the _old_ buffer, which we were about to
destroy.

## Validation

I'll add more gifs in the morning, not enough time to finish spinning a
release Terminal build with this tonight.

Closes #32 🎉🎉🎉🎉🎉🎉🎉🎉🎉
Closes #12567

(cherry picked from commit 855e136)
This pull request was closed.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Area-Output Related to output processing (inserting text into buffer, retrieving buffer text, etc.) Area-Rendering Text rendering, emoji, complex glyph & font-fallback issues AutoMerge Marked for automatic merge by the bot when requirements are met Impact-Visual It look bad. Issue-Bug It either shouldn't be doing this or needs an investigation. Priority-1 A description (P1) Priority-3 A description (P3) Product-Conhost For issues in the Console codebase

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Full-screen COLOR command no longer works right when resizing conhost and Terminal Console doesn't handle colored regions when reflowed

5 participants