Como as linhas de comando longas ($ COLUMNS) são automaticamente agrupadas em uma nova linha?

0

Existem vários pontos pelos quais a E / S é passada, alguns dos quais (que eu saiba) são o shell, pty, tty, termios, aplicação de emulador de terminal. Na maioria dos emuladores de terminal, longas linhas de comando (aquelas que excedem o valor atual de $ COLUMNS) são agrupadas em uma nova linha antes que o usuário envie o comando pressionando Enter. Além disso, a linha é retrocedida para a linha acima quando o número apropriado de caracteres é removido da linha de comando como seria de esperar.

Minha pergunta é: onde esta magia geralmente é tratada? É uma configuração do termios, ou parte do shell, ou o aplicativo emulador de terminal é responsável por isso?

Para mais contexto, eu estou usando o aplicativo emulador de terminal Terminator no Ubuntu - onde o linewrapping funciona perfeitamente (então não deve haver problemas com o meu prompt $ PS1). Mas estou trabalhando em meu próprio aplicativo de emulador de terminal que funciona com um spawner do go pty (github.com/kr/pty) e estou tendo problemas em que linhas longas não são agrupadas em uma nova linha, mas o início da linha mesma linha.

    
por Crunchex 14.04.2015 / 00:34

2 respostas

4

In most terminal emulators, long command lines […] are wrapped to a new line before the user submits the command by pressing Enter.

Esta não é uma função do emulador de terminal.

É uma função do seu shell. Seu shell não é um aplicativo de tela cheia, mas está fazendo endereçamento de cursor .

Quando você está editando uma linha de comando em um shell, a biblioteca de edição de linha no shell está com a carga total de como a linha que está sendo editada é exibida. No shell Bourne Again, esta é a biblioteca readline do GNU. O shell Almquist usa o libedit. Outros shells, como o Z Shell, possuem suas próprias bibliotecas.

Essas bibliotecas são colocadas sobre as bibliotecas termcap / terminfo, que registram os recursos do terminal do emulador de terminal. Esses recursos incluem, entre outras coisas, as seqüências de controle para posicionar o cursor em termos relativos ou absolutos, as seqüências para limpeza até o final da linha e o final da tela, e se o terminal possui ou não margens automáticas em>.

Com isso e informações sobre a largura do terminal determinada a partir do TIOCGWINSZ ioctl (voltando para a variável COLUMNS para algumas bibliotecas, ou o banco de dados termcap / terminfo para outros) em mãos, a edição de linha A biblioteca no shell rastreia o comprimento da linha de comando e quantas linhas de terminal são exibidas. Ele inteligentemente move o cursor para repintar a linha de entrada à medida que ela é editada. Às vezes, pode confiar nas margens automáticas, se o seu terminal as tiver. Às vezes, ele pode reposicionar explicitamente o cursor usando sequências de controle.

O fato de estar fazendo isso é o que causa efeitos como os discutidos no link . Alguém pode atrapalhar a idéia de onde o cursor está e quais movimentos de cursor ele precisa emitir para gravar em um local específico na tela, com sequências de controle delimitadas incorretamente em uma string de prompt.

Seu emulador de terminal não trata das noções de linhas de comando ou edição de linha. Não faz parte dessas camadas. Ele vê um fluxo simples de caracteres e seqüências de controle, que ele deve renderizar. É de sua responsabilidade do emulador de terminal implementar as seqüências de controle que são anunciadas para ele em sua entrada termcap / terminfo. A linha de leitura do GNU, libedit, ZLE, vim , screen e outros usarão o que encontrarem anunciado. Se você declarar em termcap / terminfo que seu terminal tem margens automáticas, por exemplo, o emulador deve fazer uma quebra de linha quando um caractere é impresso na margem direita. Se você afirmar que o seu terminal pode mover o cursor para cima e para baixo, então ele deve fazer isso quando receber as seqüências de controle apropriadas.

A propósito: Se a linha de leitura do GNU achar que não pode mover o cursor para cima, porque a entrada termcap / terminfo não indica uma maneira de fazer isso, não se vê realmente a quebra de linha. readline volta para um modo em que ele rola lateralmente a linha de entrada, tudo em uma linha.

    
por 14.04.2015 / 20:13
2

O terminal [emulador] é responsável por isso. Mover para a primeira coluna da próxima linha é exatamente o que o terminal faz depois de preencher a última posição em uma linha.

Você pode ver facilmente que não é o shell fazendo isso inserindo cat e digitando algumas linhas longas. Shells como bash e zsh de fato rastreiam a posição do cursor e o número de colunas que eles acreditam que o terminal tem e saem várias seqüências de controle de terminal nas extremidades das linhas, mas apenas para que possam implementar algumas de suas linhas de edição mais extravagantes recursos (como prompts do lado direito, rolagem horizontal, exibição e exclusão de menus de preenchimento de guias, reescrever / atualizar a linha atual, etc ...). O envolvimento da linha ainda aconteceria se eles não fizessem isso.

A camada tty também pode ter conhecimento do tamanho da tela, mas, novamente, não é usada para garantir que a quebra de linha ocorra.

Se o seu terminal não fizer isso, é um bug no seu terminal.

    
por 14.04.2015 / 14:40