1

I very much dislike the font faces I get for some modes. I know that I can customize them, but in some cases (e.g. org-mode) this would require customizing dozens of faces.

Therefore, what I really want to determine is, for a given character, where is its face, as it appears on the screen, defined? I'm hoping that this would lead me to a more efficient and maintainable way to fix the problem.

EDIT:

Here's an example of an approach that does not get me what I'm after: determine the name of a character's face (e.g. through M-x describe-char), and then invoke describe-face to see where the face is defined (supposedly).

When I do this I often arrive at definitions that are entirely at odds with what I see on the screen. This is why the question title emphasizes as it appears on the screen.

For example, if I invoke M-x describe-char when point is at an oversized orange character in my current buffer, the output I get tells me that its face is org-level-1. (FWIW, I get exactly the same result if I use M-: (get-char-property (point) 'face) or C-u C-x = instead.)

Now, the output of M-x describe-face for this face (org-level-1) includes the following:

Defined in `org-faces.el'.

           Family: Monaco
          Foundry: unspecified
            Width: unspecified
           Height: 1.3
           Weight: unspecified
            Slant: unspecified
       Foreground: #cb4b16
DistantForeground: unspecified
       Background: unspecified
        Underline: unspecified
         Overline: unspecified
   Strike-through: unspecified
              Box: unspecified
          Inverse: unspecified
          Stipple: unspecified
             Font: unspecified
          Fontset: unspecified
          Inherit: variable-pitch

This face specification, as far as it goes, pretty much matches what I see on the screen (though I don't know what variable-pitch means when applied to a fixed-width font like Monaco).

But if I follow the reference to org-faces.el, I find this

(defface org-level-1 ;; originally copied from font-lock-function-name-face
  (org-compatible-face 'outline-1
    '((((class color) (min-colors 88) (background light)) (:foreground "Blue1"))
      (((class color) (min-colors 88) (background dark)) (:foreground "LightSkyBlue"))
      (((class color) (min-colors 16) (background light)) (:foreground "Blue"))
      (((class color) (min-colors 16) (background dark)) (:foreground "LightSkyBlue"))
      (((class color) (min-colors 8)) (:foreground "blue" :bold t))
      (t (:bold t))))
  "Face used for level 1 headlines."
  :group 'org-faces)

Note that this definition bears little relation to the specification listed by describe-face. In particular, all the colors it mentions are shades of blue, nothing remotely like the color #cb4b16 reported by describe-face. In addition, it says nothing about any of the other spec items (Family, Height, Inherit) given explicit values in the output of describe-face.

This is why I emphasize that I'm not looking for the location of some "theoretical"/"nominal" definition of a named face, but the actual definition of the face that I'm seeing on the screen.

EDIT 2:

Digging deeper into the results described above, if I evaluate the following sub-expression in the definition of org-level-1

(org-compatible-face 'outline-1
    '((((class color) (min-colors 88) (background light)) (:foreground "Blue1"))
      (((class color) (min-colors 88) (background dark)) (:foreground "LightSkyBlue"))
      (((class color) (min-colors 16) (background light)) (:foreground "Blue"))
      (((class color) (min-colors 16) (background dark)) (:foreground "LightSkyBlue"))
      (((class color) (min-colors 8)) (:foreground "blue" :bold t))
      (t (:bold t))))

I get this

((t :inherit outline-1))

So I repeat the same wild-goose-chase with outline-1 in place of org-level-1. I find that it is defined in outline.el, as follows:

(defface outline-1
  '((t :inherit font-lock-function-name-face))
  "Level 1."
  :group 'outlines)

So, one more time, now with font-lock-function-name-face, defined in font-lock.el:

(defface font-lock-function-name-face
  '((((class color) (min-colors 88) (background light)) :foreground "Blue1")
    (((class color) (min-colors 88) (background dark))  :foreground "LightSkyBlue")
    (((class color) (min-colors 16) (background light)) :foreground "Blue")
    (((class color) (min-colors 16) (background dark))  :foreground "LightSkyBlue")
    (((class color) (min-colors 8)) :foreground "blue" :weight bold)
    (t :inverse-video t :weight bold))
  "Font Lock mode face used to highlight function names."
  :group 'font-lock-faces)

This seems to be the end of this tedious line, but the final definition is no closer to what I see on the screen.

  • 1
    Using ido, when I choose a command like make-face-bold, the first (default) completion is the face at the point. – asmeurer Feb 4 '15 at 20:26
  • 1
    M-x describe-face describes the current properties of the face. These can be adjusted by lots of factors, the most obvious one being your currently loaded theme (as seen with F1 v custom-enabled-themes). What you have traced are definitions that make up most of their properties, but don't contain these other factors. – wasamasa Feb 5 '15 at 15:45
2

Technically, the actual properties of a face is determined by a function called face-spec-recalc. It is based in the values of the symbol properties theme-face and face-override-spec. The former contains a list of all themes that you have applied that contribute to the face. (I'm not 100% what the latter does, but I think it contains user overrides.)

This function updates the actual face information of a frame.

In my project e2ansi (a package that renders font-lock buffers using ANSI sequences that provide syntax highlighting support for less), I reversed-engineered this so I can play the "what if" game (e.g. assuming that I have 16 colors and a dark background, what attributes would a face be given).

I guess that you could modify it so that it also would record the theme that provided each attributes.

  • I think your answer is probably the closest I'm going to get to what I'm after. Thanks. (BTW, very cool stuff in your repo.) – kjo Feb 5 '15 at 16:30
3

Do you really care where the face was (last) defined? (Why?)

I'm guessing that what you really want to know is what the current face definition is - each of the attributes.

For that, use C-u C-x = in front of a character that has the face you want to know about.

Or just use list-faces-display and compare appearances (if the appearance is not too common).

It is also the case often that once you know the name of the face you can find out where it is defined, if you really are interested in that. You can use M-x describe-face to find out where it was defined originally, at least.

  • 1
    Note that after C-x C-x = you can either move point to a face name and use M-x find-face-definition, or simply follow the built-in links -- the face name links to the describe-face screen, and from there (as Drew indicates) you get a link to the file (and line) which defined it. – phils Feb 5 '15 at 3:09
  • 1
    @phils Surely you meant C-u C-x =? – Harald Hanche-Olsen Feb 5 '15 at 10:09
  • Please see my EDIT. (BTW, regarding the question at the beginning of your answer: please grant posters the courtesy of assuming that they mean what they write. To do otherwise is not only rude, but also a waste of your time and everybody else's.) – kjo Feb 5 '15 at 14:53
  • +1 for what @wasamasa said in a comment. Which is why I asked whether (and why) you really want to know where the current appearance was set. In the general case, that is problematic: the face can be changed anywhere, whether via user customizations or on-the-fly code. There is really no way to know what last changed the face. This is similar to asking what last set a given variable's value. And no, no disrespect or rudeness was intended (or expressed, IMHO). We are trying to help you, not waste your time. You waste your own time (IMHO), if you try to find what last changed a face. – Drew Feb 5 '15 at 16:14
  • Harald Hanche-Olsen: Thanks, yes, that's exactly what I meant. I'm not sure how I managed to mis-type that (and not notice I'd done it). – phils Feb 5 '15 at 20:12
2

I think, it can be done.

(defun find-face-at-point (face)
  "Find the definition of FACE.

FACE defaults to the face used on the character at point."
  (interactive (list (get-char-property (point) 'face)))
  (find-function-do-it face 'defface 'switch-to-buffer))

In real life some argument checking should be added to this function.

  • That property can be a list of faces. – phils Feb 5 '15 at 3:21
  • +1 Thanks, I enjoyed working through your code snippet, but unfortunately it doesn't get to what I'm after. I've edited my post explaining why in detail. – kjo Feb 5 '15 at 14:47

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.