Вопрос или проблема
Я знаю, что, если доступен цветной терминал, можно раскрасить его вывод с помощью escape-последовательностей.
Но есть ли возможность узнать, какой цвет в данный момент используется для вывода? Или, что более важно, какой цвет будет у текста, если я выведу его сейчас?
Я спрашиваю, чтобы не нарушить предыдущие настройки цвета при использовании этих escape-последовательностей. Escape-последовательность ‘цвета по умолчанию’ получает информацию из цветовой схемы, а не из цвета текста до того, как я его изменил.
В xterm
вы можете получить текущие RGB-коды цвета, изменив escape-последовательность изменения цвета на запрос. Используйте ESC ] Ps m
, но добавьте вопросительный знак ?
. Из документации:
- Если указан
"?"
вместо имени или RGB-спецификации,xterm
отвечает управляющей последовательностью того же формата, который может быть использован для установки соответствующего динамического цвета. Поскольку в одной управляющей последовательности может быть указано более одной пары номера цвета и спецификации,xterm
может дать более одного ответа.- P s = 1 0 → Изменить цвет переднего плана текста VT100 на P t .
- P s = 1 1 → Изменить цвет фона текста VT100 на P t .
- P s = 1 2 → Изменить цвет курсора текста на P t .
- P s = 1 3 → Изменить цвет переднего плана мыши на P t .
- P s = 1 4 → Изменить цвет фона мыши на P t .
- P s = 1 5 → Изменить цвет переднего плана Tektronix на P t .
- P s = 1 6 → Изменить цвет фона Tektronix на P t .
- P s = 1 7 → Изменить цвет фона выделения на P t .
- P s = 1 8 → Изменить цвет курсора Tektronix на P t .
- P s = 1 9 → Изменить цвет переднего плана выделения на P t .
У меня есть серьезные сомнения, что это сработает в другом терминальном эмуляторе, но в xterm
, если запустить…
printf '\033]11;?\007'
…xterm
вернет в буфер ввода вашего терминала последовательность вида…
11;rgb:ffff/ffff/ffff
…для фона или для переднего плана:
printf '\033]10;?\007'
10;rgb:0000/0000/0000
В общем, получение текущих цветов невозможно. Обработка управляющих последовательностей терминалом происходит “внутри” терминала, где бы он ни находился. В случае терминального эмулятора такого как xterm
или встроенного в ядро операционной системы, предоставляющего виртуальные терминалы ядра, внутреннее состояние эмулятора, включая его представление о текущем “графическом оформлении” (т.е. цвете и атрибутах), находится на самом компьютере и теоретически доступно. Но для реального терминала эта информация находится в некотором пуле ОЗУ на физически отдельном устройстве, подключенном через последовательную линию связи.
Тем не менее, некоторые терминалы включают механизм для считывания такой информации как часть их протокола терминала, который передается по этой последовательной линии связи. Они предоставляют управляющие последовательности, которые программа может отправить терминалу, заставляющие его отправить обратно информацию о своем внутреннем состоянии, как ввод терминала. mikeserv
показал вам управляющие последовательности, на которые отвечает терминальный эмулятор xterm
. Но они специфичны для xterm
. Встроенные в ядро эмуляторы терминалов Linux и различные ядра BSD — это разные типы терминалов, например, и не реализуют никаких таких управляющих последовательностей вообще. То же самое касается целых семейств реальных терминалов.
Терминалы DEC VT525 реализуют механизм считывания, но у них есть набор управляющих последовательностей, который не имеет никакого отношения к тем, которые используются xterm
. Отправляется последовательность DECRQSS (Request Selection or Setting), чтобы запросить текущее графическое оформление, и терминал отвечает последовательностью DECRPSS (Report Selection or Setting). Конкретно:
- Хост отправляет: DCS
$
q
m
ST (DECRQSS с управляющей функцией части SGR в качестве настройки) - Терминал отвечает: DCS
0
$
r
0
;
3
3
;
4
4
m
ST (DECRPSS с параметрами и управляющей функцией части SGR управляющей последовательности, которая задает текущие цвета переднего и фона)
Конечно, внимательное прочтение вашего вопроса показывает, что вы снова машете шоколадным бананом перед европейскими валютными системами. То, что вы на самом деле пытаетесь сделать, для чего выбрали решение и затем спросили, как выполнить часть этого решения, это сохранить предыдущее состояние, при этом выводя цветной текст. Не только есть управляющая последовательность DEC VT для этого, но и консольная последовательность терминала SCO, которая распознается xterm
и различными встроенными эмуляторами терминалов в ядре, а также запись termcap/terminfo, которая говорит вам, что они представляют для вашего терминала.
Записи termcap — это sc
и rc
. Записи terminfo — это save_cursor
и restore_cursor
. Названия несколько вводят в заблуждение относительно эффекта (хотя они выступают как предупреждение, что вы полагаетесь на что-то, являющееся де-факто, а не де-юре). Фактические управляющие последовательности DECSC, DECRC, SCOSC и SCORC также сохраняют и восстанавливают текущее графическое оформление.
Учитывая, что статья, на которую вы указали, вся о генерации управляющих последовательностей из оболочечных скриптов, команда, которую вы сейчас ищете, это tput
.
Дальнейшее чтение
- Джонатан де Бойн Поллард. 2007. Put down the chocolate-covered banana and step away from the European currency systems.. Часто даваемые ответы.
- VT420 Programmer Reference Manual. EK-VT420-RM-002. Февраль 1992. Digital.
- VT520/VT525 Video Terminal Programmer Information. EK-VT520-RM. Июль 1994. Digital.
Альтернативный метод: используйте функцию vim term_dumpwrite
.
- выполните
:term
внутри vim - выполните вашу команду внутри терминала (например,
git log
) - нажмите
<c-w>:
(или любую другую клавишу, установленную в'termwinkey'
) - выполните команду
:call term_dumpwrite(bufnr(), "/tmp/a.dump")
- прочтите файл
Файл не совсем удобочитаемый, но вы, по крайней мере, можете извлечь какую-то информацию…
например, git log
начнется с чего-то вроде
|c+0#e0e0004&|o|m@1|i|t| |
вы можете догадаться, что #e0e000
относится к цвету (желтый), следующий 4
относится к тому, что это четвертый цвет (индексируется с единицы) в палитре из 16 цветов, @1
означает “еще одна копия” и т.д.
Есть также такие вещи, как term_scrape
.
Ответ или решение
Определение текущего цвета консольного вывода в компьютерной системе представляет собой сложную и интересную задачу, связанной с функциональными возможностями терминала и способами обработки управляющих последовательностей. Вопрос, как это сделать, часто затрагивает следующие аспекты: понимание, какие цвета сейчас используются текстом в консоли, и как сохранить предыдущие настройки цвета при вывода текстов с новыми цветами.
Теоретическая основа
Консольный вывод в большинстве терминальных эмуляторов осуществляется с использованием управляющих последовательностей ANSI, которые позволяют задавать атрибуты текста, такие как цвет переднего и заднего плана, стиль шрифта и другие. Эти последовательности представляют собой определенные наборы символов, начинающиеся с ESC (Escape) и далее следующих за ним символов, обозначающих те или иные инструкции для терминала. К примеру, последовательность ESC[31m
устанавливает красный цвет текста.
Но вот вопрос: как можно определить или прочитать, какой цвет текста используется в данный момент до вывода нового текста? На практике, большинство терминальных эмуляторов не предоставляет прямого способа получения текущих настроек цвета. Однако, для некоторых эмуляторов, таких как xterm
, возможно использовать специфические управляющие последовательности для получения информации о цвете.
Пример реализации
В xterm
текущие цвета могут быть считаны с помощью изменённых последовательностей изменения цвета. Например, при помощи следующей команды можно запросить цвет фона:
printf '\033]11;?\007'
После её выполнения, xterm
вернет в буфер входных данных последовательность в формате:
11;rgb:ffff/ffff/ffff
Эта последовательность указывает, например, на белый цвет фона RGB: ffff/ffff/ffff. Для получения цвета текста следует использовать команду:
printf '\033]10;?\007'
Запрос выведет текущий цвет текста в аналогичном формате RGB.
Однако, стоит помнить, что эта функциональность специфична для xterm
и может не поддерживаться другими терминальными эмуляторами, что делает это решение ограниченным.
Применение на практике
На практике, задача, которую обычно хотят решить, это не столько откровение текущего цвета, сколько сохранение предыдущих цветовых настроек перед вводом новых. Таким образом, более универсальный способ в работе с терминалами — это сохранение и восстановление состояния терминала до и после вывода нового контента. Для этого можно использовать команды tput
для сохранения (tput sc
) и восстановления (tput rc
) состояния:
# Сохранить состояние
tput sc
# Ваши команды с изменением цвета
echo -e "\033[31m Текст красного цвета \033[0m"
# Восстановить состояние
tput rc
Эти команды сохранят и восстановят не только курсор, но также и текущие атрибуты текста, что обеспечивает консистентность отображения.
Заключение
Определение текущего цвета текстового вывода в консоль является лишь частью более общей задачи управления отображением вывода в терминалах. Несмотря на ограниченные возможности запроса текущих настроек, использование операций сохранения и восстановления состояния обеспечивает эффективное управление цветами в большинстве случаев и является предпочтительным методом для сохранения предыдущих настроек консольного вывода. В дополнение, терминальные эмуляторы постоянно развиваются, и может появиться новый функционал, расширяющий возможности работы с управляющими последовательностями и извлечения состояния терминала.