runtime: Console.Clear() doesn't clear the scrollback buffer on Unix-like platforms
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.
About this issue
- Original URL
- State: closed
- Created 5 years ago
- Reactions: 4
- Comments: 41 (28 by maintainers)
I don’t have a specific scenario in mind, but from researching this a while back, it seems like quite a few people are interested in clearing the buffer as well. Whether that is programmatically or interactively isn’t clear (no pun intended) though.
On Windows, there’s no need as the existing parameterless overload already does clear the buffer. But that overload isn’t consistent across platforms. If you want to to be consistent, call the overload with either
true
orfalse
and it’ll work the same cross-platform 😊That’s the only way I can see this working out and not break everyone relying on the existing behavior.
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.
@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.
I think something like the above is a good solution. (
OperatingSystem.IsMacOS() && !OperatingSystem.IsMacOSVersionAtLeast(14)
seems better suited though)Note that with https://github.com/dotnet/roslyn/pull/70497, we should be able to even write
\e[3J
with C# next 😃If it concerns you that it might print something random out after it @adamsitnik, you could also re-append
TermInfo.WellKnownStrings.Clear
(or something similar) to it again to ensure that a clear goes through for this workaround - it seems to me like this should work well in most cases.Ie, you could write:
(note: I’ve not tested the above actually does what it’s intended to)
I can make a PR for it if you’d like @adamsitnik
How is it “of course” if it’s not in the code you showed.
Edit: I don’t know why you’re downvoting all my comments for trying to determine if this bug is fixed or not. It wasn’t “of course” because your code didn’t show it, I never said anything else had an issue, other than my personal doubt that it’s fixed (because it’s been a bug for years), I simply asked if you checked it since it wasn’t in the code (therefore I assumed you hadn’t checked it - why do you think I asked). I then pointed out it wasn’t “of course”, since it wasn’t as I just explained.
@adamsitnik It did not fix MacOS.
Assigned.
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? 😃
The point of the way I suggested doing it is assuming that they don’t all support it. That’s why I suggested a normal clear after. Would that not work?
@adamsitnik: Given @hamarb123’s summary above, there’s a pragmatic solution:
Instead of:
https://github.com/dotnet/runtime/blob/fd4621c11168ab9c21450f3c764fb46fe9aa8d29/src/libraries/System.Console/src/System/TerminalFormatStrings.cs#L77-L80
use:
Windows is not affected, and I’m not aware of issues on Linux distros, so this should be the only workaround required.
Once .NET no longer supports macOS 13 and below, this workaround can be removed.
Can confirm the following for Terminal.app:
We should fix this since macOS 10.15+ is supported for .NET 8.
Did you try printing a bunch of lines first, instead of immediately clearing @kasperk81 ? I’ve not tested it with the fix yet, but plan to tomorrow when 8.0 releases (but I’m not convinced it will work for macOS until I test it myself).
Good points, @khellang.
When implementing a shell or REPL the feature is of particular interest: often you want to start with a clean slate in a terminal before submitting a new command, so as not to get confused between the most recent command’s output and unrelated output that preceded it.
Indeed, it was the desire for consistent cross-platform behavior of PowerShell’s
Clear-Host
command that brought us here - https://github.com/PowerShell/PowerShell/issues/8606While PowerShell could certainly implement the behavior without using
Console.Clear()
, I can see other shells / REPLs benefitting from support in the CLR too - and indeed any type of application looking for consistent cross-platform behavior, notably including applications that on Windows do not want to clear the scrollback buffer.As for native shell / utility behavior:
On Windows, users of
cmd.exe
(cls
) and PowerShell (Clear-Host
, aliased tocls
) are used to the scrollback-buffer getting cleared, by default and invariably - though, as stated, Windows Terminal will change that experience.On Linux,
/usr/bin/clear
is meant to clear the scrollback buffer by default - but still doesn’t, as of Ubuntu 18.04, due to the terminal-capabilities database still not having been updated - see https://unix.stackexchange.com/a/375784/54804. Option-x
is the opt-out that clears the current screen only.On macOS,
/usr/bin/clear
was only ever designed to clear the current screen, but the default terminal offers keyboard shortcut <kbd>Command-K</kbd> to clear the scrollback buffer too.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).
Sounds reasonable.