Detectar quanto de Unicode meu terminal suporta, mesmo através da tela

10

Aqui está o problema: quero discernir se meu terminal é capaz de unicode decente ou não, a fim de usar alguns caracteres ou não, assim como os relances, que às vezes usa cores e outros sublinhados.

A motivação surge porque em qualquer tipo de terminal virtual recebo fontes decentes, mas entendo que o console básico do Linux possui um conjunto de caracteres de 256 ou 512 símbolos simultâneos, portanto você não pode esperar um suporte completo à fonte.

No começo eu pensei que poderia usar $TERMou tty, mas aqui está o problema: estou usando byobu também, então $TERMsempre é "screen.linux". A saída de tty também não é muito reveladora: /dev/pts/<some number>em termos "reais" e virtuais.

$BYOBU_TTYtambém não ajuda, porque, por exemplo, pode ser /dev/tty1e quando a sessão é aberta em Ctrl+ Alt+, F1os caracteres não são exibidos, mas ao serem anexados à mesma sessão a partir de um termo X, eles são exibidos corretamente e ainda $BYOBU_TTYnão são alterados. Além disso, eu gostaria de poder detectar isso sem presumir que o byobu esteja lá ou não.

Além disso, a localidade é exibida em todos os casos en_US.UTF-8

No entanto, de alguma forma, olha (para citar uma ferramenta específica que vejo detectando isso), mesmo dentro do byobu, usa saída diferente dependendo do terminal que estou anexando à sessão do byobu.

Estou tendo problemas com o google porque terminal e tty parecem termos de pesquisa muito comuns. No máximo, chego a soluções recomendando $TERMou tty.

Álex
fonte

Respostas:

6

Bem, primeiro eu acho que gostaria de salientar que praticamente todos os terminais hoje em dia são "virtuais" no sentido em que você fala ... mesmo se o terminal estiver na outra extremidade de uma porta serial de boa-fé. Quero dizer, os dias do VT-100 s, terminais Wyse e outros terminais "físicos" e "reais" se foram!

Além disso, digamos que você queira detectar que tipo de suporte Unicode o seu terminal possui. Você pode fazer isso escrevendo caracteres de teste em is e vendo o que acontece. (Você pode fazer um esforço para apagar os caracteres de teste depois de escrever, mas o usuário ainda poderá vê-los brevemente ou apagá-los pode não funcionar corretamente em primeiro lugar.)

A idéia é pedir ao terminal para informar sua posição do cursor, emitir um caractere de teste, pedir ao terminal novamente para informar sua posição e comparar as duas posições para ver a que distância o cursor do terminal se moveu.

Para solicitar a posição do terminal, consulte aqui . Essencialmente:

echo -e "\033[6n"; read -d R foo; echo -en "\nCurrent position: "; echo $foo | cut -d \[ -f 2

Tente emitir "é". Esse caractere ocupa 2 bytes em UTF-8, mas é exibido em apenas uma coluna na tela. Se você detectar que a saída "é" faz com que o cursor se mova em 2 posições, o terminal não tem suporte a UTF-8 e provavelmente produziu algum tipo de lixo. Se o cursor não se moveu, então o terminal provavelmente é apenas ASCII. Se movido por 1 posição, parabéns, provavelmente poderá exibir palavras em francês.

Tente imprimir "あ". Esse caractere ocupa 3 bytes em UTF-8, mas é exibido em apenas duas colunas na tela. Se o cursor se mover por 0 ou 3, más notícias são semelhantes às anteriores. Se passar 1, parece que o terminal suporta UTF-8, mas não conhece caracteres largos (em fontes de largura fixa). Se ele se move por 2 colunas, tudo está bem.

Tenho certeza de que existem outros caracteres de análise que você pode emitir, o que levaria a informações úteis. Não conheço uma ferramenta que faça isso automaticamente.

Celada
fonte
1
Obrigado pela sugestão, Celada. No entanto, não está funcionando: vejo corretamente as posições avançadas (1 para é, 2 para あ). A única diferença é que dentro de XI vejo os personagens reais, enquanto em tty1 vejo um diamante. Então eu acho que o terminal realmente suporta utf-8, mas não possui o caractere na fonte que está sendo usada.
Álex 12/02
Eu já vi o comando showconsolefont. Essa parecia uma solução possível (com -v informa que a fonte possui 512 caracteres). Infelizmente, ele só funciona quando não estiver usando byobu. Neste último caso, ele erra com "Não foi possível obter um descritor de arquivo referente ao console". Se eu passar explicitamente o tty (opção -C), o erro se tornará "Não foi possível abrir / dev / pts / 37"
Álex
By the way: script sh para determinar a largura do terminal de uma string (mas não é disso que se trata)
Gilles 'SO- stop be evil'
3

A pergunta real do OP é: quais valores Unicode o console Linux suporta e quais podem ser detectados durante a execução screen. Em princípio, pode-se fazer isso recuperando o mapa Unicode para o console.

A kbdárvore de origem contém getunimap(e sua página de manual). A página do manual diz que

O programa getunimap é antigo e obsoleto. Agora faz parte do setfont

o que não é exatamente verdade. setfonttem uma opção que faz aproximadamente a mesma coisa:

   -ou file                                  
          Save previous Unicode map in file

As diferenças:

  • setfontgrava em um arquivo, enquanto getunimapgrava na saída padrão
  • getunimap mostra o caractere que seria mapeado, como um comentário.

Por exemplo:

0x0c4   U+2500  # ─ 
0x0c4   U+2501  # ━ 
0x0b3   U+2502  # │ 
0x0b3   U+2503  # ┃ 
0x0da   U+250c  # ┌ 
0x0da   U+250d  # ┍ 
0x0da   U+250e  # ┎ 
0x0da   U+250f  # ┏ 
0x0bf   U+2510  # ┐ 
0x0bf   U+2511  # ┑ 
0x0bf   U+2512  # ┒ 
0x0bf   U+2513  # ┓ 
0x0c0   U+2514  # └ 
0x0c0   U+2515  # ┕ 
0x0c0   U+2516  # ┖ 
0x0c0   U+2517  # ┗ 

versus

0xc4    U+2500
0xc4    U+2501
0xb3    U+2502
0xb3    U+2503
0xda    U+250c
0xda    U+250d
0xda    U+250e
0xda    U+250f
0xbf    U+2510
0xbf    U+2511
0xbf    U+2512
0xbf    U+2513
0xc0    U+2514
0xc0    U+2515
0xc0    U+2516
0xc0    U+2517

Se você estiver executando screen(ou, por exemplo, executando xterme não no console), você receberá um erro de permissão, que poderá ser solucionado usando sudo.

Se eu souber qual fonte foi carregada, posso verificar isso (sem permissões especiais) usando psfgettable, por exemplo,

zcat /usr/share/consolefonts/Lat2-Fixed16.psf.gz | psfgettable -

e veja os dados de mapeamento que setfontseriam usados ​​para carregar a fonte (com o mapeamento Unicode):

#
# Character table extracted from font -
#
0x000   U+00a9
0x001   U+00ae
0x002   U+00dd
0x003   U+0104
0x004   U+2666 U+25c8 U+fffd
0x005   U+0105
0x006   U+0111
0x007   U+0150
0x008   U+0151
0x009   U+0162
0x00a   U+0164
0x00b   U+0170
0x00c   U+0171
0x00d   U+021a 
0x00e   U+02dd  
0x00f   U+2014 U+2015
0x010   U+2020
0x011   U+2021
0x012   U+2022 U+25cf
...

Ambos getunimape setfontdar os dados não separadas, enquanto que psfgettableparece ser classificados (bem como uma combinação de linhas de valores de Unicode que mapeiam para o mesmo glifo). Portanto, existem diferenças, mas a informação está acessível.

Leitura adicional (ilustrando por que você não pode usar showconsolefontpara resolver esse problema):

Thomas Dickey
fonte
Obrigado, Thomas, por esclarecer minha pergunta original e por me colocar no caminho certo. Vou tentar obter uma linha simples de suas informações e voltar com os resultados. Usar sudonão é obstáculo para o meu caso de uso.
Álex
Agora, isso é curioso: setfontnão gera nada (não cria o arquivo especificado nem gera um erro) nos terminais virtuais, mas funciona nos terminais reais conforme o esperado. Isto está no Ubuntu 16.04
Álex
2

Me deparei com essa pergunta enquanto tentava realizar a mesma coisa, mas não queria deixar nada na tela e definir uma variável, então coloquei o seguinte em um script de shell que forneço:

function test_unicode {
  echo -ne "\xe2\x88\xb4\033[6n\033[1K\r"
  read -d R foo
  echo -ne "\033[1K\r"
  echo -e "${foo}" | cut -d \[ -f 2 | cut -d";" -f 2 | (
    read UNICODE
    [ $UNICODE -eq 2 ] && return 0
    [ $UNICODE -ne 2 ] && return 1
  )
}

test_unicode
RC=$?
export UNICODE_SUPPORT=`[ $RC -eq 0 ] && echo "Y" || echo "N"`
unset test_unicode
Jeff
fonte
1
Obrigado pela contribuição, Jeff. Infelizmente, eu sempre recebo Y, mesmo no console básico: S
Álex