Open adamsitnik opened 3 years ago
Tagging subscribers to this area: @carlossanlop See info in area-owners.md if you want to be subscribed.
Author: | adamsitnik |
---|---|
Assignees: | adamsitnik |
Labels: | `Design Discussion`, `area-System.Console` |
Milestone: | Future |
@mdh1418 @MaximLipnin is there any chance that you could share your experience from https://github.com/dotnet/runtime/pull/41184 https://github.com/dotnet/runtime/pull/50931 ?
@adamsitnik The work in #41184 and #50931 was primarily done to leverage the platform compatibility analyzer and warn users when a particular API was unsupported on the specific platforms. I believe we had taken note of which APIs failed with PlatformNotSupportedException
when running library tests on Browser-wasm
Android
and also iOS
+tvOS
(which also had PlatformNotSupportedException
for System.Console
APIs, and we proceeded to mark those APIs with the Unsupported attribute
Microsoft needs to give @patriksvensson a ton of money and replace with spectre.
@phillip-haydon If you notice, Patrik is CC'd on the first message in the thread, because we've been having fortnightly calls for many months on the subject! The point of this thread is to mobilise "an army of the willing" who want to see these improvements invested in, and delivered! My original request was "please can we interop between System.CommandLine and Spectre?" 😁
I saw, I'm just totally blown away at spectre, been following it on twitter, we need to give Patrik more recognition that he's built something amazing :D (and the contributors to the project too)
100% I've said that Spectre delivers the "high level productivity API", that enables me to build impressive things quickly. It's like having the WebControls / WinForm Controls / WPF Components for the CLI, but there are also the lower-level APIs that are needed to deliver that experience consistently across all the platforms that .NET Supports. Hence my tagline of:
Spectre.Console + System.CommandLine = ❤
Please make sure it works great with https://github.com/migueldeicaza/gui.cs
@migueldeicaza would you like to provide some feedback based on your experience with building https://github.com/migueldeicaza/gui.cs?
FWIW, I'll throw this into the mix: https://github.com/alexrp/system-terminal
There are some aspects of that library I wouldn't necessarily repeat if I were to start from scratch, but I think it provides a mostly reasonable API surface that could serve as inspiration for a System.Console
re-design.
I maintain dotnet-shell so a lot of the thing I’m doing with Console are less about UI and more about input handling.
Unordered list of problems with Console / features I often require
Tek4014, I told Santa.
Or just a bitmap party space Invite
I agree that System.Console is too tied to Windows, and there are things that are hard to emulate on Linux (and generally on terminals that rely entirely on a stream of bytes).
The list of challenges above seem to be a blend of limitations in the current implementation, with some design challenges - I am not convinced that they are all design flaws (take for example the Color ones, or the Android/iOS ones that really are not speaking to a real terminal but a log).
It might be useful to compare the bugs above against the Mono version (the official version on Linux, that emulates .NET Framework 4.7) as some of those seems like limitations of the current .NET Core implementation, rather than design flaws.
If I were to design a new system, I think that I would do a few tiers of work:
(a) Put the terminal in raw mode/cooked mode, byte-at-a-time vs line-at-a-time (b) Colors, positioning
Then I would provide a split "WindowsConsole" with all the capabilities that Windows has (there are a bunch of things missing from System.Console, gui.cs shows a few of the things missing), and then also add an "XtermLineageTerminal" where there is a progression of capabilities from the simplest black and white VT100 all the way to modern terminals which support quite a number of capabilities.
The models are different, in Windows, folks can assume a framebuffer exists, while in vt100-derived terminals you must rely on escape sequences to get the job done. In the old days, it made sense for a library to interpose itself between the application and the terminal to optimize which command should be sent based on the changes made to the screen - while there is a mild case to be made for this, nowadays, connections and terminals are fast enough that it does not really matter all that much - so layers like ncurses might be overblown for things like this.
While gui.cs supports using the plain System.Console as a driver, it also has a Windows driver (for access to things like mouse events and additional modifiers) and a curses-driver, for Unix systems.
While gui.cs supports using the plain System.Console as a driver, it also has a Windows driver (for access to things like mouse events and additional modifiers) and a curses-driver, for Unix systems.
But unfortunately, Windows driver mouse events aren't supported on Windows Terminal
. So, maybe the solution is using a combination of WindowsDriver
(https://github.com/migueldeicaza/gui.cs/blob/main/Terminal.Gui/ConsoleDrivers/WindowsDriver.cs) and NetDriver
(https://github.com/migueldeicaza/gui.cs/blob/main/Terminal.Gui/ConsoleDrivers/NetDriver.cs), as discussed here https://github.com/migueldeicaza/gui.cs/issues/332#issuecomment-821297044.
Possibly slightly OT, but I would like better handling of buffers. It was somewhat unintuitive to me that running a command through System.Console has different buffering behavior (despite BeginOutputReadLine
) than a Terminal would.
Splitting it up into base/Windows/XTermLineage as Miguel mentioned makes sense to me, similar to how .NET 5 has platform-specific TFMs.
Standardize a Warning stream. It's frustrating working with Powershell and Azure DevOps automation and whatnot how all of them support the same stdout and stderror outputs but they all implement their own distinct flavor of Warn and they're not compatible.
Even if the implementation of the warning stream on most consoles is done as "color the text orange" instead of doing smart things like warning-specific redirection like Powershell offers, having a standard API for logging warnings would simplify a lot.
I want "Console.Warn".
But that probably requires some OS support that doesn't exist, I assume.
From PowerShell experience I opened https://github.com/dotnet/runtime/issues/800 to get support for tab-completions. Also there was mentioned it is desired to have a featured line editor. I don't remember whether an issue exists for TermInfo support. Currently .Net uses TermInfo internally in limited way. It would be nice enhance this, maybe expose publicly (and add Windows Terminal in TermInfo database) so that we could use unified approach for most of terminals.
@iSazonov Tab completions are available today. They're at a higher layer than System.Console
. System.CommandLine allows tool authors to configure completions, and end users can enable these using dotnet-suggest
. There's been some discussion of merging the latter's functionality into the dotnet
CLI and improving the install experience.
@jonsequitur Thanks for pointing System.CommandLine but PowerShell uses low level API to implement tab-completions for cmdlets.
One pain point for my libraries is CJK (Chinese, Japanese, and Korean) output. In the console, a single CJK character renders as two characters wide, versus English/Latin characters which are only one character wide. If you're trying to do any sort of fancy rendering where you care about character positions and alignment, it becomes pretty complex. If it's not designed for upfront, it's painful to add later on as it breaks a lot of assumptions.
Spectre.Console maintains https://github.com/spectreconsole/wcwidth/ to help retrieve this character width information, another C# implementation is this wcwidth gist.
One pain point for my libraries is CJK (Chinese, Japanese, and Korean) output. In the console, a single CJK character renders as two characters wide, versus English/Latin characters which are only one character wide.
Currently PowerShell PSReadline uses simple heuristics and it would be great to have native support the feature in .Net.
Some issues to consider with this effort:
Currently -whatif
circumvents the console. That's a small bug I'd like to see fixed - get -whatif
contents into the #6 info-stream same as write-host
Hi, just wanted to say that using Console.SetCursorPosition
is terrible if you're trying to go back to a previous position on macOS because whenever the window adds more lines, all of the numbers are offset, unlike on Windows.
eg.
var pos = Console.GetCursorPosition();
for (int i = 0; i < 100; i++) Console.WriteLine("Other line");
Console.SetCursorPosition(pos.Item1, pos.Item2);
Console.Write("Alternative text");
On windows this should put the text "Alternative text" on the first line of the output, but on macOS, it puts it at differing locations depending on how scrolled down you got.
I thought it was just with the ncurses that the horizontal scrolling wheel was not detected on Linux
and now I also came across that the same is not detected by System.Console.ReadKey(true)
, using escape sequences
. Is any solution foreseen for this?
Edit:
On Windows
it's returning the same code for horizontal left or horizontal right, the same as the wheel down.
"\u001b[<65;col;row;M"
If we do a redesign I think we should leave the old System.Console
API for now and create a new one (e.g. System.Terminal
) so that we don't have any breaking changes in System.Console
.
In this new API we can then modify all the sins we know of in System.Console
without hesitation.
@deeprobin That's the expectation. We're not going to break System.Console. This is to collect info on what the 'sins" of System.Console are.
Hi, just wanted to also say that Console.Clear doesn't do what I'd expect on macOS. It should send \u001b[3J\u001b[0;0H
(you can test this does what you want using by running printf '\u001b[3J\u001b[0;0H'
in the terminal) - this clears the screen and the scroll-buffer and then puts the cursor at the top. Currently it sends something similar to \u001b[2J\u001b[0;0H
(not exactly sure exactly what it sends) - this only clears the screen and puts the cursor at the top, it can also scroll down sometimes. I think there is a place for both types of clearing though, but currently we have only the less useful to me. Note: on Windows we only have the full console clearing currently, but I think the other is possible too using special escape sequences (possibly the same ones).
Another thing that would be really useful (but I don't know how to do / if it's possible) is have control over the scroll-bar in terminal using an api, because if you go down a line past the end of what's show, the position is still the same according to the api, so having control over both would be great on macOS for restoring positions properly. Unsure if this can be legitimately detected & controlled though.
Also, it would be very nice if we could detect dark mode easily on a platform like macOS where it changes all the colours in the terminal; I've implemented a basic version of this in one of my apps and could share the code if it's wanted.
Also, I'm sure you're aware, but please keep in mind that there are kind of 3 sets of apis in the Console class: plain text ones (like WriteLine), extra features that all/most terminals have (like colour), features to control the window (like window size) - even some of the last one should be able to work on macOS (and probably Linux if possible), not just the first 2.
Thanks!
Hi, just wanted to also say that Console.Clear doesn't do what I'd expect on macOS. It should send
\u001b[3J\u001b[0;0H
(you can test this does what you want using by runningprintf '\u001b[3J\u001b[0;0H'
in the terminal) - this clears the screen and the scroll-buffer and then puts the cursor at the top. Currently it sends something similar to\u001b[2J\u001b[0;0H
(not exactly sure exactly what it sends) - this only clears the screen and puts the cursor at the top, it can also scroll down sometimes. I think there is a place for both types of clearing though, but currently we have only the less useful to me. Note: on Windows we only have the full console clearing currently, but I think the other is possible too using special escape sequences (possibly the same ones).
@hamarb123 I think that bug does relate to the current API. Can you create a new Issue for this?
Another thing that would be really useful (but I don't know how to do / if it's possible) is have control over the scroll-bar in terminal using an api, because if you go down a line past the end of what's show, the position is still the same according to the api, so having control over both would be great on macOS for restoring positions properly. Unsure if this can be legitimately detected & controlled though.
I am not sure if this is possible. I guess this is something that belongs to the conhost
on windows.
But there are ANSI control sequences for scrolling ^1 (but these are not supported in ANSI.SYS
= no DOS-support):
Description | Sequence |
---|---|
Enable scrolling for entire display | <ESC>[r |
Enable scrolling from row {start} to row {end}. | <ESC>[{start};{end}r |
Scroll display down one line. | <ESC>D |
Scroll display up one line. | <ESC>M |
FWIW, no, controlling the scrollbar is not something that's broadly possible with VT/escape sequences. The "scroll up/down" sequences are used for shifting the contents within the active buffer (the "viewport" at the bottom of the scrollback), and account for things like scroll margins, but they don't move the viewport into scrollback.
Not all terminals have support for scrollback. There have been a few attempts across the ecosystem to try and roll one-off sequences for controlling the position of the viewport, but those aren't widely implemented (to the best of my knowledge).
Thanks, I tried some of those sequences and none of them scrolled back into the scroll-back on macOS. I will make an issue for the macOS clear function as well - thanks.
Well what I noticed was mostly things like Read/ReadKey. windows is the os where you can just ReadKey where on unixes it requires switching back and forth between terminal canonical mode, or what is done here, just staying in non canonical mode, so a dotnet console app, even a simple one reading lines, doesn't kinda feel native. Even though the fact itself that you can just ReadKey without doing os specific things is also useful. I am wondering, if a new api in any shape appears, will Console still be shown by default for simple things like WriteLine?
doesn't kinda feel native
That's another good point @webczat, something like ReadLine doesn't even let you press left and right to move the cursor - I've not seen any other console utility that does this on macOS (except things like vi where it's intentional in certain contexts) - also this doesn't mean they don't exist, I just haven't experienced them.
doesn't kinda feel native
That's another good point @webczat, something like ReadLine doesn't even let you press left and right to move the cursor - I've not seen any other console utility that does this on macOS (except things like vi where it's intentional in certain contexts) - also this doesn't mean they don't exist, I just haven't experienced them.
Well generally it's exactly the canonical vs non canonical mode. in canonical mode (default) dotnet is not supposed to handle things character by character, just ReadLine should read from terminal until newline, as only full lines are sent to it. In case of non canonical each character is sent and everything including ^u and ^k keystrokes and other such things, backspace etc needs to be directly handled by the program. I am on linux BTW.
@hamarb123 I think that bug does relate to the current API. Can you create a new Issue for this?
https://github.com/dotnet/runtime/issues/28355 - seems like I've commented here before also
I'm having the follow error when I resize the console height to zero or almost zero and pointing the mouse to the available console space:
System.InvalidOperationException: 'Cannot read keys when either application does not have a console or when console input has been redirected. Try Console.Read.'
This is happening on Windows
and WSL
using cmd, pwsh and conhost. As I'm reading escape sequences from Console.ReadKey (true)
in a console with a height equal to zero causes the System.Console.dll
crash. The problem is I can't force resizing the console. Do I still need to using for Windows the Win32 API Console by enabling ENABLE_VIRTUAL_TERMINAL_PROCESSING
to be able to use escape sequences or does System.Console allows that feature? Another question is many escape sequences request not available in Windows and WSL, is there any configuration I can use or is limitation?
To test this issue please clone the https://github.com/gui-cs/Terminal.Gui repo and run the UICatalog
project with the argument -usc
, which will use the NetDriver
using the System.Console
. Thanks.
@BDisp please create a new issue, this thread is dedicated to Console re-design
The initial design of
System.Console
was mainly driven by Windows OS capabilities and available APIs.When .NET became cross platform, a number of issues arose (click on the details button below to see the full list) as there was no good way of mapping some Windows-specific concepts to Unix. A good example are all
Console.Window*
APIs: on Unix the Window is owned by the Terminal app, the .NET Console App has no control over it.The current design makes no distinction between
Console
andTerminal
, which is also a source of plenty of issues (mostly for apps that have redirected output).Moreover,
System.Console
is astatic class
and there is no common abstraction that would allow not only for testing but also for integrating projects like spectre.console and System.CommandLine.Rendering.By creating this issue I would like to start a public and transparent discussion about what is wrong with the current design of
System.Console
and how we could fix that. Based on the results of this discussion, I would like to create a proposal for .NET 7.cc @jonsequitur @KathleenDollard @patriksvensson @colombod @Keboo @howardvanrooijen @daxian-dbw