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");
И, что еще более важно, текстовый файл, созданный вручную:
Оба из которых, которые правильно делают ожидаемую вещь: Напечатайте строку цвета ТЕАЛА "ТЕСТ":
Только 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.Kernel32
NuGet из соображений удобства, но если он слишком тяжелый для вас, вы можете создать сопоставление 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
установлен, и если он не установлен, он пытается установить режим.