-
Notifications
You must be signed in to change notification settings - Fork 4.9k
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 #28355
Comments
Perhaps adding an overload with a |
@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. |
@stephentoub 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. |
Thanks, @stephentoub.
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. |
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? :) |
Exemplary garbage disposal, @stephentoub :) |
@mklement0 do you wish to offer a PR? |
You should be able to query the terminfo db for the E3 extension, no? See user_caps(5) under "Recognized capabilities":
|
Thanks, @khellang, but in practice neither Consistent with that, the requisite escape sequence, I know little about terminal-info databases, so maybe I'm missing something. @danmosemsft: I'll give it a shot. |
Interesting Linux SE answer; https://unix.stackexchange.com/a/375784. |
@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. |
Thanks, @danmosemsft; I've accepted the invitation. |
Assigned. |
Thanks, @khellang; specifically, the passage of interest on the linked page is the following from this answer:
It sounds like the right thing to do is:
If performance is a concern, we could do (b) first, but I presume it won't matter. |
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. |
@mklement0 If you are still working this. like var clearString = TerminalFormatStrings.Instance.Clear;
if (clearString.Equal("\E[H\E[J - a standard value", StringComparison.Ordinal)
{
clearString = "\E3J" + clearString;
}
WriteStdoutAnsiString(clearString); |
@mkelement0 have you had a chance to continue looking into this? |
I understand that the planned change is going to align the behavior with Windows, however, I am not aware of any text mode application on Unix that would clear the scrollback buffer. I myself would consider such a behavior of any application intrusive and unexpected. What are scenarios when clearing the scrollback buffer is beneficial? |
My apologies for dropping the ball on this, @danmosemsft , @carlossanlop and @iSazonov - can you please unassign me? I hope someone else will take this on. However, it sounds like maybe there isn't consensus yet as to what to do: @janvorli, I can see how for programmatic (as opposed to interactive use in a shell) clearing the scrollback buffer by default could be considered too invasive. (On re-reading the documentation, it doesn't actually talk about the scrollback buffer, only about the "console buffer", which can justifiably be interpreted to mean the current screen only.) Even though also clearing the scroll-back buffer is how it has always worked in regular console windows on Windows, I now see that in Windows Terminal it does not. This takes us back to @SteveL-MSFT's suggestion to make buffer clearing an opt-in via a Boolean parameter. We could therefore:
|
To add a new API (rather than simply align behavior) we'd want a bit more evidence of need. What sort of scenario would lead someone to pass "true" ? |
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 That's the only way I can see this working out and not break everyone relying on the existing behavior. |
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 While PowerShell could certainly implement the behavior without using As for native shell / utility behavior:
|
|
If it is logically correct ("clear" doesn't mean "scroll" or "rewind") and doesn't require a galactic-scale efforts, why .Clear(true) could not be done? |
Hi, I've noticed this issue as well and developed a solution for my code on macOS: |
I'm new to this programming game as far as programming in C#. This was really frustrating me, and the last comment thank you. thank you. It was very annoying. This cleared the host completely now as opposed to just using Console.Clear() which appears to just clear the last buffer. |
The issue got fixed by #88487 and is included in .NET 8. |
@adamsitnik It did not fix MacOS.
|
are you sure? i tried 8.0-rtm with
it clears the scrollback buffer on mac terminal and prints out Hello, World! |
Did you try printing a bunch of lines first, instead of immediately clearing @kasperk81 ? |
of course i tested with overflown buffers and that's the difference between .net 8 vs 7 |
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. |
I just installed the officially released Repro code (reproduces the symptom on macOS 13.5.2): for (var i = 0; i < 500; ++i) { Console.WriteLine(i); };
Console.Write("Press a key to clear the terminal");
Console.ReadKey(true);
Console.Clear(); // Scroll back up afterwards - you'll see that the numbers are still there. By contrast, adding the escape sequence that clears the scrollback buffer shown in the initial post works, in both terminal applications: Console.Clear(); Console.WriteLine("\x1b[3J"); Shell alternatives: Note:
/usr/bin/clear; printf '\x1b[3J'
/usr/bin/clear; printf "`e[3J" |
i'm on 14 (sonoma) and i don't see the numbers afterwards |
Can confirm the following for Terminal.app:
We should fix this since macOS 10.15+ is supported for .NET 8. |
The referenced fix (#88487) checks the terminfo for an I would love to fix it for all terminals, but how can we do that reliably if they don't define this capability? Sharing https://unix.stackexchange.com/questions/375743/why-clear-do-not-clear-whole-screen/375784#375784 for reference. |
@adamsitnik: Given @hamarb123's summary above, there's a pragmatic solution: Instead of:
use: if (
(
RuntimeInformation.IsOSPlatform(OSPlatform.OSX) && Environment.OSVersion.Version.Major < 14 ?
"\x1b[3J"
:
db.GetExtendedString("E3")
) is string clearScrollbackBuffer
)
{
Clear += clearScrollbackBuffer; // the E3 command must come after the Clear command
} 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. |
I think something like the above is a good solution. ( Note that with dotnet/roslyn#70497, we should be able to even write If it concerns you that it might print something random out after it @adamsitnik, you could also re-append Ie, you could write: if (db.GetExtendedString("E3") is string clearScrollbackBuffer)
{
Clear += clearScrollbackBuffer; // the E3 command must come after the Clear command
}
else if (OperatingSystem.IsMacOS() && !OperatingSystem.IsMacOSVersionAtLeast(14))
{
Clear += "\e[3J" + db.GetString(TermInfo.WellKnownStrings.Clear); //use \e[3J to do a full clear on macOS terminal, and print the clear string again in case some terminal emulators don't understand this code to ensure we don't get random characters printed out
} (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 |
The solution that you suggested assumes that every Terminal that runs on macOS supports Don't get me wrong, I want to get all the bugs fixed. But in reliable way. My current best idea is to recognize the Terminals that support it, but don't define that in Terminfo. Similarly to what we do in:
But I doubt that such a fix would be approved for backporting to .NET 8 (unless we can guarantee that older versions of this Terminals support it). |
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? |
Console.Clear()
's documentation states (emphasis added):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:
[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.
The text was updated successfully, but these errors were encountered: