faceの情報取得

emacsの色の設定などを変更したかったので、カーソル位置の文字のfaceの情報を取得したかった。
現在位置のfaceは以下のようにして取得できる

(get-char-property (point) 'face)

取得したfaceから設定されている情報をみたい。
face-all-attributesという関数が存在した。
(でも、この関数は継承元まで読んでくれないみたい)*1

face.el中を見てみた

face-all-attributesはface-attributeを呼び出す際に、inherit(継承)の部分に値を渡していない*2

(defun face-all-attributes (face &optional frame)
  "Return an alist stating the attributes of FACE.
Each element of the result has the form (ATTR-NAME . ATTR-VALUE).
Normally the value describes the default attributes,
but if you specify FRAME, the value describes the attributes
of FACE on FRAME."
  (mapcar (lambda (pair)
	    (let ((attr (car pair)))
	      (cons attr (face-attribute face attr (or frame t)))));;<-ここ
  	  face-attribute-name-alist))

(defun face-attribute (face attribute &optional frame inherit) ;;<-このinheritがnil
  "Return the value of FACE's ATTRIBUTE on FRAME..."
...

元の関数に手をいれたくないなー。

自分で新しいface-all-attributesを作った方が良さそうだ。

以下元の関数との変更点

  • defaultで継承元まで探索して情報を取得するようにする。
    • defun*を使ってinheritの部分にdefault valueを指定しよう。
  • 出力先のリストに説明っぽい文字列も加える
    • attributeだけだとよく分からないし。
    • face-attribute-name-alistの初期値に説明っぽい文字列が入っているし

clパッケージの関数をどんどん使おう。

(defun* face-all-attributes* (face &optional frame (inherit t))
  (loop for (attr . desc) in face-attribute-name-alist
	collect `(,desc ,attr ,(face-attribute face attr frame inherit))))

これで現在位置のfaceの情報を表示する関数が作れる

作った関数

(defun get-current-face () (interactive)
  (let ((face (get-char-property (point) 'face)))
    (when face
      (with-output-to-temp-buffer "*current face*"
	(princ (format "%s\n\n" (pp-to-string face)))
	(pp (face-all-attributes* face nil t)))
      (with-current-buffer "*current face*"
	(call-interactively 'emacs-lisp-mode)))
      face))

faceのattributeに設定できる値を知りたければ,set-face-attributeを見ればいい。

*1:明らかに色がついているfaceに対しても、foregroundにunspecifiedという値が入ってしまう。

*2:自動的にnilになる