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

Console.Clear() doesn't clear the scrollback buffer on Unix-like platforms #34463

Open
mklement0 opened this Issue Jan 9, 2019 · 16 comments

Comments

Projects
None yet
5 participants
@mklement0
Copy link
Collaborator

mklement0 commented Jan 9, 2019

Console.Clear()'s documentation states (emphasis added):

Clears the console buffer and corresponding console window of display information.

Indeed, not just clearing the current terminal window (screen), but also the scrollback buffer is the typical use case, and it is how this method has always worked on Windows.[1]

By contrast, the Unix implementation currently only clears the screen, which makes for an inconsistent cross-platform experience.

While there is no POSIX-compliant way to clear the scrollback buffer (only clearing the screen is mandated by POSIX, via tput clear), xterm-compatible terminal applications do support escape sequence <esc>[3J - see Wikipedia.

In practice, the macOS terminal application and the one on Ubuntu, for instance, do support this escape sequence - generally, terminal emulators based on the X Window System.

I don't know if there are popular terminal emulators out there that do not support it, but even a best-effort implementation would be useful.

Here's a workaround that demonstrates use of the escape sequence:

// Clears the screen and the scrollback buffer in xterm-compatible terminals.
Console.Clear(); Console.WriteLine("\x1b[3J")

[1] Whether there should be an opt-in for predictably clearing only the screen across platforms, while leaving the scrollback buffer intact, is a separate question.

@SteveL-MSFT

This comment has been minimized.

Copy link
Contributor

SteveL-MSFT commented Jan 9, 2019

Perhaps adding an overload with a bool includeScrollBackBuffer would retain current behavior and allow for the desired behavior

@mklement0

This comment has been minimized.

Copy link
Collaborator

mklement0 commented Jan 9, 2019

@SteveL-MSFT: Given that (a) clearing the buffer is documented and (b) doing so is generally the more sensible behavior, my vote is to simply change the existing behavior to align with the documentation / the behavior on Windows.

@danmosemsft

This comment has been minimized.

Copy link
Member

danmosemsft commented Jan 9, 2019

@stephentoub do you recall whether this was intentional, to not attempt to clear scrollback if supported?

@stephentoub

This comment has been minimized.

Copy link
Member

stephentoub commented Jan 9, 2019

do you recall whether this was intentional, to not attempt to clear scrollback if supported?

Not clearing it was not a goal. If there's a "safe" way to do it whenever it's possible (by safe I mean not emitting garbage to stdout when the particular escape code isn't supported by the terminal in use), such as relying on some reliable way to query that a compatible terminal is being used, I'm fine with doing so.

@mklement0

This comment has been minimized.

Copy link
Collaborator

mklement0 commented Jan 9, 2019

Thanks, @stephentoub.

relying on some reliable way to query that a compatible terminal is being used

Based on the answers posted at https://unix.stackexchange.com/q/93376/54804, this should be as simple as:

# ... perform screen clearing (as before)
# In compatible terminals, also clear the scrollback buffer.
if (Environment.GetEnvironmentVariable("TERM").StartsWith("xterm")) Console.WriteLine("\x1b[3J");

xterm-compatible terminal emulators set env. var. TERM either to xterm or xterm-<colorCountSpec>, e.g., xterm-256color.

@stephentoub

This comment has been minimized.

Copy link
Member

stephentoub commented Jan 9, 2019

And presumably if we did that first and then did the current clear (rather than the opposite order), if we did end up for some reason generating garbage, it'd be mitigated by being immediately cleared? :)

@mklement0

This comment has been minimized.

Copy link
Collaborator

mklement0 commented Jan 10, 2019

Exemplary garbage disposal, @stephentoub :)

@danmosemsft

This comment has been minimized.

Copy link
Member

danmosemsft commented Jan 10, 2019

@mklement0 do you wish to offer a PR?

@khellang

This comment has been minimized.

Copy link
Collaborator

khellang commented Jan 10, 2019

You should be able to query the terminfo db for the E3 extension, no?

See user_caps(5) under "Recognized capabilities":

E3 string, tells how to clear the terminal's scrollback buffer.

When present, the clear(1) program sends this before clearing the terminal.

The command "tput clear" does the same thing.

@mklement0

This comment has been minimized.

Copy link
Collaborator

mklement0 commented Jan 10, 2019

Thanks, @khellang, but in practice neither clear nor tput clear clear the scrollback buffer on macOS 10.14 and Ubuntu 18.04.

Consistent with that, the requisite escape sequence, \E[3J, is not present in the output from infocmp when invoked from an xterm-compatible terminal.

I know little about terminal-info databases, so maybe I'm missing something.

@danmosemsft: I'll give it a shot.

@khellang

This comment has been minimized.

Copy link
Collaborator

khellang commented Jan 10, 2019

Interesting Linux SE answer; https://unix.stackexchange.com/a/375784.

@danmosemsft

This comment has been minimized.

Copy link
Member

danmosemsft commented Jan 10, 2019

@mklement0 sounds good. I sent you a collaborator invite: it's optional, if you accept it I can formally assign you. Note that accepting it switches on notifications for all of the repo, which you'll likely want to switch off again.

@mklement0

This comment has been minimized.

Copy link
Collaborator

mklement0 commented Jan 11, 2019

Thanks, @danmosemsft; I've accepted the invitation.

@danmosemsft

This comment has been minimized.

Copy link
Member

danmosemsft commented Jan 11, 2019

Assigned.

@mklement0

This comment has been minimized.

Copy link
Collaborator

mklement0 commented Jan 13, 2019

Thanks, @khellang; specifically, the passage of interest on the linked page is the following from this answer:

The gnome terminfo entry does not define an E3 capability, and on many systems — still! — neither does the xterm entry as this has not percolated down from Dickey terminfo. So clear just writes out the contents of the clear capability.

It sounds like the right thing to do is:

  • (a) query the E3 capability in the terminfo database (based on env. var. TERM) and use the corresponding escape sequence, if defined.

  • (b) if not defined, and TERM is xterm or starts with xterm- (matches ^xterm(?:-|$)), hard-code "\x1b[3J".

If performance is a concern, we could do (b) first, but I presume it won't matter.

@stephentoub

This comment has been minimized.

Copy link
Member

stephentoub commented Jan 13, 2019

If performance is a concern

It shouldn't be. The terminal doesn't change, so what to output for a Clear can be cached (it already is in many cases).

It sounds like the right thing to do is

Sounds reasonable.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment