How to define multiple emacs faces?
Categories:
Mastering Emacs Faces: Defining Multiple Styles for Enhanced Readability
Learn how to define and apply multiple Emacs faces to customize your editor's appearance, improve code readability, and personalize your Emacs experience.
Emacs faces are fundamental to customizing the visual appearance of your editor. They control attributes like foreground and background colors, font families, font sizes, and text decorations (bold, italic, underline). While Emacs provides a rich set of default faces, defining your own or modifying existing ones allows for a highly personalized and often more productive editing environment. This article will guide you through the process of defining multiple Emacs faces, explaining the different methods and best practices.
Understanding Emacs Faces
At its core, a face in Emacs is a collection of display properties. These properties are applied to specific text regions, such as keywords in a programming language, comments, or parts of the Emacs UI like the modeline. By defining multiple faces, you can create distinct visual cues that help you quickly parse information and differentiate between various elements in your buffer.
flowchart TD A[Emacs Face] --> B{Display Properties} B --> C[Foreground Color] B --> D[Background Color] B --> E[Font Family] B --> F[Font Size] B --> G[Weight (Bold/Light)] B --> H[Slant (Italic)] B --> I[Underline] B --> J[Other Attributes] K[Text Region] --> A L[UI Element] --> A
Components and application of an Emacs Face
Defining New Faces with defface
The most robust way to define a new face in Emacs Lisp is by using the defface
macro. This macro allows you to specify a face name, its default attributes, and a documentation string. It's particularly useful when you're creating a new major mode or a package that requires custom styling.
(defface my-custom-face
'((((class color) (min-colors 88)) :foreground "#FF5733" :background "#333333" :weight bold :height 1.2)
(t :foreground "red" :background "black"))
"A custom face for highlighting important text."
:group 'my-custom-group)
Defining a new face using defface
In the defface
example above:
my-custom-face
is the name of our new face.- The first argument is a list of specifications. Each specification consists of a list of
(conditions)
and a list of(attributes)
. This allows you to define different appearances based on the terminal's capabilities (e.g.,(class color)
for graphical Emacs or(min-colors 88)
for terminals with at least 88 colors). Thet
condition acts as a fallback for all other environments. :foreground
,:background
,:weight
, and:height
are some of the common face attributes.- The documentation string explains the purpose of the face.
:group 'my-custom-group
associates this face with a customization group, making it discoverable viaM-x customize-group my-custom-group
.
t
fallback ensures your face looks reasonable even in less capable environments.Modifying Existing Faces with custom-set-faces
Often, you don't need to create entirely new faces but rather want to modify the appearance of existing ones, such as font-lock-comment-face
or default
. The custom-set-faces
function is ideal for this, as it integrates with Emacs's customization system.
(custom-set-faces
'(font-lock-comment-face ((t (:foreground "#888888" :italic t))))
'(default ((t (:family "Fira Code" :height 110))))
'(my-custom-face ((t (:foreground "#FFD700" :background "#282828" :underline t)))))
Modifying existing faces and a custom face using custom-set-faces
This snippet modifies three faces:
font-lock-comment-face
: Sets comments to a dark grey and italic.default
: Changes the default font to "Fira Code" and sets its height (110 means 11 points if the default height is 10 points).my-custom-face
: Updates the custom face we defined earlier, demonstrating thatcustom-set-faces
can also be used to set properties for faces defined withdefface
.
set-face-attribute
directly in your init.el
for persistent changes, as it bypasses the customization system. custom-set-faces
is the preferred method for user-level face customization.Applying Faces Programmatically
Once faces are defined, you can apply them to text regions programmatically using text properties. This is how major modes apply syntax highlighting, for example.
(with-current-buffer (get-buffer-create "*My Scratchpad*")
(insert "This is normal text.\n")
(insert "This text is important!\n")
(add-text-properties (1- (point)) (point) '(face my-custom-face))
(insert "This is a comment.\n")
(add-text-properties (1- (point)) (point) '(face font-lock-comment-face))
(switch-to-buffer (current-buffer)))
Applying faces to text regions in a buffer
This example creates a new buffer, inserts some text, and then applies my-custom-face
and font-lock-comment-face
to specific lines. The add-text-properties
function is key here, taking a start position, end position, and a list of properties (including face
).
1. Open your Emacs configuration file
Typically, this is ~/.emacs.d/init.el
or ~/.emacs
. You can open it with C-x C-f ~/.emacs.d/init.el
.
2. Define your custom face
Add the defface
block from the example to your init.el
. Remember to choose a unique name for your face, like my-important-highlight-face
.
3. Modify existing faces (optional)
If you wish to change the appearance of built-in faces, add the custom-set-faces
block, adjusting the face names and attributes to your preference.
4. Save and restart Emacs
Save your init.el
file (C-x C-s
) and then restart Emacs (M-x restart-emacs
) for the changes to take effect. Alternatively, you can evaluate the new Lisp code with M-x eval-buffer
.
5. Test your new faces
Open a buffer and try applying your custom face programmatically, or observe how modified built-in faces now appear.