Is there a better way in Emacs Lisp to print the list of monospace fonts in a separate buffer?

I found out the following Emacs Lips code in a gist on Github:

(defun font-is-mono-p (font-family)
  ;; with-selected-window
  (let ((wind (selected-window))
        m-width l-width)
   (with-current-buffer "*Monospace Fonts*"
     (set-window-buffer (selected-window) (current-buffer))
     (text-scale-set 4)
     (insert (propertize "l l l l l" 'face `((:family ,font-family))))
     (goto-char (line-end-position))
     (setq l-width (car (posn-x-y (posn-at-point))))
     (insert (propertize "m m m m m" 'face `((:family ,font-family) italic)))
     (goto-char (line-end-position))
     (setq m-width (car (posn-x-y (posn-at-point))))
     (eq l-width m-width))))

(defun compare-monospace-fonts ()
  "Display a list of all monospace font faces."
  (pop-to-buffer "*Monospace Fonts*")
  (dolist (font-family (font-family-list))
    (when (font-is-mono-p font-family)
      (let ((str font-family))
         (propertize (concat "The quick brown fox jumps over the lazy dog 1 l; 0 O o ("
                             font-family ")\n") 'face `((:family ,font-family)))
         (propertize (concat "The quick brown fox jumps over the lazy dog 1 l; 0 O o ("
                             font-family ")\n") 'face `((:family ,font-family) italic)))))))

The way it tries to find out if a font is mono-spaced is to print some lines and check for their length as far as I can see:

enter image description here

But is there a better way, e.g. to filter out only the mono spaced fonts to begin with, I mean without relying on actually printing strings in that font and comparing the width of the display. I mean by using some font specification, etc. I read https://www.gnu.org/software/emacs/manual/html_node/elisp/Low_002dLevel-Font.html, but it doesn't mention anything about "monospace" (unlike https://www.gnu.org/software/emacs/manual/html_node/emacs/Fonts.html).


The following seems working:

(seq-filter (lambda (font)
              (when-let ((info (font-info font)))
                (string-match-p "spacing=100" (aref info 1))))

;; =>

("Andale Mono"
 "Courier New"
 "GB18030 Bitmap"
 "PT Mono"
 "Source Code Pro"
 "Apple Braille"
 "Apple Color Emoji")

the above produces the same result as macOS's Font Book.app:

fixed-width fonts

I am not a font expert and spacing=100 is from by https://unix.stackexchange.com/questions/363365/command-to-list-all-monospace-fonts-known-to-fontconfig/363368.

  • I've just tried your code in the *scratch* buffer of my Emacs 27.0.50 on MS Windows 10, and it returned nil. Weird. I'm trying to understand why. Apr 29 '19 at 18:35

Small modification of @xuchunyang's answer for Windows, Emacs 26:

(require 'subr-x)
(seq-filter (lambda (font)
              (when-let ((info (font-info font)))
                (string-match-p "-mono-" (aref info 0))))

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.