Existe uma maneira de determinar a face no quadro x / y (posição do mouse)?

8

Ao tentar tema de certos modos, não é possível colocar o ponto no item temático (por exemplo, fazer C-u C-x =) e identificar o rosto usado.

Meu pensamento é usar o mouse para identificar o rosto usado, mas tudo o que posso obter é o quadro x, posição y (usando (mouse-position))

A partir daí, não sei como obter a definição de rosto nessas cordas.

Qualquer ajuda é apreciada.

ocodo
fonte

Respostas:

4

Aqui está uma maneira. Você precisa vincular o comando a um evento do mouse. Mas se você clicar com o botão do mouse, provavelmente precisará vincular o evento para a outra parte do clique (por exemplo, para baixo) ignore. Este é apenas um exemplo - você pode não querer desperdiçar C-mouse1esse comando.

A principal função (comando, na verdade) é describe-char. Ele descreve o ponto em uma determinada posição de buffer. Parte dessa descrição inclui as propriedades de texto e as sobreposições nessa posição e, se a propriedade facefor uma delas, você verá seu valor.

(defun foo (event)
  (interactive "e")
  (let* ((mouse-pos  (event-start event))
         (pos-pt     (posn-point mouse-pos)))
    (describe-char pos-pt)))

(global-set-key [(control down-mouse-1)] 'ignore)
(global-set-key [(control mouse-1)] 'foo)

Isso pode ser um pouco melhor - o acima pode não funcionar em alguns contextos:

(defun foo (event)
  (interactive "e")
  (let* ((mouse-pos  (event-start event))
         (mouse-buf  (window-buffer (posn-window mouse-pos)))
         (pos-pt     (posn-point mouse-pos)))
    (with-current-buffer mouse-buf (describe-char pos-pt))))

(Observe também que isso C-x =está vinculado a what-cursor-position, que usa describe-char. Então você estava no caminho certo C-u C-x =.)


No que diz respeito ao Ido: Ao contrário do Icomplete, que usa uma sobreposição, o modo Ido insere texto no minibuffer. Mas a razão pela qual o código acima não funciona nesse texto é que o modo Ido remove o texto no início de cada comando, usando pre-command-hook. Portanto, quando o comando acima é executado, o texto que mostra as conclusões já foi removido.

O código a seguir soluciona esse problema, apenas no modo Ido. Ele reinsere o texto mostrando as conclusões no início e remove as conclusões no final.

(defun foo (event)
  (interactive "e")
  (when (and (boundp 'ido-mode)  ido-mode) (ido-exhibit))
  (let* ((mouse-pos  (event-start event))
         (mouse-buf  (window-buffer (posn-window mouse-pos)))
         (pos-pt     (posn-point mouse-pos)))
    (with-current-buffer mouse-buf (describe-char pos-pt)))
  (when (and (boundp 'ido-mode)  ido-mode) (ido-tidy)))
Desenhou
fonte
Bom, @drew muito apreciado
ocodo 27/10/2015
Oh, infelizmente, quando isso é usado no minibuffer com ido-vertical (e outros), a mensagem: describe-char: No character follows specified positioné retornada por descrevem-char. Eu acho que é devido ao minibuffer ser liberado em algum momento após o evento. Eu assumi que o 'ignoreiria parar com isso, mas isso não está acontecendo. Alguma ideia?
ocodo 27/10
Por favor, dê uma receita passo a passo. (Ele funciona para mim: M-x some-text, C-mouse-1em que texto no minibuffer.) Você deve, naturalmente, clique com o mouse em uma posição que tem texto. Se você clicar após o final do texto, receberá o erro mencionado.
Tirou
Use o modo ido-vertical ou o modo ido-grid com o modo ido, agora pressione a tecla Ctrl e clique no texto de seleção Ido no minibuffer. Erro.
ocodo 27/10
Ao clicar na lista de conclusões para o modo Ido ou Icomplete, você está clicando além do texto no buffer (minibuffer). Você está clicando em uma sobreposição (apenas). Se você clicar em uma sobreposição no topo do texto do buffer, não haverá problema, mas se você clicar além da extremidade do buffer (que é o que está fazendo), receberá a mensagem de erro.
Tirou
2

Se você não pode colocar o ponto no local e uso corretos C-u C-x =, pode ser devido ao fato de o elemento relevante ser exibido por meio de uma string antes / depois da sobreposição ou porque esse elemento desaparece / muda quando você tenta colocar o ponto ou quando você C-u C-x =.

Você pode tentar evitar esses problemas da seguinte maneira:

  • use posn-at-x-yque retornará uma descrição do que está nessa coordenada x / y. Por exemplo, se for um pedaço de texto retirado de uma sequência depois / antes, essa sequência será mencionada lá (assim como a posição dentro dessa sequência), para que você possa procurar a propriedade de face aplicada a essa sequência nessa posição.
  • você pode executar o código "em segundo plano" em vez de usar um comando. Por exemplo, com run-with-timervocê pode executar o código a cada segundo, imprimindo o resultado em algum tipo de buffer de depuração de sua escolha.
Stefan
fonte
1

Você pode usar o pacote com a face para cima para criar uma representação de texto legível por humanos, com informações sobre a face. Por exemplo:

(defun foo (arg)
  (if arg 1 2))

Execute M-x faceup-vire-buffer RETe o seguinte é mostrado:

(«k:defun» «f:foo» («v:arg»)
  («k:if» arg 1 2))

As faces de bloqueio de fonte padrão são representadas usando nomes abreviados, como kpara font-lock-keyword-face, enquanto as faces não padrão são apresentadas usando seu nome completo.

(Face para cima é um sistema de teste de regressão para destacar pacotes, por exemplo, palavras-chave de bloqueio de fonte, a representação de texto é armazenada como um arquivo de referência.)

EDITAR:

Para responder à pergunta no comentário: "Se estou tentando depurar os rostos usados ​​em uma exibição de minibuffer, isso ainda vai me dar as informações?"

Sim. No entanto, você deve vincular a função a uma chave, pois sua execução M-xnão funcionará quando o minibuffer estiver em uso. Por exemplo:

(global-set-key (kbd "<f6>") 'faceup-view-buffer)

Se você com o "minibuffer" realmente quis dizer a área de eco - é isso, gostaria de inspecionar a mensagem atual de que precisará um pouco mais. A seguinte função fará isso:

(defun my-faceup-view-current-message ()
  (interactive)
  (let ((msg (current-message)))
    (unless msg
      (error "Echo area is empty"))
    (with-temp-buffer
      (insert msg)
      (faceup-view-buffer))))

Por exemplo, o seguinte:

(let ((s "My Message"))
  (add-text-properties 3 (length s) '(face font-lock-warning-face) s)
  (message s)
  (my-faceup-view-current-message))

Irá mostrar-lhe:

My «w:Message»
Lindydancer
fonte
Se estou tentando depurar os rostos usados ​​em uma exibição de minibuffer, isso ainda vai me dar as informações?
Ocodo 27/10
@EmacsFodder Sim, veja minha resposta atualizada.
Lindydancer 27/10/2015
Para ser muito específico, o que me levou a fazer a pergunta foi tirar os rostos da ida-vertical e da ida-grade. Ambos liberam o buffer antes do evento do mouse (ao que parece).
ocodo 27/10
Embora tecnicamente a resposta direta à pergunta seja, você não pode. Esse método é um pouco mais fácil do que vasculhar o emacslisp de qualquer modo. Apesar de que é simples como: Cs defface Ms o
ocodo
1

Uma solução alternativa pode ser usar um seletor de cores e fornecer o valor da cor list-faces-for-colordefinido abaixo (caso o seletor de cores esteja um pouco desativado, use o argumento da distância):

(defun list-faces-for-color (color &optional distance)
  "List faces which use COLOR as fg or bg color.

            Accept colors within DISTANCE which defaults to 0."
  (interactive (list (read-color "Color: ")
                     (and current-prefix-arg
                          (prefix-numeric-value current-prefix-arg))))
  (with-help-window (get-buffer-create (format " *%s*" this-command))
    (dolist (face (sort
                   (list-faces--for-color color distance)
                   (lambda (f1 f2)
                     (string< (symbol-name f1)
                              (symbol-name f2)))))
      (list-faces--print-face face)
      (terpri))))

(defun list-faces--print-face (face)
  "Print face and its parents if any."
  (with-current-buffer standard-output
    (let ((fchain (cdr (list-faces--inheritance-chain face :foreground)))
          (bchain (cdr (list-faces--inheritance-chain face :background))))
      (insert (propertize (format "%s" face) 'face face))
      (cond (fchain
             (dolist (face fchain)
               (insert " > " (propertize (format "%s" face) 'face face))))
            (bchain
             (dolist (face bchain)
               (insert " > " (propertize (format "%s" face) 'face face))))))))

(defun list-faces--inheritance-chain (face attr)
  "Return inheritence change for face and attr."
  (let ((g (face-attribute face attr)))
    (if (and (stringp g)
             (not (string= "unspecified" g)))
        (list face)
      (let ((inherit (face-attribute face :inherit)))
        (when inherit
          (if (facep inherit)
              (cons face
                    (list-faces--inheritance-chain inherit attr))
            (if (consp inherit)
                (cl-dolist (face inherit)
                  (let ((res nil))
                    (when (and (facep face)
                               (setq res (list-faces--inheritance-chain face attr)))
                      (cl-return res)))))))))))


(defun list-faces--attribute (face attr)
  "Get face attribute of face as defined or inherited."
  (let* ((chain (list-faces--inheritance-chain face attr)))
    (cl-dolist (f (nreverse chain))
      (let ((g (face-attribute f attr)))
        (when (and (stringp g)
                   (not (string= "unspecified" g)))
          (cl-return g))))))



(defun list-faces--for-color (color &optional distance)
  "Return all faces with COLOR as fg or bg withing DISTANCE."
  (let ((faces ())
        (distance (or distance 0)))
    (mapatoms (lambda (atom)
                (when (facep atom)
                  (let ((fg (list-faces--attribute atom :foreground))
                        (bg (list-faces--attribute atom  :background)))
                    (when (or (and fg
                                   (<= (color-distance
                                        fg
                                        color)
                                       distance))
                              (and bg
                                   (<= (color-distance
                                        bg
                                        color)
                                       distance)))
                      (push atom faces))))))
    (delete-dups faces)))
clemera
fonte