Set Emacs defaut font face per-buffer/mode
Asked Answered
P

5

39

How do you change the default face which Emacs uses to style text on a per-mode basis?

For example, say that I am already happy with the face customizations that I have, which include a default fixed-width font. However, in one particular mode (markdown-mode.el, say), I want the default font to be variable-width.

It is easy to style headers, links etc. uniquely for markdown-mode: simply place the cursor over the styled text and M-x describe-face, then click the link to customize it.

However, the default face is the face used if no other face is specified, so it is not specific to markdown-mode and if modified will affect all other modes.

What magic can I put in the markdown-mode-hook to set the default face for buffers using this mode?

Promiscuity answered 10/2, 2009 at 21:33 Comment(2)
If there is a some variable that controls the default faces then you can localized it for the current buffer only in a hook that getting called while opening a file w/ markdown.Prunelle
The question is asked in a general way, then a specific example is made and answers revolve around this specific example. If you really need to "Set Emacs defaut font face per-mode", see Using a different font for each major mode - Emacs Stack ExchangeKreis
A
36

How about something like this:

(add-hook 'markdown-mode-hook (lambda () (variable-pitch-mode t))

You can then customize the variable-pitch face, and the other faces in the buffer will inherit from this instead of the default face.

Read the docs for buffer-face-mode for more customization details. (BufFace is also used for text-scale-increase and text-scale-decrease... very useful.)

Anglosaxon answered 11/2, 2009 at 0:37 Comment(3)
To my understanding this requires Emacs 23, can't find neither variable-pitch-mode nor buffer-face-mode in Emacs 22.Elsewhere
Wow, people still use Emacs 22?Anglosaxon
Thanks, does the trick. However, when a buffer uses variable-pitch fonts scrolling becomes so paaainfully slow that it's unusable. But this is probably just a bug.Promiscuity
P
6

I have to give a partial answer because this is too complicated to figure out on the spot and I already blew my time budget.

Face is a frame property. A frame can display multiple buffers at the same time. Mode is a buffer property. You ask how to vary the face on a per-mode basis. Combining all this, it seems that the question cannot not have a single fully-correct answer.

You can approximate the desired answer if you assume that a given frame will never display more than one buffer. You can actually accomplish that with something like this, but modified to use special-display-regexps and a set of regexps that match your markdown-mode buffer names.

(append special-display-buffer-names
        '("*VC-log*"
          "*Help*"
          ("*Completions*" 
           (height . 25)
           (font . "8x13"))))

However, this is probably not what you want. Your question seems to imply changing the face properties of a single frame.

Again assuming that a frame will never display more than one buffer at a time, you can try advising switch-to-buffer. But that might not be sufficiently low level and it might be too slow. (untested)

(defadvice switch-to-buffer (after switch-to-buffer activate compile)
  "change the frame's default face after switch-to-buffer"
  (doSomethingToChangePropertiesOfDefaultFace))

And now for my actual (incomplete) answer...

A better, albeit more complicated, approach would instruct markdown-mode to use a new face for all regions that are not already assigned one of the built-in faces. You can create a new face with copy-face and give it interesting properties with set-face-*.

Modify markdown-mode's font-lock-defaults to override the default font-lock-fontify-region-function as described in the comment block near line 946 of font-lock.el that begins, "Fontification functions". You can probably use a very slightly modified font-lock-default-fontify-region that does just one extra step immediately after it does:

  (unless font-lock-keywords-only
    (font-lock-fontify-syntactically-region beg end loudly))

The extra step parses the region similar to what font-lock-fontify-syntactically-region does, breaking the region into "interesting" sub-regions. But this time you find sub-regions that have the default face and you put-text-property those sub-regions to the new face that you previously created.

In all this feels like it should be only a couple lines of elisp in your .emacs file, plus make a copy of font-lock-default-fontify-region that has only a minor diff from the original (call one new function), plus make a copy of font-lock-fontify-syntactically-region and modify it to do your bidding (the most difficult part).

Actually, if you "after" advise font-lock-fontify-syntactically-region then you probably don't even need to modify font-lock-defaults or font-lock-default-fontify-region.

Prase answered 11/2, 2009 at 9:39 Comment(3)
Names and line numbers speak to GNU emacs 22.3.1.Prase
Or just get a recent version of emacs and use buffer-face-mode.Anglosaxon
Cool. But I'll probably wait until emacs 23 actually ships before updating to it.Prase
U
5

The variable-pitch-mode is awesome. I found out about it through this thread. But it can be made even more awesome:

(dolist (hook '(erc-mode-hook
        LaTeX-mode-hook
        org-mode-hook
        edit-server-start-hook
        markdown-mode-hook))
  (add-hook hook (lambda () (variable-pitch-mode t))))

Just add whatever mode you want sans-serif fonts in to the list.

Underworld answered 20/9, 2010 at 22:34 Comment(2)
What the code above does is to enable variable-pitch-mode for all the modes enumerated in all the lines except the last.Kreis
@StéphaneGourichon (variable-pitch-mode t)Chaldean
P
5

There is a block of code which I find very convenient, from EmacsWiki. The advantage of this is that you can set not only font face, but conveniently configure :height, :width etc as well

;; Use variable width font faces in current buffer
(defun my-buffer-face-mode-variable ()
  "Set font to a variable width (proportional) fonts in current buffer"
  (interactive)
  (setq buffer-face-mode-face '(:family "DejaVu Sans" :height 100 :width semi-condensed))
  (buffer-face-mode))
;; Use monospaced font faces in current buffer
(defun my-buffer-face-mode-fixed ()
  "Sets a fixed width (monospace) font in current buffer"
  (interactive)
  (setq buffer-face-mode-face '(:family "Consolas" :height 100))
  (buffer-face-mode))
;; Set default font faces for Info and ERC modes
(add-hook 'erc-mode-hook 'my-buffer-face-mode-variable)
(add-hook 'Info-mode-hook 'my-buffer-face-mode-variable)

Combined with load-theme-buffer-local package, you can even specify the color theme for the buffer easily:

(defun my-buffer-face-mode-variable ()
  "Set font to a variable width (proportional) fonts in current buffer"
  (interactive)
  (setq buffer-face-mode-face '(:family "DejaVu Sans" :height 100 :width semi-condensed))
  (buffer-face-mode)
  (load-theme-buffer-local 'leuven (current-buffer)))
Protactinium answered 24/5, 2015 at 6:2 Comment(0)
F
2

It's actually straightforward even for emacs version 22.3.1…

Just try the following:

(progn 
  (set-buffer "your buffer name here")
  (overlay-put (make-overlay 0 (buffer-size)) 'face 'your-face))
Fingerprint answered 13/1, 2010 at 22:21 Comment(2)
you could also find a definition of a function that easily changes the font of a buffer at junis.orgfree.com/SetBufferFont.elMirellamirelle
overlays are not good , because they are slow. they are good only if you do not have too many in the same time...Damarisdamarra

© 2022 - 2024 — McMap. All rights reserved.