CLI приложения #7. ANSI-коды
Цветной вывод в консоли выглядит как что-то, для чего нужна библиотека. На самом деле ничего особо сложного там нет: цвет — это обычный текст, просто терминал показывает его не как текст, а исполняет как команду.
Можно легко убедиться одной строкой:
Console.WriteLine("\u001b[31mОшибка\u001b[0m: файл не найден");
Слово «Ошибка» станет красным, остальное — обычным. Разберём, что здесь происходит.
\u001b — это символ Escape, тот самый, что на клавише Esc. Терминал, встретив его, понимает: дальше идёт не текст для показа, а инструкция. Следом [ открывает саму инструкцию, потом число-параметр, потом буква — что с этим параметром делать. Буква m означает «поменять оформление текста».
Получается Esc + [ + 31 + m — «включи красный». А \u001b[0m — «сбрось всё обратно».
Основных кодов не так уж много и их несложно запомнить:
0 — сброс всего оформления
1 — жирный
4 — подчёркнутый
30–37 — цвет текста: чёрный, красный, зелёный,
жёлтый, синий, пурпурный, голубой, белый
40–47 — то же самое, но для фона
90–97 — яркие варианты цветов текста
Параметры можно совмещать через точку с запятой: \u001b[1;31m — жирный красный.
Но, #мыжпрограммисты, поэтому вместо бесконечного указания в коде кодов (да-да, это тавтология) заведём helper:
csharp
internal static class Ansi
{
private const string Esc = "\u001b[";
public const string Reset = Esc + "0m";
public const string Bold = Esc + "1m";
public const string Red = Esc + "31m";
public const string Green = Esc + "32m";
public const string Yellow = Esc + "33m";
// 16 миллионов цветов, если терминал умеет
public static string Rgb(int r, int g, int b) => $"{Esc}38;2;{r};{g};{b}m";
public static string Paint(string text, string color) => $"{color}{text}{Reset}";
}
И пользоваться становится проще, а код нагляднее и понятнее:
csharp
Console.Error.WriteLine(Ansi.Paint("Ошибка", Ansi.Red) + ": файл не найден");
Console.WriteLine(Ansi.Paint("Готово", Ansi.Green));
Console.WriteLine(Ansi.Paint("Фирменный цвет", Ansi.Rgb(0, 122, 204)));
Резонный вопрос: а зачем всё это, если в .NET есть Console.ForegroundColor? Он проще, но умеет рисовать только шестнадцать цветов и не умеет форматировать текст — ни жирного, ни подчёркивания в нём нет. Плюс это глобальное состояние: забыли вызвать Console.ResetColor() — и пользователь остался с зелёным приглашением командной строки. ANSI-последовательность живёт внутри одной строки и никуда не утекает.
Ещё нюанс: в Windows Terminal и в современных версиях PowerShell всё заработает сразу, а вот старая консоль cmd.exe может показать сами коды в виде мусора вроде ←[31m. Так что проверять стоит не только на своей машине.
И вот тут возникает главный вопрос: а что, если вывод вообще никто не видит? Если его перенаправили в файл, все эти коды окажутся внутри него мусором. Как это определить и что с этим делать? Об этом и не только поговорим в следующем посте.