Emacs: buffer-local faces (face-remap-add-relative)
Raw link: https://www.youtube.com/watch?v=zt0sCpA1Q54
In this video presentation, I demonstrate how to change Emacs faces only in specific contexts instead of using the standard methods which modify their global value.
Context-dependent faces give us the freedom to particularise the presentation of certain interfaces or major-modes. I am already implementing those ideas in my LIN package: https://protesilaos.com/emacs/lin.
The code I use starts from the basics and culminates in the creation of
a minor-mode that can be invoked with
M-x or via hooks. It covers all
you need to get started. Such techniques are also discussed in the
manual of my
modus-themes package (built into Emacs 28 or higher):
Below is the code I used for the demo:
;; This is what we will be using: (face-remap-add-relative SOURCE DEST) ;; To find the face at point, use M-x describe-char or type C-u C-x = ;; ;; To learn about all available faces from the loaded packages on your ;; system, use M-x list-faces-display ;; ;; Create a disposable buffer and evaluate the following (you'll soon ;; learn why a disposable buffer is needed): (face-remap-add-relative 'font-lock-comment-face 'error) ;; The problem with what I just showed is that we cannot undo the ;; remapping with the code we used. ;; ;; The `face-remap-add-relative' returns what is known as a "cookie". ;; To revert the changes we need to know the cookie. So we must store ;; that cookie in a variable. (defvar-local my-comment-remap-cookie nil "Cookie of the last `face-remap-add-relative'.") (setq my-comment-remap-cookie (face-remap-add-relative 'font-lock-comment-face 'error)) ;; Now use `face-remap-remove-relative' on the cookie. (face-remap-remove-relative my-comment-remap-cookie) ;; Let's now write our own face instead of relying on existing ones ;; (those may change and/or they may not suit our particular ;; requirements). (defface my-comment-remap-style '((default :inherit italic) (((class color) (min-colors 88) (background light)) :foreground "#904200") (((class color) (min-colors 88) (background dark)) :foreground "#fba849") (t :foreground "yellow")) "Yellow-tinted text with slanted font (italics).") (setq my-comment-remap-cookie (face-remap-add-relative 'font-lock-comment-face 'my-comment-remap-style)) (face-remap-remove-relative my-comment-remap-cookie) ;; Time to put our functionality in a minor-mode so we can activate it ;; whenever we want with M-x. (define-minor-mode my-comment-remap-mode "Remap the face of comments." :local t :init-value nil (if my-comment-remap-mode (setq my-comment-remap-cookie (face-remap-add-relative 'font-lock-comment-face 'my-comment-remap-style)) (face-remap-remove-relative my-comment-remap-cookie))) ;; Or you can use a hook (this one targets the mode of the *scratch* ;; buffer): (add-hook 'lisp-interaction-mode-hook #'my-comment-remap-mode)