Console.Unix: for echoing, write back to the terminal instead of writing to Console.Out.#94414
Console.Unix: for echoing, write back to the terminal instead of writing to Console.Out.#94414adamsitnik merged 11 commits intodotnet:mainfrom
Conversation
…ing to Console.Out. On Unix .NET implements its own echo to make Console behave similar to Windows. The echo implementation was writing to standard output, which has the unintended effect of writing the echo characters into a redirected standard output. This changes to write the echo to the stdin terminal where they were read from.
|
Tagging subscribers to this area: @dotnet/area-system-console Issue DetailsOn Unix .NET implements its own echo to make Console behave similar to Windows. The echo implementation was writing to standard output, which has the unintended effect of writing the echo characters into a redirected standard output. This changes to write the echo to the stdin terminal where they were read from. Fixes #22314. @adamsitnik @stephentoub ptal.
|
|
I need to make some additional changes so the characters that are written back for echo use the proper encoding. |
This is done. The PR is up for review. |
adamsitnik
left a comment
There was a problem hiding this comment.
The fix is great! It's relatively simple for the bug that has been hunting us for years! 👍
I added some comments for improving perf. It would be great to address them before merging.
Thank you @tmds !
| SetCursorPosition(Interop.Sys.FileDescriptors.STDOUT_FILENO, left, top); | ||
| } | ||
|
|
||
| internal static void SetCursorPosition(SafeFileHandle terminalHandle, int left, int top) |
There was a problem hiding this comment.
Have you tested all scenarios that include calling SetCursorPosition?
There was a problem hiding this comment.
I ran the manual tests and I saw no regression.
I will try some additional scenarios this week.
There was a problem hiding this comment.
I changed the PR so it prefers using stdout as a terminal handle to remain closer to the current behavior.
I also made the cursor/window size getting to work against the stdin handle.
…or stdin terminal handle.
| { | ||
| return; | ||
| } | ||
| } |
There was a problem hiding this comment.
@adamsitnik does this look good to you? I wrote it this way to have the bytes Span is in the same scope as the WriteToTerminal call.
|
I want to highlight a specific special case which will now throw. When standard output is redirected, and standard input is a read-only terminal handle, This seems appropriate as we don't have a way to echo the characters to. |
| public static Stream OpenStandardInput() | ||
| { | ||
| return new UnixConsoleStream(Interop.CheckIo(Interop.Sys.FileDescriptors.STDIN_FILENO), FileAccess.Read, | ||
| return new UnixConsoleStream(Interop.Sys.FileDescriptors.STDIN_FILENO, FileAccess.Read, |
There was a problem hiding this comment.
I'm not sure what the Interop.CheckIo is about, so I removed it.
There was a problem hiding this comment.
I am not familiar with this particular overload, let me share it here think loud about that:
runtime/src/libraries/Common/src/Interop/Unix/Interop.IOErrors.cs
Lines 86 to 105 in 487d7f0
- The xml comment does not describe what it does.
- If provided handle is invalid, then it gets last error for the current thread and throws an exception.
I don't think that we need such check here, as we have not performed any IO yet (the handle is created by providing a constant number: 0, 1 or 2, it's not a result of a sys-call), so there is no last error that makes sense. It can become invalid once we try to use it in a sys-call, but other layers are ready for that.
So I am fine with removing these checks (and the method itself if it's not used elsewhere) 👍
| } | ||
| } | ||
|
|
||
| internal static unsafe void WriteFromConsoleStream(SafeFileHandle fd, ReadOnlySpan<byte> buffer) |
There was a problem hiding this comment.
These other changes sync with the .Unix file.
adamsitnik
left a comment
There was a problem hiding this comment.
LGTM, thank you very much @tmds!
| public static Stream OpenStandardInput() | ||
| { | ||
| return new UnixConsoleStream(Interop.CheckIo(Interop.Sys.FileDescriptors.STDIN_FILENO), FileAccess.Read, | ||
| return new UnixConsoleStream(Interop.Sys.FileDescriptors.STDIN_FILENO, FileAccess.Read, |
There was a problem hiding this comment.
I am not familiar with this particular overload, let me share it here think loud about that:
runtime/src/libraries/Common/src/Interop/Unix/Interop.IOErrors.cs
Lines 86 to 105 in 487d7f0
- The xml comment does not describe what it does.
- If provided handle is invalid, then it gets last error for the current thread and throws an exception.
I don't think that we need such check here, as we have not performed any IO yet (the handle is created by providing a constant number: 0, 1 or 2, it's not a result of a sys-call), so there is no last error that makes sense. It can become invalid once we try to use it in a sys-call, but other layers are ready for that.
So I am fine with removing these checks (and the method itself if it's not used elsewhere) 👍
I am OK with that. I've applied |
|
@adamsitnik did you create a breaking change doc for this? |
On Unix .NET implements its own echo to make Console behave similar to Windows.
The echo implementation was writing to standard output, which has the unintended effect of writing the echo characters into a redirected standard output.
This changes to write the echo to the stdin terminal where they were read from.
Fixes #22314.
@adamsitnik @stephentoub ptal.