Вопрос или проблема
Я поддерживаю расширение для среды Bash под названием Basta. Basta обеспечивает защитную строку состояния в нижней части вашего терминала ANSI/VT100.
Когда Basta настраивается, эффективное количество строк, как известно из вещей termios в ядре и переменной оболочки LINES
, уменьшается на 1. Изменение размера терминала обрабатывается хорошо. Почти. Есть trap
для сигнала SIGWINCH
для вызова обновляющей процедуры, которая также вызывается после каждой команды, перед возвращением к подсказке.
Однако время от времени я вижу ситуацию, когда область прокрутки теряется. Подсказка перекрашивается по нижней строке, где пользователь редактирует команды и где появляется вывод команд, что приводит к хаосу.
У меня есть гипотеза о том, как это может произойти, для которой есть надежные шаги для воспроизведения.
-
Мы запускаем программу, которая ожидает ввода, пока Bash находится в фоновом режиме, например,
cat
. -
В то время как эта программа работает, мы изменяем размер окна таким образом, чтобы уменьшить его на одну строку.
-
Завершаем программу
cat
.
Если терминал изменяется в размерах, пока работает cat
, Bash не получает SIGWINCH
(потому что, я думаю, SIGWINCH
отправляется только процессам в передней группе процессов терминального сеанса, а Bash в этот момент находится в фоновом режиме). Наш trap
не выполняется.
Функция обновления Basta также полагается на сравнение предыдущего размера терминала с текущим, чтобы обнаружить изменение размера.
Вот в чем проблема: в этой ситуации, когда терминал с защитной строкой состояния сократился на одну строку, количество строк, похоже, не изменилось.
Например, экран из 40 строк с областью прокрутки на 39 строк: LINES=39
. Измените размер терминала так, чтобы он был длиной в 39 строк. Область прокрутки пропала. LINES=39
снова. Для программного обеспечения это выглядит как тот же размер, поэтому делается вывод, что изменения размера не произошло. Теперь строка состояния перекрывает нижнюю строку, перекрывая ввод пользователя, потому что Basta хочет поместить ее на 40 строку, которой больше нет, поэтому курсор закрепляется на 39.
Если Basta знает, что произошло изменение размера окна, она не будет выполнять сравнение размеров; в этой ситуации она проходит по медленному пути, запрашивая сам терминал, чтобы определить размер. (Это было бы нежелательно делать для каждого обновления, потому что отправка запросов на терминал ненадежна. Если пользователь быстро вводит текст, ответ терминала может смешиваться с их нажатиями клавиш, и может быть заметная задержка в получении ответа от терминала через лаговые удаленные соединения.)
Есть ли какой-либо умный способ узнать, что терминал изменился (или, по крайней мере, подозревать это с достаточно низкой частотой ложных срабатываний), в отсутствие получения ловушки WINCH
, из-за нахождения в фоновом режиме, без общения с терминалом?
.
Ответ или решение
Обнаружение пропущенных сигналов SIGWINCH в Bash-расширении без явного изменения размера терминала представляет собой интересную техническую задачу, особенно в контексте поддержки скролл-защищённой статусной строки средствами вашего расширения Basta. Давайте рассмотрим эту проблему с использованием подхода TEA, который включает теорию, примеры и применение.
Теория
Основной причиной отсутствия реакции на изменение размера терминала является специфика работы сигналов в UNIX-системах. В случае сигнала SIGWINCH, данный сигнал передаётся только процессам, находящимся в активной группе процессов терминала, т.е. тем, что работают на переднем плане. Если Bash находится в фоновом режиме (например, когда выполняется программа cat
), то SIGWINCH Bash не получает. Эта ситуация приводит к неактуальному обновлению внутренней переменной LINES, что в свою очередь нарушает работу вашего расширения, поскольку попытка повысить статусную строку на одну строку выше её текущего уровня приводит к перезаписи пользовательского ввода.
Примеры
Ваши практические шаги по воспроизведению этой проблемы подтверждают теоретическую часть. Когда терминал уменьшает свой размер во время выполнения cat
, Bash оказывается в фоновом режиме, и необходимый сигнал не доходит до него. В результате Bash не обновляет LINES, и возникает путаница с расчётом текущей высоты терминала. Подобная ситуация может возникать и с другими программами, способными подозревать Bash в фоновый режим.
Несмотря на это, повторяя проблему в контролируемой среде, можно убедиться в том, как именно подобное поведение ведёт к печати статусной строки поверх строки ввода пользователя. Этот "клапан" происходит из-за того, что ваш механизм сравнения размеров терминала полагается на прежние и текущие значения LINES, которые, в данном случае, совпадают.
Применение
С учётом вышеописанных теоретических и практических моментов, возникают несколько возможных путей решения проблемы:
-
Использование периодического таймера для проверки изменений: Реализовать внешний демон или встроенный в ваш инструмент механизм, который будет периодически запрашивать фактические размеры терминала. Хотя это может несколько повысить нагрузку на систему или даже создать небольшие задержки, этот подход способен выявлять изменения размера, не завися от сигналов.
-
Обработка потенциальных изменений задним числом: Ввести логическую проверку, срабатывающую при возврате процесса на передний план, которая будет анализировать текущее состояние терминала и при обнаружении несоответствий инициировать мягкую перезагрузку статуса. В сочетании с другими эвристиками это может решить задачу без постоянных запросов терминала.
-
Модификация алгоритма обработки сигнала: Создать более сложный механизм обработки штатных и чрезвычайных ситуаций, используя сочетание переменных окружения и команд return для более полных проверок.
Таким образом, решение вашей проблемы требует балансирования множества аспектов, включая производительность и надёжность. Поскольку Баш находится в основе большинства UNIX-подобных систем, ваше расширение может задействовать дополнительные его функции для обеспечения более стабильной работы в случае отсутствия привилегий доступа к сигналу WINCH.
Проблема, с которой вы столкнулись, требует глубокого понимания механизма сигналов в UNIX и оптимизации программных алгоритмов, что обещает стать интересной исследовательской задачей в вашем будущем развитии Basta.