-
Notifications
You must be signed in to change notification settings - Fork 1.4k
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
Exec ConsoleToMSBuild=true doesn't preserve colors #4299
Comments
Per my new friend Mark Junker, it should be possible to do this thanks to Windows 10's Windows Subsystem for Linux (WSL). In looking this up, it appears he is right, and it is possible thanks to microsoft/WSL#406 |
Thanks for filing this; I've been thinking about it for a long time, too. Unfortunately, I haven't found a good solution either. There are a few problems:
This came up in the context of |
A couple of thoughts:
My last point may be too clever for some people to understand, so I'll break it down another way: When you write logging code, you could write: It's this sort of abstraction people want, and it just needs to exist and be documented for it to work really well. So, let's |
@rainersigwald Let me know if the above replies make sense. We'll fight the good fight. In the mean time, since it seems like my Trojan Horse about Exec needing Colors was unnecessary, since you already seem to understand the general problem, let me know if I can rename this to something a bit more serendipitous with your thoughts. But, seriously though: I would be very happy just to get MSBuild to preserve dotnet cli colors. |
@rainersigwald Thanks for the reference to ConDrv. I was unaware that a Console Team even exists. It seems their solution is a bit too clever by half, and seems to prevent the very scenario I want to achieve. It's hard to fully understand their architecture drawing, but it seems to me that they boxed developers in by only having a "Command Line API" on the left hand side of ConDrv, and no "Command Line API" on the right hand side of ConDrv. I guess I'll try to track down Rich to understand his drawing better. Do you happen to know if ConPTY is exposed on .NET Core, and, if so, how? TYVM! Could it be this? https://github.com/Microsoft/console/tree/07d06f62aa5a883f70cbe8572bf8ea1f8577f53f/samples/ConPTY/GUIConsole/GUIConsole.ConPTY |
Hey so lemme chime in real quick before we get off the rails on ConPty. Conpty exists to enable applications to act as terminal emulators on Windows. It acts as the console host, servicing console API calls in the same way the console normally does, but then "renders" the side effects of the API calls to a stream of VT sequences. This means that client applications (like cmd.exe, msbuild.exe, etc) can use the same old Console API's they've been using since Windows 3.1, but now instead being forced to use conhost as the terminal window, another application could step in as the terminal instead, and the new terminal application could be written just the same as a terminal emulator on linux. We (the console team) certainly haven't done any work to expose ConPTY in any sort of managed sense. The sample you linked is community code, but there's no official support currently. Conpty is not a new magic commandline client API. It will not magically make your client app emit output as VT. For commandline-client application developers targeting Win10+, our general recommendation is to use VT sequences always, and enable VT processing with SetConsoleMode. We're expanding our support for VT sequences, but we're leaving the console API as it is, for compatibility reasons. As noted here, the Console API isn't really portable to other platforms. |
@zadjii-msft But does my "call-by-intention" remarks make sense to you, and what I think a "good API" for this aesthetically has? For example, awhile ago author Joe Albahari created a library called Linqkit for extending Linq SQL libaries with common sub-expression substitutions. However, this library is fundamentally the wrong user experience for "call-by-intention" programming: The API producer has to "know" the end-user plans to require such substitutions, and the API end-use has to "know" the API producer provides such substitute-ability: The API Producer calls linqQuery.AsExpandable(). A much better approach is in the erecruit.Expr library, where the client caller can call Expand() at the very end of a an IQueryable builder pattern, without needing to know whether the IQueryable "supports" any special functionality. Sorry if this is overly verbose, but it's a Interpreter design pattern I have discovered some programmers have experience with, and others do not, and somewhere in the middle where there is a huge portion of engineers who don't even see the difference. THIS is the architecture we need. |
Yea I'm gonna say that's out of my area of expertise. I'm mostly only really concerned about the characters that end up getting written to the console. How apps want to pipe information to each other and preserve metadata such as color is not something I spend a lot of time thinking about :/ |
Thanks. One last question: When you say:
Are you referring to the Win32 Console API or the .NET surface area exposed via System.Console? As a .NET engineer discussing a .NET project MSBuild, I hear "the Console API isn't really portable to other platforms" as "the [.NET] Console API isn't really portable to other platforms." |
I'm talking about the Win32 Console API, as that's the layer we maintain. I'm not entirely sure there's anyone maintaining the .NET Console API. |
Got it. After comparing to what UNIX systems do, they are not too far off from how Windows behaves. The key thing is that GNU Core Utilities tend to have a In this sense, I suppose you might be right: the Win32 Console API shouldn't necessarily care what programs do, but the general Windows ecosystem sucks at having any support for this. |
Yes there are. For .NET Core, we live in https://github.com/dotnet/corefx |
I pinged @mscraigloewen and @bitcrazed on twitter about this issue. My "call by intention" idea has outstanding merit. |
@rainersigwald I am realizing that custom colorization also prevents tests output from being processed by MSBuild loggers (microsoft/vstest#680)! By the way If I may add my 2 cents here, having used MSBuild for many years, I love the austerity of the MSBuild output which gives me 2 simple and essential things: errors are red and warnings are yellow. And further information I can dig in the logs, should I need them. Other environments (think Rake, gulp.js, Phing...) are lacking in this regard IMHO, most often in their (in)ability to produce detailed logs. |
The problem of Windows' command-line tools not handling VT sequences is a long and historical one. But to summarize: Windows was architected upon object-based principles. UNIX was designed upon the principle that everything is a stream/file. Thus there are MANY differences to the design and implementation of both OS' and the tools that run upon them. This is easily seen in the way that UNIX and Windows command-lines work: In UNIX, apps emit streams of characters. Those streams of characters may contain embedded formatting codes (ANSI/VT sequences) that instruct the recipient to render the subsequent characters in bold, italic, or specific foreground / background colors, etc. In Windows, command-line apps emit text, but call APIs on the Console (the traditional Windows command-line GUI app that you see on-screen) to set colors, move the cursor around, etc. However, this breaks-down when you try to execute a command-line app on a remote machine - how does the remote command-line app call a method on your local Console from the remote machine upon which the command-line app is running? This is why Windows command-line apps suddenly start rendering in monochrome when accessed via ssh etc. We've been overhauling Windows' command-line infrastructure over the last several years to allow us to build a modern Windows Terminal app, and to eventually allow Windows command-line apps themselves to start emitting text/VT directly, rather than calling Windows' Console APIs (via We built the "magic" ConPTY to render text and API calls to an off-screen buffer and then stream the updated chars as text/VT so that Terminal doesn't have to continue to implement legacy Console APIs. This ConPTY will also allow comms gateways like OpenSSH to locally "render and stream" the text UI of Windows command-line apps as text/VT meaning you'll see color text coming back from remote command-line apps at some point when the work gets done 😜 And now that Console and Terminal have pretty decent support for VT, command-line apps like MSBuild could emit text/VT directly rather than calling We're also working with @jonsequitur & @KathleenDollard ( HTH. |
@bitcrazed Thanks for the thoughtful reply. My point was something much simpler, though. I was pointing out that if you look at how various UNIX utilities like troff behave and what formatting they support, there is a concept of:
Think of it this way. Color switch is like an HTTP media type. The terminal can query the program and the program can query the terminal and negotiate content types. In some cases, the terminal is just a browser/intermediary for two programs to communicate in a client-server pattern. The terminal can't and shouldn't know about the "magic conPTY" you describe. There has to be basic infrastructure for IPC. I understand for portability reasons to UNIX and general platform goals of supporting Linux, you chose what you chose. It's a defensible choice. I am simply trying to argue what I think the next 30 years of my career would ideally look like: content-based negotiation. I can also come up with more interesting examples to further my argument. But first I'm just seeking understanding of my viewpoint, as it is likely non-obvious to both Linux and Windows users. |
The color arg passed to This has nothing to do with the Terminal. Why? Terminals don't know what they're connected to - it could be a bash shell on the local machine, it could be ping.exe, it could be SSH which connects via WIFi to a weather station in Llanfairpwllgwyngyllgogerychwyrngogogoch To launch and connect to an tool, a terminal:
Everything else is transparent to the Terminal. That's why the ConPTY is magic.
|
I get that you're focused on pseudoterminals. Would it be more helpful to use a different word than pseudoterminal / pty, as ConPTY magic is basically just giving Windows what Linux has had for a long time? Would BrowserTerminal or
In the pseudoterminal world, you're forced to tell Rather than all this talk of pipes, what I'd rather see is simpler abstractions of Processor and ProcessorContext. The Programs communicating over what you call pipes are just sharing a context. Then my command line expression could be a continuation instead of just a co-routine, and I could have deep Control+C SIGINT. As Rainier said, some programs already sniff for things like whether their output is being redirected. It would be a lot nicer if that sniffing layer was uniform and we had canonical names for all these wonderful smells we can sniff. To be honest, this way of thinking about the problem is new to me, too. I looked around for others with similar ideas and probably the closest person is Thomas Lord (of GNU Arch DVCS and GNU Guile Lisp fame). I only thought about it recently because I had seen a large number of problems in Continuous Integration servers and their toolchains around color and formatting expectations. |
ConPTY is much, MUCH more than simply bringing a Linux-style Pty to Windows. If that's all we'd done, no existing Windows command-line app would work on any terminal connecting to the simpler pty. The point is that pty should be an unintelligent pipe and should not be responsible for nor involved in content/capability negotiation. There's an important architectural quirk here: There is no meta-communication channel between the Terminal and the command-line app. There's no way for the Terminal to send commands or requests for information to a command-line app. SHOULD there be one? Perhaps. But know that for this to work, there'd need to be an industry-wide, standardized, multi-decade initiative to make this happen. Re. sniffing: What @rainersigwald is seeing is not redirection sniffing Calling echo specifying If you emit VT, however, you'll see the color is preserved: $esc = "$([char]27)"
echo "$esc[91mHello$esc[0mWorld" | wsl cat So, if you want to color/stylize the output of your command-line apps, you should start planning to adopt VT, and avoid Console APIs if you want your styling to survive being piped through environments, between machines, and displayed even on non-Windows terminals. |
This makes me happy. I mean, it's 2020 and I'm finally enjoying web apps. |
I actually re-read this three times before I understood your point. Welp. I think I over complicated my immediate needs. Good discussion, though.
This is the big takeaway. I'll give it a try and see what problems I run into. |
LOLZ. Sorry if I dove deep, but I wanted to be sure that people realize that the command-line today is LITERALLY a mirror of the command-line as it was in 1960: It's chars out and chars in. That's it; everything else is just details! 😜 It's for this very reason that I wrote this multi-part series on the command-line and how it evolved, and how Windows differs from *NIX, etc. |
Supporting some form of content negotiation in a way that can work everywhere is why we have this "directive" concept in System.CommandLine: > myapp [output:ansi] --some-args --and stuff The syntax is weird because we wanted it to be amenable to standardization regardless of your CLI's own grammar. |
@jonsequitur So System.CommandLine will strip VT if [output:ansi] is set? |
We typically try to detect the terminal capabilities and set this for you, so these are explicit overrides to that behavior. |
@bitcrazed One discussion @jonsequitur and I had months ago (years ago??) in private was whether there was any standard for representing command line grammars, so that tools could interop with command line grammars and provide services like auto-complete and rich GUIs similar to the PowerGUI concept that was acquired by Dell and subsequently buried after budget cuts. If you happen to know of any standard, that would probably be helpful towards |
@jonsequitur - Got it, thanks. Though one suggestion: You may want to rename ANSI to VT since ANSI stopped standardizing escape codes and VT sequences in the '80s, deferring instead to industry standards. ISO/IEC and ECMA both maintain standards, but haven't really kept up with industry's advancements to support, for example, 24-bit color, etc. And perhaps |
@jzabroski Alas, the only shell <-> command-line protocol for things like arg expansion, etc. that I am aware of are ad-hoc approaches like those supported by bash et. al. However, John, Kathleen, and I (and others) have discussed how we might be able to systematize this somewhat - which is why @jonsequitur introduced the ability to dynamically reflect-over/query command-line apps built atop But, from small acorns ... 😜 |
And a footnote to this is that the mechanism by which this query is performed is also the directive syntax I mentioned earlier, e.g.: > dotnet-interactive [suggest] stdio h
--help
--log-path
-h
/h
http |
@rainersigwald I've spent some time pondering some deep, Confucious stuff lately regarding my build toolchain, and started asking:
"How can I run a .NET Core CLI Tool in an MSBuild Exec Task AND preserve the color output?"
Oh, boy.
Along the way, I found that MSBuild output itself can emit ANSI Escape Codes to processes like Travis CI... so it got me wondering, why can't MSBuild parse ANSI Escape Codes rather than generate them? Searching StackOverflow, I don't see any good answers. People seem to think fundamentally there is no way to capture color, it's drastically impractical, because color is a property of the console, not the standard output and error streams. I say, let there be color. Pastel, maybe.
Here is a sample repro of the issue:
build.targets
Expected Output
"hi" in red.
Actual Output
"hi" in console default foreground color and default background color
Deep Thoughts
“I for one believe that if you give people a thorough understanding of what confronts them and the basic causes that produce it, they’ll create their own program, and when the people create a program, you get action.” — Malcolm X
The text was updated successfully, but these errors were encountered: