Skip to content

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

Open
wants to merge 5 commits into
base: main
Choose a base branch
from

Conversation

lhecker
Copy link
Member

@lhecker lhecker commented May 28, 2025

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

  • Launch ConsoleMonitor.exe
  • Create some text above & below the cursor in PowerShell
  • Clear Buffer
  • Buffer is cleared except for the cursor row ✅
  • ...same in ConPTY ✅

Copy link
Member

@carlos-zamora carlos-zamora left a 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.
Copy link
Member

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

Copy link
Member Author

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.

@DHowett
Copy link
Member

DHowett commented May 28, 2025

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())
Copy link
Collaborator

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.

Copy link
Collaborator

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)
Copy link
Collaborator

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);
Copy link
Collaborator

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.

Copy link
Member Author

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.

Copy link
Collaborator

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.

Copy link
Member

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. ☹

Copy link
Member Author

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.

@microsoft-github-policy-service microsoft-github-policy-service bot added the Needs-Author-Feedback The original author of the issue/PR needs to come back and respond to something label May 30, 2025
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.

James! Excellent catch!

@microsoft-github-policy-service microsoft-github-policy-service bot added the No-Recent-Activity This issue/PR is going stale and may be auto-closed without further activity. label Jun 6, 2025
@carlos-zamora carlos-zamora removed the No-Recent-Activity This issue/PR is going stale and may be auto-closed without further activity. label Jun 13, 2025
@carlos-zamora carlos-zamora reopened this Jun 13, 2025
@lhecker lhecker requested a review from DHowett June 17, 2025 15:49
@microsoft-github-policy-service microsoft-github-policy-service bot removed the Needs-Author-Feedback The original author of the issue/PR needs to come back and respond to something label Jun 17, 2025
@DHowett
Copy link
Member

DHowett commented Jun 17, 2025

Still broke during tests (and now audit! may need to merge main)

@DHowett
Copy link
Member

DHowett commented Jun 17, 2025

oh you merged main. alas

@DHowett
Copy link
Member

DHowett commented Jun 17, 2025

PowerShell and CMD both resume writing input at the old cursor position after we clear the buffer this way:

image

@DHowett
Copy link
Member

DHowett commented Jun 17, 2025

Clearing the buffer this way after the viewport scrolls down results in a loss of the prompt:

WindowsTerminal_NcoNMNUI7c

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.

noted

@microsoft-github-policy-service microsoft-github-policy-service bot added the Needs-Author-Feedback The original author of the issue/PR needs to come back and respond to something label Jun 17, 2025
@lhecker
Copy link
Member Author

lhecker commented Jun 17, 2025

Right, forgot about the tests.

PowerShell and CMD both resume writing input at the old cursor position after we clear the buffer this way:

That's already the case before this PR, though.

@microsoft-github-policy-service microsoft-github-policy-service bot added Needs-Attention The core contributors need to come back around and look at this ASAP. and removed Needs-Author-Feedback The original author of the issue/PR needs to come back and respond to something labels Jun 17, 2025
@DHowett
Copy link
Member

DHowett commented Jun 17, 2025

That's already the case before this PR, though.

Huh. Was it the case before 1.22/the conPTY rewrite?

@lhecker
Copy link
Member Author

lhecker commented Jun 17, 2025

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 TextBuffer. PowerShell 5 is broken in 1.21 too, though.

@lhecker
Copy link
Member Author

lhecker commented Jun 18, 2025

/azp run

Copy link

Azure Pipelines successfully started running 1 pipeline(s).

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Needs-Attention The core contributors need to come back around and look at this ASAP.
Projects
Status: To Cherry Pick
Status: To Cherry Pick
Development

Successfully merging this pull request may close these issues.

Clear buffer: option to clear up to the current cursor line Clear buffer clears the prompt
4 participants