Eu mantenho uma extensão para o ambiente Bash chamada Basta . Basta fornece uma linha de status protegida por rolagem na parte inferior do seu terminal ANSI/VT100.
Quando o Basta se configura, o número efetivo de linhas, como conhecido pelo material termios no kernel e a LINES
variável shell diminui em 1. O redimensionamento do terminal é tratado bem. Quase. Há trap
um SIGWINCH
sinal para chamar a rotina de atualização, que também é chamada após cada comando, antes de retornar ao prompt.
No entanto, de vez em quando, vejo uma situação em que a região de rolagem é perdida. O prompt está sendo pintado sobre a linha inferior, onde o usuário está editando comandos e onde a saída do comando aparece, resultando em uma bagunça.
Tenho uma hipótese sobre como isso pode ocorrer, que tem etapas de reprodução confiáveis.
Executamos um programa que aguarda entrada, enquanto o Bash está em segundo plano, como
cat
.Enquanto o programa estiver em execução, redimensionamos a janela para reduzi-la em uma linha.
Encerrar o
cat
programa.
Se o terminal for redimensionado enquanto cat
estiver em execução, o Bash não obtém o SIGWINCH
(porque, eu acho, SIGWINCH
é enviado apenas para os processos no grupo de processos em primeiro plano das sessões do terminal, e o Bash está em segundo plano naquele momento). Nosso trap
não executa.
A função de atualização do Basta também depende da comparação do tamanho do terminal anterior com o atual para detectar uma alteração de tamanho.
Aqui está o problema: nesta situação em que um terminal com um status protegido contra rolagem como encolheu em uma linha, o número de linhas parece não ter mudado .
Por exemplo, tela de 40 linhas com região de rolagem de 39 linhas: LINES=39
. Redimensione o terminal para ter 39 linhas de comprimento. A região de rolagem desapareceu. LINES=39
de novo. Para o software, parece o mesmo tamanho, então ele conclui que não houve um redimensionamento. A linha de status agora está sendo pintada sobre a linha inferior, sobre a entrada do usuário, porque Basta quer colocá-la na linha 40, que não existe mais, então o cursor se fixa em 39.
Se Basta souber que uma mudança de tamanho de janela ocorreu, ele não fará a comparação de tamanho; nessa situação, ele pega o caminho lento, pelo qual ele consulta o próprio terminal para determinar o tamanho. (Seria indesejável fazer isso para cada atualização, porque enviar consultas para o terminal é duvidoso. Se o usuário estiver digitando rapidamente, a resposta do terminal pode se misturar com suas teclas, e pode haver um atraso perceptível em obter uma resposta do terminal em conexões remotas lentas.)
Existe alguma maneira inteligente de saber se o terminal mudou (ou pelo menos suspeitar disso com uma taxa de falsos positivos razoavelmente baixa), na ausência de ter recebido a WINCH
armadilha, devido a ter estado em segundo plano, sem falar com o terminal?
Existe algum motivo para basta.query_terminal_lines não funcionar?
Ou, para aqueles que não leram o código "basta":
Existe alguma razão pela qual você não pode: salvar a posição do cursor no terminal (
ESC 7
), mover o cursor para a linha inferior (ESC [ 9 9 9 9 ; 9 9 9 9 H
), consultar a posição do cursor (ESC [ 6 n
), restaurar a posição do cursor (ESC 8
) e então ler a sequência de escape enviada pela consulta?Isso acaba sendo uma maneira custosa, mas eficaz, de obter o tamanho atual da tela quando se alteram os valores armazenados internamente. Parte do motivo pelo qual isso funciona é que o movimento explícito do cursor ignora a região de rolagem em terminais estilo ansi/xterm/... (Acho que usei um terminal diferente que não fazia isso.)
Note que o número 9999 precisa ser maior do que a tela poderia ser. Com um novo display de 7680 × 4320 e a fonte "nil2", a janela poderia ter 2160 linhas e 7680 colunas. (E isso não conta o Xinerama, ou janelas muito grandes para serem exibidas.) 9999 pode não ser grande o suficiente por muito tempo.