Maneiras de variar discretamente a renderização de texto?

12

Estou escrevendo uma extensão do emacs para uso com reconhecimento de fala e estou procurando ajuda com um recurso específico. Algumas palavras que o reconhecedor de fala (Dragão) reconhece consistentemente mal - não importa quantas vezes você o treine, será uma merda reconhecer algumas palavras. Ao mesmo tempo, normalmente, quando você estiver escrevendo sobre um tópico ou codificando, estará usando muitas das mesmas palavras repetidamente.

Então, eu escrevi um modo que usa sobreposições para alterar a forma como as palavras são renderizadas no buffer. Ele pega uma letra aleatória na palavra, a sublinha em uma cor aleatória e coloca uma marca diacrítica aleatória (acento, trema etc.) por cima dela. Aqui está uma captura de tela (você provavelmente precisará aumentar o zoom para ver marcas / sublinhados):

insira a descrição da imagem aqui

Então você pode dizer "cabelo p roxo" e ele procurará a palavra com um sublinhado roxo embaixo do 'a' com uma marca diacrítica que se parece com cabelo e digite essa palavra para você. Portanto, na captura de tela acima dizendo que faria com que o emacs digite "regexp-quote" para você.

A idéia é que isso permita que você se refira a qualquer palavra que você já tenha usado na tela usando um conjunto finito de palavras que o reconhecedor é sempre bom em reconhecer.

Funciona muito bem, exceto que ocasionalmente há uma colisão. Para fazer isso, eu posso aprender a me referir consistentemente às palavras da mesma maneira que estou usando bytes do hash md5 da palavra, em vez de (random)ou ter um algoritmo para atribuir as alterações, para evitar colisões. Encontrei apenas 6 cores facilmente distinguíveis (é difícil quando o sublinhado tem apenas um caractere de largura e um único pixel de espessura) e 3 marcas diacríticas facilmente distinguíveis (fáceis de distinguir uma da outra e também não podem ser confundidas com uma sublinhada acima) sobreposição ou sublinhado), visto na parte superior da fonte acima.

Preciso de mais maneiras de alterar a renderização para reduzir a frequência de colisão. Idealmente, uma modificação de renderização:

  • Não seja dissonante com o resto do texto. Isso me levou a descartar, por exemplo, a propriedade inverso-vídeo.
  • Não seja facilmente confundível com outras alterações. As sublinhadas são facilmente confundidas com as sublinhadas da linha anterior. Muitas marcas diacríticas parecem semelhantes, a menos que o tamanho da fonte seja impraticávelmente grande.
  • Esteja espacialmente próximo de onde estão as outras mudanças. No momento em que meu olho encontra o caractere alvo, todas as informações estão lá, o marcador, o sublinhado e a letra.
  • Trabalhe bem com uma fonte de largura fixa (necessária para a codificação) que renderize corretamente as marcas diacríticas (tive que mudar para o DejaVu Sans Mono da Consolas para que as marcas sejam renderizadas corretamente)
  • Trabalhar em letras do alfabeto latino. Existem marcas de combinação arábica, por exemplo, mas elas não combinam nos caracteres do alfabeto latino.
  • Não altere a cor da letra, pois ela já está sendo usada para realçar a sintaxe.
  • Seja factível no emacs com o emacs lisp;)

Talvez haja caracteres unicode especiais controlando a renderização que possam ser abusados ​​para abrir novas possibilidades? Ou uma maneira de engrossar os sublinhados para poder distinguir facilmente mais cores? Ou algum outro recurso obscuro do emacs que permite renderizar marcas sobre os caracteres, além do unicode?

Joseph Garvin
fonte
Não é uma resposta direta à sua pergunta, mas talvez algumas idéias usando sobreposições para dar aparência a novos personagens. Uma idéia seria concat / sanduíche duas sobreposições - forçando-as a se encaixar no mesmo espaço que um caractere comum - por exemplo, o primeiro caractere é uma linha fina com a cor adicionada (char-to-string ?\uFEFF)e o outro é um caractere de destino reduzido em tamanho para que ambos se encaixem. Outra idéia seria usar uma passagem vertical (disponível em algumas fontes, mas não em todas) semelhante ao que é usado na biblioteca vline.el emacswiki.org/emacs/VlineMode
lawlist
@lawlist: Essa ideia de linha unicode é interessante, me deixaria fazer uma 'linha lateral'. Você tem alguma idéia de como reduzir o tamanho do seguinte personagem? Talvez eu pudesse gerar uma imagem para uso com a propriedade display, mas AFAICT não há como fazer o emacs renderizar texto em uma imagem, então eu teria que fazer as imagens fora do emacs.
Joseph Garvin
Este comentário substitui o comentário anterior (que eu removi) e o código no link a seguir também foi atualizado - ele contém três exemplos (um dos quais é idêntico à resposta que eu publiquei abaixo no thread atual): stackoverflow .com / questions / 23744237 /…
lawlist

Respostas:

4

Outra possibilidade seria exibir os números das linhas e dizer o número da linha antes da palavra, ou, como olhar para obter o número exato da linha seria incômodo, você poderia fazer a pesquisa do algoritmo entre + ou - 5 ou 10 linhas do número que você deseja. dizer.

Ou, talvez, declare uma região ou função em que você está trabalhando e todas as pesquisas apenas procurem lá. Eu acho que isso limitaria colisões.

Você também pode renderizar símbolos unicode antes ou depois de uma palavra em uma determinada cor para ajudá-los a se destacar. E também coloque ou sublinhe a palavra em outra cor. Dessa forma, você pode ter 6 cores de palavras * 6 cores de símbolos * N possibilidades de símbolos. Você provavelmente poderia encontrar 10 símbolos bons e ter 360 combinações. Por exemplo, você pode dizer "estrela azul amarela" para se referir à palavra gato aqui.

insira a descrição da imagem aqui

Se a estrela é muito chocante, você pode acoplar: caixa e duas diferentes: sublinhados.

Portanto, você pode consultar a palavra árvore aqui usando "azul amarelo vermelho", o que forneceria 216 combinações para usar.

insira a descrição da imagem aqui

Jordon Biondo
fonte
1
Esperei um pouco para ver se alguém sugeriria outros truques, mas provavelmente vou usar a cor de sublinhado duplo, pois a adição de símbolos pode causar recuo. Aceito, obrigado.
Joseph Garvin
2

Você já ouviu falar do modo ás-salto ?

Ele não atende a nenhum dos requisitos especificados, mas parece que se encaixa perfeitamente no que você está tentando alcançar. Isso permitiria ao usuário especificar qualquer palavra dizendo apenas 2 ou 3 palavras.

Você pode definir o conjunto de caracteres que ele oferece, para evitar consoantes difíceis de distinguir. Em seguida, o uso pode apenas dizer "corrigir A nove" e corrigir a 9ª palavra que começa com a.

Malabarba
fonte
Veja meu comentário no post de tmalsburg para saber por que o ace-jump-mode não deu certo.
Joseph Garvin
1

Pergunta interessante. Aposto que você receberá algumas sugestões interessantes.

Uma sugestão menor que me ocorre é usar cores e estilos diferentes para sublinhar. Consulte o manual Elisp, nó Face Attributescerca de atributo :underlinee seu :colore:style componentes.

Você também pode experimentar atributos :boxe larguras de linha e estilos diferentes, mas isso pode ser muito chocante.

Desenhou
fonte
1

Responderei propondo uma maneira alternativa de selecionar a palavra de destino. Destaque metade das palavras (escolhidas aleatoriamente). O usuário diz "sim" se a palavra de destino estiver destacada e "não" caso contrário. Se o usuário disse "sim", pegue todas as palavras destacadas e destaque aleatoriamente metade delas. Se o usuário disser "não", destaque aleatoriamente a metade das palavras que não foram destacadas. Novamente, o usuário indica se a palavra de destino está destacada dizendo "sim" ou "não". Repita isso até que apenas a palavra de destino seja destacada.

Alguns benefícios dessa abordagem:

  • Isso funciona, não importa quantas palavras você tenha na tela.
  • Você não precisa de cores, fontes ou símbolos sofisticados. Uma tela monocromática é suficiente.
  • Carga cognitiva muito baixa porque é fácil saber se uma palavra está destacada ou não.

Desvantagem: você deve dizer "sim" e "não" com muita frequência. No entanto, isso é corrigido pela seguinte variação da ideia: não destaque as palavras, mas use cores para elas. Você diz que possui 6 cores facilmente distinguíveis. Isso significa que, se você tiver 100 palavras na tela, selecionar a palavra de destino exige nomear 2,6 cores em média. Se houver 1000 palavras, é necessário nomear 3,9 cores em média.

Tmalsburg
fonte
1
Infelizmente, o número de palavras faladas é uma métrica enganosa. O problema desse estilo de solução é que ele contém viagens de ida e volta de percepção / ação. Eu tenho que ver a cor, depois reagir, depois ver, reagir, ver. Dizer três palavras sem ter que parar para procurar entre cada uma deve ser mais rápido na prática do que uma solução onde você faz, especialmente com Dragon com baixa latência. Se essas viagens de ida e volta não fossem um problema, eu apenas usaria o modo ás-salto. Com as marcas diacríticas, posso olhar para a tela uma vez e conhecer toda a sequência do que preciso dizer sem ter que fazer uma pausa para que Dragon reaja após cada palavra.
Joseph Garvin
1

A seguir, é apresentado um exemplo usando uma sobreposição com uma imagem xpm para versões gráficas do Emacs compatíveis com o formato de imagem xpm. Tem 11 pixels de largura; 20 pixels de altura; e tem um número especificado pelo usuário de 4 cores possíveis. Estou em um Mac executando o Snow Leopard 10.6.8 e a fonte que prefiro ao usar o Emacs é -*-Courier-normal-normal-normal-*-18-*-*-*-m-0-iso10646-1- frame-char-widthé 11 e frame-char-heighté 20. Adicionei uma fina linha vertical amarela à esquerda da letra maiúscula "A" como exemplo de como desenhar imagens personalizadas. A substituição do caractere no ponto pode ser feita programaticamente usando (char-after (point))e tomando esse número - que neste caso é 65 pela letra maiúscula "A" - e substituindo a variável apropriada - por exemplo, (cond ((eq (char-after (point)) 65) cap-ltr-a-xpm) . . .- e usando essa variável no campo posicionamento da sobreposição - por exemplo,(overlay-put (make-overlay (point) (1+ (point))) 'display cap-ltr-a-xpm) . Isso funciona muito bem para buffers truncados e também com quebra de linha porque odisplayA propriedade overlay em um caractere no meio de uma palavra não faz com que a quebra de linha pense que a primeira parte da palavra pertence ao final da linha anterior. Obviamente, levará tempo para criar uma biblioteca personalizada de imagens xpm favoritas.

O ImageMagick é capaz de produzir um xpm semi-preciso de um caractere específico com base em uma família e tamanho de fonte específicos, mas não foi tão preciso quanto eu esperava - aqui está um link para instruções de uso desse utilitário externo: https: / /stackoverflow.com/a/14168154/2112489 Em poucas palavras, o usuário deve estar preparado para gastar tempo personalizando as imagens xpm ao seu gosto.

(defun xpm-example ()
(interactive)
"Doc-string"
  (let* (
      (cap-ltr-a-xpm `(image :type xpm :mask nil :ascent center :data
        "/* XPM */
        static char * letters_xpm[] = {
        /* columns rows colors chars-per-pixel */
        /* columns = 1 pixel in width -- see also (frame-char-width) */
        /* rows = 1 pixel in height -- see also (frame-char-height) */
        \"11 20 4 1\",
        \". c #000000\",
        \"+ c #FF0000\",
        \"@ c #7F0000\",
        \"% c yellow\",
        \"%..........\",
        \"%....++....\",
        \"%....++....\",
        \"%..++..++..\",
        \"%..++..++..\",
        \"%++......++\",
        \"%++......++\",
        \"%++......++\",
        \"%++......++\",
        \"%++......++\",
        \"%++......++\",
        \"%++++++++++\",
        \"%++++++++++\",
        \"%++......++\",
        \"%++......++\",
        \"%++......++\",
        \"%++......++\",
        \"%++......++\",
        \"%++......++\",
        \"%..........\"};"))  )
    (overlay-put (make-overlay (point) (1+ (point))) 'display cap-ltr-a-xpm)))
lista de leis
fonte
@wasamasa - obrigado - removi a declaração incorreta referente aos bitmaps XBM.
lawlist