Use E3 to completely clear console on Unix when possible#88487
Use E3 to completely clear console on Unix when possible#88487adamsitnik merged 3 commits intodotnet:mainfrom natehitze:issue-84351
Conversation
Some terminals define an extra sequence to clear the terminal scroll buffer. Using it after the clear sequence makes Clear() work like the 'clear' command. Fix #84351
|
Tagging subscribers to this area: @dotnet/area-system-console Issue DetailsSome terminals define an extra sequence to clear the terminal scroll buffer. Using it after the clear sequence makes Clear() work like the 'clear' command. Fix #84351 The linked issue has a detailed analysis and explanation which was the guide for this PR.
|
|
@dotnet-policy-bot agree |
adamsitnik
left a comment
There was a problem hiding this comment.
@natehitze big thanks for your contribution! PTAL at my comments, we need to solve the macOS CI failure.
| [InlineData("mach-color", "\u001B\u005B\u00335m", "\u001B\u005B\u00345m", 5)] | ||
| [InlineData("mach-color", "\u001B\u005B\u003312m", "\u001B\u005B\u003412m", 12)] | ||
| public void TermInfoVerification(string termToTest, string expectedForeground, string expectedBackground, int colorValue) | ||
| [InlineData("xterm-256color", "\u001B\u005B\u00330m", "\u001B\u005B\u00340m", 0, true)] |
There was a problem hiding this comment.
the test failures indicate that E3 is missing on xterm-256color, but only macOS. I wonder why: does macOS simply not provide it or it has a different name?
Please let me know if you need a copy of macOS terminfo file.
/private/tmp/helix/working/AFB20920/w/BFE50A43/e /private/tmp/helix/working/AFB20920/w/BFE50A43/e
Discovering: System.Console.Tests (method display = ClassAndMethod, method display options = None)
Discovered: System.Console.Tests (found 113 of 148 test cases)
Starting: System.Console.Tests (parallel test collections = on, max threads = 4)
Color.RedirectedOutput_EnvVarSet_EmitsAnsiCodes [SKIP]
Condition(s) not met: "TermIsSetAndRemoteExecutorIsSupported"
0
0
TermInfoTests.TermInfoVerification(termToTest: "xterm-256color", expectedForeground: "\x1b[30m", expectedBackground: "\x1b[40m", colorValue: 0, expectedScrollbackClearSupport: True) [FAIL]
Assert.Equal() Failure
Expected: True
Actual: False
Stack Trace:
/_/src/libraries/System.Console/tests/TermInfo.Unix.cs(102,0): at TermInfoTests.TermInfoVerification(String termToTest, String expectedForeground, String expectedBackground, Int32 colorValue, Boolean expectedScrollbackClearSupport)
at System.RuntimeMethodHandle.InvokeMethod(Object target, Void** arguments, Signature sig, Boolean isConstructor)
/_/src/libraries/System.Private.CoreLib/src/System/Reflection/MethodInvoker.cs(59,0): at System.Reflection.MethodInvoker.Invoke(Object obj, IntPtr* args, BindingFlags invokeAttr)
TermInfoTests.TermInfoVerification(termToTest: "xterm-256color", expectedForeground: "\x1b[31m", expectedBackground: "\x1b[41m", colorValue: 1, expectedScrollbackClearSupport: True) [FAIL]
Assert.Equal() Failure
Expected: True
Actual: False
Stack Trace:
/_/src/libraries/System.Console/tests/TermInfo.Unix.cs(102,0): at TermInfoTests.TermInfoVerification(String termToTest, String expectedForeground, String expectedBackground, Int32 colorValue, Boolean expectedScrollbackClearSupport)
at InvokeStub_TermInfoTests.TermInfoVerification(Object, Object, IntPtr*)
at System.Reflection.MethodInvoker.Invoke(Object obj, IntPtr* args, BindingFlags invokeAttr)
TermInfoTests.TermInfoVerification(termToTest: "xterm-256color", expectedForeground: "\x1b[90m", expectedBackground: "\x1b[100m", colorValue: 8, expectedScrollbackClearSupport: True) [FAIL]
Assert.Equal() Failure
Expected: True
Actual: False
Stack Trace:
/_/src/libraries/System.Console/tests/TermInfo.Unix.cs(102,0): at TermInfoTests.TermInfoVerification(String termToTest, String expectedForeground, String expectedBackground, Int32 colorValue, Boolean expectedScrollbackClearSupport)
at InvokeStub_TermInfoTests.TermInfoVerification(Object, Object, IntPtr*)
at System.Reflection.MethodInvoker.Invoke(Object obj, IntPtr* args, BindingFlags invokeAttr)
Finished: System.Console.Tests
There was a problem hiding this comment.
According to https://github.com/watchexec/clearscreen/blob/main/TERMINALS.md#platforms macOS doesn't include E3 in terminfo. That seems to be true on the mac I have access to -- and the clear command with xterm-256color does not clear the scrollback buffer but does clear it on my machine (PopOS 22.04) with xterm-256color.
I'll take a look at the Console.ReadKey tests you mentioned below and get the tests fixed up for CI. Thanks for reviewing!
| [InlineData("wsvt25", "\u001B\u005B\u003311m", "\u001B\u005B\u003411m", 11, false)] | ||
| [InlineData("mach-color", "\u001B\u005B\u00330m", "\u001B\u005B\u00340m", 0, false)] | ||
| [InlineData("mach-color", "\u001B\u005B\u00335m", "\u001B\u005B\u00345m", 5, false)] | ||
| [InlineData("mach-color", "\u001B\u005B\u003312m", "\u001B\u005B\u003412m", 12, false)] |
There was a problem hiding this comment.
it's a pity that it's not supported by more terminals. FWIW we have Console.ReadKey tests that have copies of terminfo files for multiple terminals:
runtime/src/libraries/System.Console/tests/KeyParserTests.cs
Lines 16 to 26 in 104752a
if you want to check anything related to this terminals you can just hack these tests, the TermInfo.Database is created here:
runtime/src/libraries/System.Console/tests/KeyParserTests.cs
Lines 431 to 432 in 104752a
You can even debug that on Windows, as these tests are platform-independent.
| if (!Console.IsOutputRedirected) | ||
| { | ||
| WriteStdoutAnsiString(TerminalFormatStringsInstance.Clear); | ||
| if (!string.IsNullOrEmpty(TerminalFormatStringsInstance.ClearScrollbackBuffer)) |
There was a problem hiding this comment.
according to https://unix.stackexchange.com/a/375784 we should do E3 before clear:
If the terminfo/termcap entry has an E3 capability it, it first writes out that.
It then uses the clear capability to clear the visible screen.
There was a problem hiding this comment.
The snippet of clear shared in the issue had E3 being issued after clear, but I'm not sure it matters either way. I'll switch the order.
There was a problem hiding this comment.
I assume we manually validated the behavior on at least some system with the E3 and then clear?
There was a problem hiding this comment.
@stephentoub I had tested before, but unfortunately just assumed the switched order was okay per the linked answer. I just ran my manual test again and having E3 issued before clear does not clear the scrollback buffer.
That means this order needs reversed back to the original: Clear, then E3. Would you mind making that change on your PR? Or do you want me to submit a new PR with the optimization mentioned below + this fix?
There was a problem hiding this comment.
Would you mind making that change on your PR?
No problem; I switched the order back.
adamsitnik
left a comment
There was a problem hiding this comment.
LGTM, again big thanks for your contribution @natehitze !
| { | ||
| WriteStdoutAnsiString(TerminalFormatStringsInstance.ClearScrollbackBuffer); | ||
| } | ||
| WriteStdoutAnsiString(TerminalFormatStringsInstance.Clear); |
There was a problem hiding this comment.
This is the only place Clear is used, right? Rather than doing two separate writes, could we just update TerminalFormatStringsInstance.Clear to be constructed as the concatenation with ClearScrollbackBuffer if it exists, and then this call site doesn't change from what it was before... it just writes out Clear, which will issue both commands if they're supported.


Some terminals define an extra sequence to clear the terminal scroll buffer. Using it after the clear sequence makes Clear() work like the 'clear' command.
Fix #84351
The linked issue has a detailed analysis and explanation which was the guide for this PR.