-
Notifications
You must be signed in to change notification settings - Fork 8.6k
Preserve the cursor row during Clear Buffer #18976
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
Conversation
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thanks for doing this! Love the comments too :)
I was surprised that ClearBufferType
isn't a flag enum, but changing that would be more trouble than it's worth tbh.
_terminal->Write(command); | ||
// In absolute buffer coordinates, including the scrollback (= Y is offset by the scrollback height). | ||
const auto viewport = _terminal->GetViewport(); | ||
// The absolute cursor coordinate. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
comment says "absolute" but method says "viewport relative" o_O
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Right, I changed the code and forgot to remove the comment.
wow, we actually have tests that this caused to fail! |
if (clearType == ClearBufferType::Screen || clearType == ClearBufferType::All) | ||
{ | ||
// Erase any viewport contents below (but not including) the cursor row. | ||
if (cursor.x < viewport.Height()) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This should assumedly be cursor.y
. Also I think it's off by one, so actually cursor.y + 1
.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
There's still an off-by-one error here. You can see that by doing a directory listing or something so that the prompt ends up on the last line of the screen, then try clearing the buffer. Note that it hasn't preserved the prompt line.
} | ||
|
||
// Erase any viewport contents above (but not including) the cursor row. | ||
if (cursor.x > 0) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
As above, should be cursor.y
.
// Erase any viewport contents above (but not including) the cursor row. | ||
if (cursor.x > 0) | ||
{ | ||
fmt::format_to(std::back_inserter(sequence), FMT_COMPILE(L"\x1b[{}S\x1b[1;{}H"), cursor.y, cursor.x + 1); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This is not super important, but I'd prefer we didn't use an SU
sequence here, because it's not standard (in the way modern terminals implement it). We should ideally be using a DL
sequence, so something like \x1b[H\x1b[{}M
in place of the \x1b[{}S
.
Also, and this is important, that final cursor positioning sequence should be applied outside the if, because it's required for both branches. If you're on the top line of the page, you're going to erase below, and not above, but you'll still need to reposition the cursor.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thank you for your review! Sorry that it took so long. It should be fixed now.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The cursor repositioning still needs to be moved out so it applies to both branches. You can see the problem by clearing the buffer once, so the prompt ends up on the first line of the display, then immediately clear the buffer again. Note that cursor now ends up underneath the prompt.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This is not super important, but I'd prefer we didn't use an
SU
sequence here, because it's not standard (in the way modern terminals implement it).
Reflecting on this a little bit.
The API between ControlCore
and its Terminal
member using VT at all is more of an implementation detail. VT emitted here never escapes out of conhost or out of terminal into another application.
In truth, I think that means SU
is fine?
But also it means that we're using stringly typed magic between two components statically linked into the same executable image. ☹
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I did consider moving the scroll logic to TextBuffer
to make this possible, but it's currently fairly tightly ingrained with the VT implementation. IMO we first need to clean up the API between the VT and buffer layers. They're currently too low level (and too low performance). With faster, high-level functions we can probably make everything a lot easier and cleaner. Most notably, a "copy rectangle" function is missing in TextBuffer
.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
James! Excellent catch!
Still broke during tests (and now audit! may need to merge main) |
oh you merged main. alas |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
noted
Right, forgot about the tests.
That's already the case before this PR, though. |
Huh. Was it the case before 1.22/the conPTY rewrite? |
No, I mean just before this PR, on main. It did work in 1.21 because the CMD prompt relied heavily on the conhost |
/azp run |
Azure Pipelines successfully started running 1 pipeline(s). |
Introduces an ABI change to the ConptyClearPseudoConsole signal.
Otherwise, we have to make it so that the API call always retains
the row the cursor is on, but I feel like that makes it worse.
Closes #18732
Closes #18878
Validation Steps Performed
ConsoleMonitor.exe