ANSI-раскраска консоли вывода с.NET

Я пытаюсь сгенерировать цветной вывод консоли, используя управляющие коды ANSI, с помощью следующей минимальной программы на C#:

using System;

// test.cs
class foo {
    static void Main(string[] args) {
        Console.WriteLine("\x1b[36mTEST\x1b[0m");
    }
}

Я использую Ansicon v1.66 ​​в Windows 7 x64 с помощью csc.exe (компилятор Microsoft C (Visual C# версии 4.6.0081.0).

Цветной вывод работает нормально в этой конфигурации; Сам Ансикон работает без нареканий.

Для перекрестной проверки я использую однострочник node.js, который на 100% эквивалентен программе на C#:

// test.js
console.log("\x1b[36mTEST\x1b[0m");

И, что еще более важно, текстовый файл, созданный вручную:

скриншот редактора текстового файла hex

Оба из которых, которые правильно делают ожидаемую вещь: Напечатайте строку цвета ТЕАЛА "ТЕСТ":

введите описание изображения здесь

Только test.exe, который я создал с помощью csc, печатает что-то еще. Зачем?

3 ответа

Решение

Ваша программа должна быть скомпилирована для /platform:x64 если вы используете среду AnsiCon x64 и с /platform:x86 если вы используете AnsiCon x86/32-битную версию. Точная причина загадка...

Первоначально я думал, что вам нужно все это:

Вам нужно взять StandardOutput и позволить Console.WriteLine считать, что вы пишете в файл, а не в консоль и используете кодировку ASCII.

Вот как это будет работать:

 var stdout = Console.OpenStandardOutput();
 var con = new StreamWriter(stdout, Encoding.ASCII);
 con.AutoFlush = true;
 Console.SetOut(con);

 Console.WriteLine("\x1b[36mTEST\x1b[0m");

.Net Console.WriteLine использует внутренний __ConsoleStream который проверяет, если Console.Out как дескриптор файла или дескриптор консоли. По умолчанию он использует дескриптор консоли и для этого пишет в консоль, вызывая WriteConsoleW. В комментариях вы найдете:

Хотя приложение может использовать WriteConsole в режиме ANSI для записи символов ANSI, консоли не поддерживают escape-последовательности ANSI. Однако некоторые функции обеспечивают эквивалентную функциональность. Для получения дополнительной информации см. SetCursorPos, SetConsoleTextAttribute и GetConsoleCursorInfo.

Для записи байтов непосредственно в консоль без WriteConsoleW мешает простой файловый дескриптор / поток, который достигается путем вызова OpenStandardOutput, Заворачивая этот поток в StreamWriter так что мы можем установить его снова с Console.SetOut мы сделали. Последовательности байтов отправляются в OutputStream и принимаются AnsiCon.

Обратите внимание, что это можно использовать только с соответствующим эмулятором терминала, таким как AnsiCon, как показано здесь:

Я создал небольшой плагин (доступный на NuGet), который позволяет вам легко переносить строки в цветовые коды ANSI. Поддерживаются цвета переднего плана и фона.

Это работает путем расширения String объект, и синтаксис очень прост:

"colorize me".Pastel("#1E90FF");

После чего строка готова к печати на консоли.

Сегодня я столкнулся с этим вопросом и не смог получить принятый ответ на работу. После некоторых исследований я нашел ответ, который заставит его работать.

Жаль, но нам нужно пойти на очень низкий уровень и напрямую вызвать Windows API. Для этой цели я использую PInvoke.Kernel32NuGet из соображений удобства, но если он слишком тяжелый для вас, вы можете создать сопоставление P\Invoke самостоятельно.

Следующий метод иллюстрирует, как можно активировать коды ANSI:

      bool TryEnableAnsiCodesForHandle(Kernel32.StdHandle stdHandle)
{
    var consoleHandle = Kernel32.GetStdHandle(stdHandle);
    if (Kernel32.GetConsoleMode(consoleHandle, out var consoleBufferModes) &&
        consoleBufferModes.HasFlag(Kernel32.ConsoleBufferModes.ENABLE_VIRTUAL_TERMINAL_PROCESSING))
        return true;
    
    consoleBufferModes |= Kernel32.ConsoleBufferModes.ENABLE_VIRTUAL_TERMINAL_PROCESSING;
    return Kernel32.SetConsoleMode(consoleHandle, consoleBufferModes);
}

Чтобы включить его для StdOut, вы вызываете его так:

      TryEnableAnsiCodesForHandle(Kernel32.StdHandle.STD_OUTPUT_HANDLE);

Если метод возвращает значение true, коды ANSI включены, в противном случае — нет.

Решение использует очень низкоуровневый Windows API. GetConsoleModeа также SetConsoleModeпроверить, работает ли режим буфера управления ENABLE_VIRTUAL_TERMINAL_PROCESSINGустановлен, и если он не установлен, он пытается установить режим.

Другие вопросы по тегам