Em um emulador de terminal, pode-se usar o relatório de posição do cursor para obter posições antes / depois, por exemplo, de
...record position
printf '%s' $string
...record position
e descubra a largura dos caracteres impressos no terminal. Como essa é uma seqüência de controle ECMA-48 (bem como VT100) suportada por quase todos os terminais que você provavelmente usará, ela é bastante portátil.
Para referência
-
Sequências de controle do XTerm
CSI Ps n Device Status Report (DSR). ... Ps = 6 -> Report Cursor Position (CPR) [row;column]. Result is CSI r ; c R
Por fim, o emulador de terminal determina a largura imprimível devido a esses fatores:
- as configurações do local afetam a maneira como uma string pode ser formatada, mas a série de bytes enviados ao terminal é interpretada com base em como o terminal é configurado (observando que algumas pessoas argumentarão que ele precisa ser UTF-8) a outra mão portabilidade foi o recurso solicitado na questão).
-
wcswidth
sozinho não informa como os caracteres combinados são manipulados; O POSIX não menciona este aspecto na descrição dessa função. - alguns caracteres (desenho de linha, por exemplo), que pode ser considerado como largura única (em Unicode) "largura ambígua", solapando a portabilidade de um aplicativo usando
wcswidth
sozinho (veja por exemplo Capítulo 2. Configurando o Cygwin ). Por exemplo,xterm
tem provisão para selecionar caracteres de largura dupla para configurações necessárias. - para manipular qualquer coisa que não sejam caracteres imprimíveis, você teria que confiar no emulador de terminal (a menos que você queira simular isso).
As APIs do Shell que chamam wcswidth
são suportadas em graus variados:
-
Text :: CharWidth - Obtém o número de colunas ocupadas de uma string no terminal
This module supplies features similar as wcwidth(3) and wcswidth(3) in C language.
- discussão para Ruby
- API para Python
São mais ou menos diretos: simulando wcswidth
no caso de Perl, chamando o tempo de execução C de Ruby e Python. Você poderia até mesmo usar palavrões, por exemplo, do Python (que lidaria com caracteres combinados):
- inicialize o terminal usando setupterm (nenhum texto é gravado na tela)
- use a função
filter
(para linhas únicas) - desenhe o texto no início da linha com
addstr
, verificação de erro (no caso de ser muito longo) e, em seguida, para a posição final - se houver espaço, ajuste a posição inicial.
- chame
endwin
(que não deve fazer arefresh
) - escreva as informações resultantes sobre a posição inicial na saída padrão
O uso de palavrões para saída (ao invés de alimentar as informações de volta a um script ou chamar diretamente tput
) limparia toda a linha ( filter
o limitaria a uma linha). p>