Управляющие последовательности терминала: почему терминалы не сообщают, какие функции они поддерживают, вместо того, чтобы полагаться на terminfo?

echo "lowercase" | tr a-z A-Z

Вывод:

LOWERCASE
6
05.09.2017, 03:19
2 ответа

Это не так просто, как вы думаете. xterm (, как и терминалы DEC VTxxx, начиная с VT100 ), имеет ряд отчетов для различных функций (, см.XTerm Control Sequences). Наиболее часто полезной является информация о типе терминала :

.
CSI Ps c  Send Device Attributes (Primary DA).

Не все терминалы имеют такой ответ. (Аппаратная консоль Sun имеет/имела ни одного).

Но есть больше возможностей, чем отчетов (например, как определить, действительно ли терминал интерпретирует UTF -8 :принятый путь для этого — через локаль переменные окружения, поэтому не было установлено необходимости в другой управляющей последовательности/отклике ).

На практике, хотя есть несколько приложений, которые обращают внимание на отчеты (, такие как vim , проверяя фактические значения функциональных клавиш, количество цветов с помощьюDCS + p Pt STи даже появление курсора с использованием DCS $ q Pt ST), этот процесс ненадежен, поскольку некоторые разработчики считают, что проще вернуть заданный отчет -, чем реализовать эту функцию. Если вы прочитаете исходный код различных программ, вы обнаружите интересные особенности, когда кто-то настроил ответ так, чтобы он выглядел как какая-то версия xterm.

7
27.01.2020, 20:24

Вот мой взгляд на управляющие последовательности, которые запрашивают эмулятор терминала.

tl;dr :Из-за их асинхронной природы они действительно проблематичны для приложений. (Не с помощью эмуляторов терминала, там это проще простого.)


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

Давайте спроектируем и реализуем в уме простую утилиту (, такую ​​как «ls» ), а также более сложное полноэкранное приложение (, такое как «mc» или «vim» ), и посмотрим с какими проблемами мы сталкиваемся.

  • Стандартной функцией Unix является то, что вы можете вводить следующую команду, пока выполняется предыдущая (, например. введите «sleep 10» Enter, затем «mc» Enter, затем нажмите F5; примерно через 10 секунд откроется «mc» с диалоговым окном «Копировать» ). Кому-то может нравиться эта функция, а может и не нравиться, но, по крайней мере, поведение должно быть одинаковым для всех приложений, и это поведение приложений, которые не запрашивают динамически эмулятор терминала. Давайте также представим, что «mc» использует такую ​​управляющую последовательность запроса при запуске, чтобы выяснить, какая функция. Теперь mc получит управляющую последовательность F5 перед ответом. Он может игнорировать его (, и в этом случае поведение будет несовместимым с остальными приложениями )или его нужно где-то спрятать, подождать, пока не придет ответ на запрос, а затем обработать эту F5.Чтобы сделать это, он больше не может позволить каждому компоненту читать и обрабатывать непосредственно из стандартного ввода, ему нужен некоторый промежуточный слой-оболочка. Выполнимо, но требует некоторых усилий для реализации (необходимая дополнительная работа заметна даже для проектов, начатых с нуля, не говоря уже о тех, которые уже реализованы без этого критерия и, следовательно, вам приходится сильно рефакторить.)

  • Аналогичная история происходит, если ему необходимо запросить терминал по какой-либо причине во время его работы. Тогда отбрасывание промежуточных «нормальных» символов до прихода ответа абсолютно недопустимо.

  • Теперь вместо утилиты, написанной на C или другом подобном языке, представьте себе сценарий оболочки, которому необходимо прочитать этот ответ, а также другие обычные данные, вводимые пользователем (со стандартного ввода ). Как бы вы пошли? Для каждого «чтения» в вашем коде, обрабатывающем такой ответ, вы бы вручную установили символы завершения в новую строку или конец escape-последовательности ответа, а также нашли и удалили escape-последовательность из остальных? Как сделать так, чтобы ответ escape-последовательности не отображался на экране, пока пользовательский ввод все еще отображается? Как бы вы «подавали» обычный ввод, который вы получаете, ожидая ответа управляющей последовательности, на последующие «обычные» команды «чтения», которые ожидают пользовательские данные? Я не понимаю, как это можно сделать, но даже если и можно, то очевидно, что это невыносимо сложно, утомительно и подвержено -ошибкам. Единственное, что я могу себе представить разумно реализуемым и надежно работающим, - это отбрасывать введенные -символы вперед (, что приводит к необычному поведению ), и обрабатывать такую ​​escape-последовательность ответа только при запуске вашего скрипта.

  • Время обмена данными между эмулятором терминала и приложением может стать значительным, если ваша простая утилита (, например. «ls» )используется в сценарии оболочки внутри цикла. В системах с одним ядром -требуется переключение контекста между двумя приложениями (, утилитой и эмулятором терминала ).хотя, наверное, это не так уж и плохо по сравнению с форком ()+execve ()+friends, который все равно случается. Думаю, в многоядерных -системах в этом нет необходимости, хотя я не уверен в деталях. Однако стоимость (задержки )может стать действительно значительной, если речь идет о реальном сетевом трафике.

  • В редких случаях приложение завершает работу, не прочитав ответ (, например. он падает или уничтожается ), ответ появляется при следующей команде, которую вы начинаете вводить (, что, я уверен, вы уже видели, например. когда вы случайно пометили двоичный файл ).


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

  • Как долго вы ждете ответа? Как вы составляете произвольный тайм-аут? Настраиваете ли вы (и если, то как )это время ожидания в соответствии с характеристиками сети (, например. эмулятор локального терминала или ssh для подключения к соседнему зданию или ssh для подключения к другой стороне земного шара )?

  • Что делать, если ответ не приходит вовремя (например. из-за отставания от ssh )? Будет ли ваше приложение продолжать работу в деградированном режиме, видимом пользователю?

  • Что, если ответ придет позже, чем приложение сдастся? Ваше приложение потенциально должно быть готово к такому ответу, приходящему даже в тех местах, где он вообще не ожидал. (. в вашем сценарии оболочки вы сначала запрашиваете некоторое состояние, ждете ответа с тайм-аутом, но каждое отдельное «чтение» позже должно быть подготовлено к тому, чтобы быть загрязненным этим отложенным ответом.)

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


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

4
27.01.2020, 20:24

Теги

Похожие вопросы