¿Hay alguna manera de determinar la cara en el cuadro x / y (posición del mouse)?

8

Cuando se trata de tema de ciertos modos, no es posible colocar el punto en el elemento temático (por ejemplo, hacer C-u C-x =) e identificar la cara utilizada.

Mi pensamiento es usar el mouse para identificar la cara utilizada, pero todo lo que puedo obtener es la posición x, y del marco (usando (mouse-position))

A partir de ahí, no sé cómo obtener la definición de la cara en esas coordenadas.

Cualquier ayuda es apreciada.

ocodo
fuente

Respuestas:

4

Aquí hay una manera. Debe vincular el comando a un evento del mouse. Pero si usa un clic del botón del mouse, entonces probablemente necesitará vincular el evento para la otra parte del clic (por ejemplo, hacia abajo) ignore. Este es solo un ejemplo: es posible que no desee desperdiciar C-mouse1en dicho comando.

La función principal (comando, en realidad) es describe-char. Describe el punto en una posición de amortiguación dada. Parte de esa descripción incluye las propiedades de texto y las superposiciones en esa posición, y si la propiedad facees una de estas, verá su 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)

Esto podría ser un poco mejor: lo anterior podría no funcionar en algunos 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))))

(Tenga en cuenta también que C-x =está vinculado a what-cursor-positionqué usos describe-char. Así que estaba en el camino correcto con C-u C-x =).


En cuanto a Ido: a diferencia de Icomplete, que utiliza una superposición, el modo Ido inserta texto en el minibúfer. Pero la razón por la que el código anterior no funciona en ese texto es que el modo Ido elimina el texto al comienzo de cada comando, usando pre-command-hook. Entonces, cuando se ejecuta el comando anterior, el texto que muestra las finalizaciones ya se ha eliminado.

El siguiente código soluciona ese problema, solo para el modo Ido. Vuelve a insertar el texto que muestra las finalizaciones al principio, y luego elimina las finalizaciones al 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)))
Dibujó
fuente
Nice one @drew muy apreciado
ocodo
Oh, desafortunadamente cuando esto se usa en el minibúfer con ido-vertical (y otros) el mensaje: describe-char: No character follows specified positiones devuelto por describe-char. Supongo que se debe a que el minibúfer se despejó en algún momento después del evento. Asumí 'ignoreque esto detendría esto, pero eso no está sucediendo. ¿Algunas ideas?
ocodo
Por favor, da una receta paso a paso. (Funciona para mí: M-x some-text, C-mouse-1en ese texto en el minibúfer.) Debe hacer clic en el ratón, por supuesto, en una posición que tiene texto. Si hace clic después del final del texto, obtiene el error que mencionó.
Dibujó el
Use el modo ido-vertical o el modo ido-grid con el modo ido, ahora Ctrl + clic en el texto de selección Ido en el minibúfer. Error.
ocodo
Cuando hace clic en la lista de finalizaciones para el modo Ido o Icomplete, hace clic más allá del texto en el búfer (minibúfer). Estás haciendo clic en una superposición (solo). Si hace clic en una superposición que está encima del texto del búfer, entonces no hay problema, pero si hace clic más allá del final del búfer (que es lo que está haciendo), recibirá el mensaje de error.
Dibujó
2

Si no puede colocar el punto en el lugar y uso correctos C-u C-x =, puede deberse al hecho de que el elemento relevante se muestra a través de una cadena anterior / posterior de una superposición, o porque ese elemento desaparece / cambia cuando intenta colocar el punto o cuando tu C-u C-x =.

Puede intentar evitar esos problemas de la siguiente manera:

  • use posn-at-x-ycual devolverá una descripción de lo que está en esa coordenada x / y. Por ejemplo, si se trata de un fragmento de texto tomado de una cadena after / before, esa cadena se mencionará allí (así como la posición dentro de esa cadena), para que pueda buscar la propiedad de la cara aplicada a esa cadena en esa posición.
  • puede ejecutar el código "en segundo plano" en lugar de hacerlo mediante un comando. Por ejemplo, con run-with-timerusted puede ejecutar el código cada segundo, imprimiendo el resultado en algún tipo de búfer de depuración de su elección.
Stefan
fuente
1

Puede usar el paquete cara arriba para crear una representación de texto legible por humanos de un texto, con información de la cara. Por ejemplo:

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

Ejecute M-x faceup-vire-buffer RET, y se muestra lo siguiente:

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

Las caras de bloqueo de fuente estándar se representan con nombres cortos, como kfor font-lock-keyword-face, mientras que las caras no estándar se presentan con su nombre completo.

(Faceup es un sistema de prueba de regresión para resaltar paquetes, por ejemplo, palabras clave de bloqueo de fuente, la representación de texto se almacena como un archivo de referencia).

EDITAR:

Para responder a la pregunta en el comentario: "Si estoy tratando de depurar las caras utilizadas en una pantalla de minibúfer, ¿esto todavía me dará la información?"

Si lo hace. Sin embargo, debe vincular la función a una tecla ya que ejecutarla usando M-xno funcionará cuando el minibúfer esté en uso. Por ejemplo:

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

Si por "minibúfer" realmente se refería al área de eco, es decir, le gustaría inspeccionar el mensaje actual que necesitará un poco más. La siguiente función hará esto:

(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 ejemplo, lo siguiente:

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

Te mostrará:

My «w:Message»
Lindydancer
fuente
Si estoy tratando de depurar las caras utilizadas en una pantalla de minibúfer, ¿esto todavía me dará la información?
ocodo
@EmacsFodder Sí, vea mi respuesta actualizada.
Lindydancer
Para ser muy específico, lo que me llevó a hacer la pregunta fue obtener las caras de ido-vertical y ido-grid. Ambos vacían el búfer antes del evento del mouse (parece).
ocodo
Aunque técnicamente la respuesta directa a la pregunta es, no puedes. Este método es un poco más fácil que buscar el emacslisp de cualquier modo. Aunque eso es simple como: Cs defface Ms o
ocodo
1

Una solución alternativa podría ser usar un selector de color y proporcionar el valor de color list-faces-for-colordefinido a continuación (en caso de que el selector de color esté un poco apagado, use el argumento de distancia):

(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
fuente