Цветной вывод текста в терминале Linux

Иногда возникает необходимость вывести в командную строку Linux сообщение, в котором часть текста или весь текст имеет какой-либо цвет. Согласитесь, очень удобно было бы иметь возможность грамотно и красиво оформить вывод своей программы на D с помощью понятного и почти всем доступного цветового оформления.

В этой статье, я покажу вам содержимое одного самописного модуля, который позволит, не используя сторонних компонентов, добавить в свои консольные программы больше цвета и некоторых других эффектов.

Начнем с того, что терминал Linux — очень умная и хорошо разработанная вещь, которая поддерживает очень многие возможности в помощь программисту. Одной из таких возможностей является обработка специальных кодовых серий, которые называются escape-последовательностями.

Эти последовательности представляют собой ряд символов, которые не видны в ходе печати текста на терминал, но при этом трактуются как некоторые управляющие команды. Данные команды мы будем представлять в виде строковых последовательностей в Unicode, которые имеют общий шаблон построения: указание кодового символа в Unicode и некоторое числовое значение:

"\u001b[Nm"

где N — некоторый управляющий код.

Совокупность escape-последовательностей, помещенных перед текстом, по сути дела, и дают нужный цветовой эффект. Однако, чтобы текст после применения нужного цветового эффекта вернулся в исходное состояние и не оказал действия на последующий текст, то после окрашенного фрагмента текста нужно подать особую команду (добавить особую escape-последовательность) — команду сброса всех последовательностей.

Эта команда выглядит просто:
"\u001b[0m"
А теперь сам текст модуля, который называется colorize:

module colorize;

class ColoredTerminal
{
 	private
 	{
 		enum string reset = "\u001b[0m";
	 	
	 	enum string[string] backgroundColors = [
			"default"      :  "\u001b[49m",
			"black"        :  "\u001b[40m",
			"red"          :  "\u001b[41m",
			"green"        :  "\u001b[42m",
			"yellow"       :  "\u001b[43m",
			"blue"	       :  "\u001b[44m",
			"magenta"      :  "\u001b[45m",
			"cyan"	       :  "\u001b[46m",
			"lightGray"	   :  "\u001b[47m",
			"darkGrey"     :  "\u001b[100m",
			"lightRed"     :  "\u001b[101m",
			"lightGreen"   :  "\u001b[102m",
			"lightYellow"  :  "\u001b[103m",
			"lightBlue"    :  "\u001b[104m",
			"lightMagenta" :  "\u001b[105m",
			"lightCyan"    :  "\u001b[106m",
			"white"        :  "\u001b[107m"
	 	];

	 	enum string[string] foregroundColors = [
			"default"      :  "\u001b[39m",
			"black"        :  "\u001b[30m",
			"red"          :  "\u001b[31m",
			"green"        :  "\u001b[32m",
			"yellow"       :  "\u001b[33m",
			"blue"	       :  "\u001b[34m",
			"magenta"      :  "\u001b[35m",
			"cyan"	       :  "\u001b[36m",
			"lightGray"	   :  "\u001b[37m",
			"darkGrey"     :  "\u001b[90m",
			"lightRed"     :  "\u001b[91m",
			"lightGreen"   :  "\u001b[92m",
			"lightYellow"  :  "\u001b[93m",
			"lightBlue"    :  "\u001b[94m",
			"lightMagenta" :  "\u001b[95m",
			"lightCyan"    :  "\u001b[96m",
			"white"        :  "\u001b[97m"
	 	];

	 	enum string[string] textStyles = [
			"default"      :  "\u001b[0m",
			"bold"         :  "\u001b[1m",
			"bright"       :  "\u001b[1m",
			"dim"          :  "\u001b[2m",
			"underline"    :  "\u001b[4m",
			"blink"	       :  "\u001b[5m",
			"reverse"      :  "\u001b[7m",
			"hidden"	   :  "\u001b[8m",
	 	];
 	}
	
	// colorize your text
 	static string colorize(
 		string text, 
 		string foregroundColor = "default", 
 		string backgroundColor = "default", 
 		string textStyle = "default"
 		)
 	{
 		string foreground, background, style;
 		
 		// set foreground
 		if (foregroundColor in foregroundColors)
 		{
 			foreground = foregroundColors[foregroundColor];
 		}
 		else
 		{
 			foreground = foregroundColors["default"];
 		}

 		// set background
 		if (backgroundColor in backgroundColors)
 		{
 			background = backgroundColors[backgroundColor];
 		}
 		else
 		{
 			background = backgroundColors["default"];
 		}

 		// set style
 		if ((textStyle in textStyles) && (textStyle != "default"))
 		{
 			style = textStyles[textStyle];
 		}
 		else
 		{
 			style = "";
 		}

 		string newText = foreground ~ background ~ style ~ text ~ reset;

 		return newText;
 	}

 	// colorize with some caption style
 	static string colorize2(string caption, string text, string foregroundColor)
 	{
 		return colorize(caption, foregroundColor, "default", "bold") ~ " " ~ colorize(text, "white", "default", "bold");
 	}

 	// colorize as info message
 	static string info(string text)
 	{
 		return colorize2("Info:", text, "green");
 	}

 	// colorize as log message
 	static string log(string text)
 	{
 		return colorize2("Log:", text, "blue");
 	}

 	// colorize as warning message
 	static string warning(string text)
 	{
 		return colorize2("Warning:", text, "yellow");
 	}

 	// colorize as error message
 	static string error(string text)
 	{
 		return colorize2("Error:", text, "red");
 	}
}

Модуль colorize содержит простой класс ColoredTerminal, который реализует вышеупомянутые идеи о раскраске текста в терминале. Данный класс содержит общий метод colorize, принимающий строку текста, строку с описанием его цвета в виде обычного названия цвета на английском (поэтому список цветов довольно скудный), строку с описанием фонового цвета и строку с описанием стиля написания текста (это тоже описание на английском, которое говорит, что текст либо обычный, либо подчеркнутый и т.д.), а возвращает строку с примененными к тексту escape-последовательностями. Также, доступен ряд методов выводящих текст в стиле соответствующем какому-либо из следующих вариантов сообщения: информация (info), отладочное сообщение (log), предупреждение (warning) и ошибка (error).

Испытать класс легко, достаточно подключить модуль colorize к своей программе, разместив его в файле colorize.d, и воспользоваться любым из нужных методов в сочетании, например, с функцией writeln из std.stdio:

void main()
{
	import std.stdio;
	import colorize;

	ColoredTerminal.info("Связь с USB-устройством была установлена").writeln;
	ColoredTerminal.log("Был установлен цифровой режим").writeln;
	ColoredTerminal.warning("Настройки режима установлены в значения по умолчанию").writeln;
	ColoredTerminal.error("Отсутствует подключение к шине USB").writeln;
}

Выглядит это так:

Удачного использования в проектах!

Добавить комментарий