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

Console.Foreground does not correctly set the color in every Terminal #62186

Open
GregorLamche opened this issue Nov 30, 2021 · 10 comments
Open

Comments

@GregorLamche
Copy link

GregorLamche commented Nov 30, 2021

Description

When setting the output color with Console.Foreground not every terminal correctly displays the color.
However if the color is set with unicode characters like \u001b[31m those terminals do show the correct color, meaning they do support color. (but some Terminals display the characters instead of the color making it not a functional workaround)

Reproduction Steps

  1. Create small console program (dotnet new console).
  2. Write the following code:
Console.ForegroundColor = ConsoleColor.Red;
Console.WriteLine("Hello, World!");
Console.ResetColor();
Console.WriteLine($"\u001b[31mHello, World!\u001b[0m");
  1. Run program in different terminal to see color support:
  • Microsoft Terminal
  • PowerShell
  • CommandPromt
  • VisualStudioCode Terminal
  • VisualStudioCode Debug Console (for this you have to create a launch.json in VSC)

Expected behavior

Console.Foreground should correctly set the font color independent of terminal, or at least in all terminals that support font colors.

Actual behavior

In some terminals Console.Foreground works, in some it doesn't.
In some terminals \u001b[31m works, in some it doesn't.
These two collections are not the same.
The user doesn't know in which type of terminal the code is running.
There is no way to consistently set color in the terminal.

Regression?

No response

Known Workarounds

None, see Actual behavior.

Configuration

No response

Other information

Tested on net6.0/Windows

@dotnet-issue-labeler dotnet-issue-labeler bot added area-System.Console untriaged New issue has not been triaged by the area owner labels Nov 30, 2021
@ghost
Copy link

ghost commented Nov 30, 2021

Tagging subscribers to this area: @dotnet/area-system-console
See info in area-owners.md if you want to be subscribed.

Issue Details

Description

When setting the output color with Console.Foreground not every terminal correctly displays the color.
However if the color is set with unicode characters like \u001b[31m those terminals do show the correct color, meaning they do support color. (but some Terminals display the characters instead of the color making it not a functional workaround)

Reproduction Steps

  1. Create small console program (dotnet new console).
  2. Write the following code:
Console.ForegroundColor = ConsoleColor.Red;
Console.WriteLine("Hello, World!");
Console.ResetColor();
Console.WriteLine($"\u001b[31mHello, World!\u001b[0m");
  1. Run program in different terminal to see color support:
  • Microsoft Terminal
  • PowerShell
  • CommandPromt
  • VisualStudioCode Terminal
  • VisualStudioCode Debug Console (for this you have to create a launch.json in VSC)

Expected behavior

Console.Foreground should correctly set the font color independent of terminal, or at least in all terminals that support font colors.

Actual behavior

In some terminals Console.Foreground works, in some it doesn't.
In some terminals \u001b[31m works, in some it doesn't.
These two collections are not the same.
The user doesn't know in which type of terminal the code is running.
There is no way to consistently set color in the terminal.

Regression?

No response

Known Workarounds

None, see Actual behavior.

Configuration

No response

Other information

No response

Author: GregTheMad
Assignees: -
Labels:

area-System.Console, untriaged

Milestone: -

@huoyaoyuan
Copy link
Member

Have you compared other programs that writes different colors into console? Those console are implemented in very different ways, and will have different compatibility.

@adamsitnik adamsitnik removed the untriaged New issue has not been triaged by the area owner label Nov 30, 2021
@GregorLamche
Copy link
Author

I tried it in various terminals, but only with my small program written in the Reproduction Steps.
I did however notice that the ASP.Net Core default debug output manages to correctly format the output for the VSC Debug Console output, while Console.Foreground does not.
A C++ library I was using (wrapped in C#) also managed to correctly format the output for the VSC Debug Console.
Visual Studio Code Debug Console is the only terminal so far that I discovered where Console.Foreground does not work, while the Unicode approach does work (which is why I guess it's a DotNet issue and not a VSC issue).

@huoyaoyuan
Copy link
Member

Console in Windows and console in Unix are fundamentally different. Using control character is Unix-like way, and VSCode is more Unix-like. The others are mostly native Windows console. This may be a cross compatibility issue.

@GregorLamche
Copy link
Author

It's hard to tell. ASP.NET Core outputs the color in VSC Debug Console correctly, so it either has some hidden secret sauce, or I'm missing something.
In the VSC Terminal (which I think is a wrapped external terminal?) for example the Console.Foreground gets correctly displayed.
As a program I have no idea (and I guess I shouldn't) in what type of terminal I'm running (eg. Unix or Windows), and so I can't handle the different support myself. The DotNet Runtime need to do this for me.

@danmoseley
Copy link
Member

It would be interesting to look at what aspnet is doing differently.

@hopperpl
Copy link

Yes, I had similar issues in the past and I don't think anything has changed since then. Since about 6 months ago.

Sometimes setting colors directly works. Sometimes sending ANSI codes works. Sometimes only basic ANSI codes work, sometimes also extended (like bold/italic/enhanced-color) codes work.

Now, it's not so much a problem to put all in a helper function that uses different approaches for coloring, but in Core there is really no good way to determine "where you are", what is supported and what is not. That terminal information is provided by the operating system, as tools like compilers (gcc, clang, you name it) know exactly if they can print ANSI codes or not. Or if enhanced ANSI codes are supported. As far as I know ForegroundColor is Windows-only anyway. As are all cursor ("caret") features.

Unification, or console feedback of supported features is really missing. Best would be if Core would emit ANSI when on non-Windows and the terminal supports it. Not just color, but cursor ("caret") movement as well.

And then there is the new Terminal Window and all its issues with Core.

@jeffhandley jeffhandley added this to the Future milestone Jul 10, 2022
@moorbren
Copy link

moorbren commented Nov 9, 2023

If anyone's still having an issue with this, just printing the ANSI reset code near the start of the app boot fixed on Windows using the new terminal.

Console.Write("\x1b[0m");

@LaithSaq
Copy link

Any updates to this? I am interested in a clean way to change colors in VScode's Debug console

@PTac-h
Copy link

PTac-h commented Mar 19, 2024

Hi !
If you want to use rgb colors with the native windows terminal, you need to enable VT100 support first.
source : https://learn.microsoft.com/en-us/windows/console/console-virtual-terminal-sequences
See the "Extended Colors" section to format your escape sequence.

To do it, you can import some methods from kernel32.dll directly.
Simply call TerminalSetup.Setup(), it worked for me on Windows 10 with vs2019, vs2022, cmd, powershell, the new windows terminal and through puTTy as well.

public class TerminalSetup
{

    // ReSharper disable InconsistentNaming

    private const int STD_INPUT_HANDLE = -10;

    private const int STD_OUTPUT_HANDLE = -11;

    private const uint ENABLE_VIRTUAL_TERMINAL_PROCESSING = 0x0004;

    private const uint DISABLE_NEWLINE_AUTO_RETURN = 0x0008;

    private const uint ENABLE_VIRTUAL_TERMINAL_INPUT = 0x0200;

    // ReSharper restore InconsistentNaming

    [DllImport("kernel32.dll")]
    private static extern bool GetConsoleMode(IntPtr hConsoleHandle, out uint lpMode);

    [DllImport("kernel32.dll")]
    private static extern bool SetConsoleMode(IntPtr hConsoleHandle, uint dwMode);

    [DllImport("kernel32.dll", SetLastError = true)]
    private static extern IntPtr GetStdHandle(int nStdHandle);

    [DllImport("kernel32.dll")]
    public static extern uint GetLastError();

    public static void Setup()
    {
        var iStdIn = GetStdHandle(STD_INPUT_HANDLE);
        var iStdOut = GetStdHandle(STD_OUTPUT_HANDLE);

        if (!GetConsoleMode(iStdIn, out uint inConsoleMode))
        {
            Console.WriteLine("failed to get input console mode");
            Console.ReadKey();
            return;
        }
        if (!GetConsoleMode(iStdOut, out uint outConsoleMode))
        {
            Console.WriteLine("failed to get output console mode");
            Console.ReadKey();
            return;
        }

        inConsoleMode |= ENABLE_VIRTUAL_TERMINAL_INPUT;
        outConsoleMode |= ENABLE_VIRTUAL_TERMINAL_PROCESSING | DISABLE_NEWLINE_AUTO_RETURN;

        if (!SetConsoleMode(iStdIn, inConsoleMode))
        {
            Console.WriteLine($"failed to set input console mode, error code: {GetLastError()}");
            Console.ReadKey();
            return;
        }
        if (!SetConsoleMode(iStdOut, outConsoleMode))
        {
            Console.WriteLine($"failed to set output console mode, error code: {GetLastError()}");
            Console.ReadKey();
            return;
        }
    }
}

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

9 participants