Skip to content
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

Overload Console.Write and Console.WriteLine to take ConsoleColor as a parameter #39746

Open
abhaycashikar opened this issue Jul 21, 2020 · 20 comments
Labels
api-suggestion Early API idea and discussion, it is NOT ready for implementation area-System.Console
Milestone

Comments

@abhaycashikar
Copy link

abhaycashikar commented Jul 21, 2020

(I was directed to repost this feature request here.)

Background and Motivation

I'm trying to create a user-friendly command-line application, and as such I wanted to color my output to the console. However, I found myself frequently writing code like this:

Console.WriteLine("This output is white on black.");
Console.ForegroundColor = ConsoleColor.Red;
Console.BackgroundColor = ConsoleColor.Green;
Console.WriteLine("This output is red on green.");
Console.ResetColor();
Console.WriteLine("This output is white on black.");

Proposed API

I thought it might be a lot easier for Console to have an overload on Write and WriteLine that takes in two ConsoleColor elements as arguments for the ForegroundColor and BackgroundColor variables and abstracts this process away from the developer. This way, the process of setting the ForegroundColor and BackgroundColor variables, writing to the console, and resetting the color can be written as one line in code. I think something like the below would work:

+ public static void WriteLine(ConsoleColor foreground, ConsoleColor background, string value) { throw null; }

Usage Examples

Console.WriteLine("This output is white on black.");
Console.WriteLine(ConsoleColor.Red, ConsoleColor.Green, "This output is red on green.");
Console.WriteLine("This output is white on black.");

would be equivalent to the code in the Background and Motivation section.

Alternative Designs

If overloading is not possible, additional methods like WriteColor and WriteLineColor would still be very useful in my opinion.

Risks

I'm not really sure if there are any risks that come with making this change. I don't think there would be because the functionality would just use the existing methods in Console and the existing ConsoleColor enum.

@Dotnet-GitSync-Bot Dotnet-GitSync-Bot added area-System.Console untriaged New issue has not been triaged by the area owner labels Jul 21, 2020
@ghost
Copy link

ghost commented Jul 21, 2020

Tagging subscribers to this area: @eiriktsarpalis
Notify danmosemsft if you want to be subscribed.

@danmoseley danmoseley added the api-suggestion Early API idea and discussion, it is NOT ready for implementation label Jul 22, 2020
@danmoseley
Copy link
Member

@abhaycashikar thanks for the suggestion. Could you please edit your suggestion above to follow the format here: https://github.com/dotnet/runtime/issues/new?assignees=&labels=api-suggestion&template=02_api_proposal.md&title=
(you don't need to create a new issue)

Making it explicit and formatted like that will help us review it.

@abhaycashikar
Copy link
Author

Hi @danmosemsft, I apologize for not using that formatting initially! I've edited the issue to match it now, with the exception of the diff block in Proposed API (I thought it didn't really make sense since it would just be all additions).

@danmoseley
Copy link
Member

@abhaycashikar looks good...could you add that diff block although it's just an add? That helps the review process.

@abhaycashikar
Copy link
Author

Sure, no problem.

@KalleOlaviNiemitalo
Copy link

KalleOlaviNiemitalo commented Jul 22, 2020

public static void WriteLine(string str, ConsoleColor foreground, ConsoleColor background)

If you have source code that calls this method, but compile it against a target framework that does not have the method, then overload resolution chooses WriteLine(string format, object arg0, object arg1), which unexpectedly treats the string as a format string and the compiler does not warn about this. WriteLine(ConsoleColor foreground, ConsoleColor background, string str) would not have that risk. It would also be consistent with PSHostUserInterface.WriteLine.

@KalleOlaviNiemitalo
Copy link

I think the name of the string parameter should be value, for consistency with WriteLine(string value).

@SingleAccretion
Copy link
Contributor

Linking as related: #34742. There was a lot of discussion in the reviews of that API about color, and the consensus was that BCL should consider adding some StreamWriter-type API for writing ANSI escapes and that's how color should be done in the future. Not that it invalidates these additions to Console, just another point in the bucket for ANSIEscapesWriter.

@KalleOlaviNiemitalo
Copy link

According to PowerShell/PowerShell#13071 (comment), PowerShell has prototyped System.CommandLine.Rendering for colors. However, that package is still in prerelease, lacks documentation, and is far more complex than the API being proposed here.

@danmoseley
Copy link
Member

@abhaycashikar nit, the diff section would just look like

+ public static void WriteLine(string str, ConsoleColor foreground, ConsoleColor background) { throw null; }

At this stage, we don't care about implementation.

As other folks pointed out above, this is not as simple an addition as it may seem 😄

@KalleOlaviNiemitalo
Copy link

A developer writing

Console.ForegroundColor = ConsoleColor.Blue;
Console.BackgroundColor = ConsoleColor.Black;
Console.WriteLine("Blue on black.");
Console.WriteLine(ConsoleColor.Red, ConsoleColor.Green, "This output is red on green.");
Console.WriteLine("Guess what this is!");

could expect that the third line is again blue on black. However, that is difficult or impossible to implement if Console is using Console Virtual Terminal Sequences rather than the Win32 console API. It would just have to be documented.

@Jaykul
Copy link

Jaykul commented Jul 22, 2020

I don't think it's worth the risk to add 16 color support to the Console api when we should be adding 16 million color support.

@KalleOlaviNiemitalo is on the right track here, the Windows Console supports RGB colors now, and does not support controlling those colors through the Win32 API. There's no point trying to update System.Console. We just need to use VT based APIs through the Terminal class in the System.CommandLine package. It's right here in /dotnet/command-line-api.

@SingleAccretion
Copy link
Contributor

There's no point trying to update System.Console

That's a little harsh in my view. System.Console is widely used and widely known to be useful, so any improvements there will have the highest impact on the ecosystem.

@eiriktsarpalis eiriktsarpalis added this to the Future milestone Aug 11, 2020
@eiriktsarpalis eiriktsarpalis removed the untriaged New issue has not been triaged by the area owner label Aug 11, 2020
@GSPP
Copy link

GSPP commented Sep 1, 2020

It would be useful if this API was integrated with the normal locking that writing to the console does. WriteLine is atomic which is important in multi-threaded console output. Changing colors before and after calling WriteLine is racy. Therefore, applications need to introduce their own global console lock if they want atomic colored WriteLine. If this was built-in, it could just be handled correctly.

@bramborman
Copy link

bramborman commented Nov 12, 2020

I was just going to file a similar proposal with almost identical motivation but found this one so I will add my thoughts to this discussion.

First of all, I'd expect this API would not reset colors to default after writing but reset to previous:

Console.ForegroundColor = ConsoleColor.Yellow;
Console.WriteLine(ConsoleColor.Red, ConsoleColor.Black, "Red on Black");
Console.WriteLine("Yellow on Black");  // Not White on Black or whatever the default combination is

Second - I think that all the overloads of Write and WriteLine should have support for coloring, so there would be many overloads such as:

Write(ConsoleColor foregroundColor, ConsoleColor backgroundColor, int value);
WriteLine(ConsoleColor foregroundColor, ConsoleColor backgroundColor, string format, params object[] args);

Imho foreground color is changed much more frequently than the background color, so it'd be nice to have overloads that change only the foreground color:

Write(ConsoleColor foregroundColor, string value);

For the two-color-parameters overloads, the colors may be made nullable so you can change only the non-null color. These may, however, only be added if the color-changing methods have names different to Write and WriteLine as, as noted above, that'd also be a problem if compiled against framework without these overloads, as using the above would silently use the WriteLine(string format, object arg0, object arg1) overload.

Console.ForegroundColor = ConsoleColor.Yellow;
Console.WriteLine(null, ConsoleColor.DarkBlue, "Yellow on Dark Blue");

Btw if this gets approved, I'm willing to implement it 😊

@KalleOlaviNiemitalo
Copy link

KalleOlaviNiemitalo commented Nov 12, 2020

I'd expect this API would not reset colors to default after writing but reset to previous

How would you implement that? The Windows console host does not support XTPUSHSGR and XTPOPSGR yet (microsoft/terminal#1796).

@bramborman
Copy link

I'd expect this API would not reset colors to default after writing but reset to previous

How would you implement that? The Windows console host does not support XTPUSHSGR and XTPOPSGR yet.

ConsoleColor previousColor = Console.ForegroundColor;
Console.ForegroundColor = ConsoleColor.Red;
Console.Write("Red text");
Console.ForegroundColor = previousColor;

@KalleOlaviNiemitalo
Copy link

ConsoleColor previousColor = Console.ForegroundColor;

That cannot restore the color properly if the previous color is not any of the 16 colors supported by the ConsoleColor type, e.g. if it was specified in RGB, as implemented in Windows Terminal.

@bramborman
Copy link

bramborman commented Nov 12, 2020

ConsoleColor previousColor = Console.ForegroundColor;

That cannot restore the color properly if the previous color is not any of the 16 colors supported by the ConsoleColor type, e.g. if it was specified in RGB, as implemented in Windows Terminal.

It could be a note in the documentation. I think that if users are using RGB colors, they'd not be using this method :D

@eiriktsarpalis
Copy link
Member

I think that all the overloads of Write and WriteLine should have support for coloring

Agreed, if anything your typical console app does not use the same colors for entire lines, so arguably a Write overload is more useful.

@adamsitnik adamsitnik removed their assignment Nov 13, 2023
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
api-suggestion Early API idea and discussion, it is NOT ready for implementation area-System.Console
Projects
None yet
Development

No branches or pull requests

10 participants