Posts

  • Setting the Default Font for Emacs

    Even after almost 20 years of using Emacs I keep learning new things about it. I’ve always known that if you’re using Emacs on Linux the best way to set the default font is via the file .Xresources. Here’s some random example:

    Emacs.font: Iosevka Term Curly:weight=regular:size=14
    

    But I’ve got several computers and I use Emacs on macOS, Linux (I consider WSL Linux as well) and occasionally natively on Windows. That’s why I’ve historically preferred to use just the font in my init.el like this:

    ;; the font size here is huge, because it's for X on a HiDPI screen
    ;; X can't handle font scaling properly, therefore I just double the font size
    ;; when I have to use Emacs under X
    (set-frame-font "Cascadia Code 28")
    

    I recently, however, noticed that under X child frames are not using the same font and looked a lot smaller.1

    child_frames_font.png

    I was sure this had something to do with X not handling HiDPI screens properly, but it wasn’t immediately obvious to me why was the font in the child frame different from the font used in the primary Emacs frame.

    Turned out that set-frame-font by default doesn’t apply to child frames of the main frame. Fortunately you can easily address this by specifying an optional set-frame-font parameter:

    (set-frame-font FONT &optional KEEP-SIZE FRAMES INHIBIT-CUSTOMIZE)

    Set the default font to FONT. When called interactively, prompt for the name of a font, and use that font on the selected frame. When called from Lisp, FONT should be a font name (a string), a font object, font entity, or font spec.

    If KEEP-SIZE is nil, keep the number of frame lines and columns fixed. If KEEP-SIZE is non-nil (or with a prefix argument), try to keep the current frame size fixed (in pixels) by adjusting the number of lines and columns.

    If FRAMES is nil, apply the font to the selected frame only. If FRAMES is non-nil, it should be a list of frames to act upon, or t meaning all existing graphical frames. Also, if FRAMES is non-nil, alter the user’s Customization settings as though the font-related attributes of the ‘default’ face had been “set in this session”, so that the font is applied to future frames.

    If INHIBIT-CUSTOMIZE is non-nil, don’t update the user’s Customization settings.

    So, in the end all I needed to do was:

    (set-frame-font "Cascadia Code 28" nil t)
    

    Magic! Now the child frames had exactly the same font as the rest of my Emacs!

    Another Emacs lesson learned. That’s all I have for you today. Keep hacking!

    P.S. By the way, if someone knows that does KEEP-SIZE do exactly please share this in the comments section. I’m utterly baffled by its description.

    1. I finally got to trying out the popular Corfu code-completion library and it’s using child frames to display the completion candidates. 

  • The Compat Elisp Library: A Package Maintainer's Best Friend

    I guess every package maintainer has been in the following situation - an upcoming version of Emacs introduces some new cool API that you’d like to use immediately. Or simply you have to maintain compatibility with many old Emacs versions, but you’d still like to use some modern APIs. Usually what happens in this case is that people start to backport themselves whatever Elisp APIs they need. E.g. for a long time CIDER had a file named cider-compat.el that looked something like this right before it became obsolete:

    (eval-and-compile
    
      (unless (fboundp 'if-let*)
        (defmacro if-let* (bindings then &rest else)
          "Process BINDINGS and if all values are non-nil eval THEN, else ELSE.
    Argument BINDINGS is a list of tuples whose car is a symbol to be
    bound and (optionally) used in THEN, and its cadr is a sexp to be
    evalled to set symbol's value."
          (declare (indent 2)
                   (debug ([&or (&rest (symbolp form)) (symbolp form)] form body)))
          `(let* ,(internal--build-bindings bindings)
             (if ,(car (internal--listify (car (last bindings))))
                 ,then
               ,@else))))
    
      (unless (fboundp 'when-let*)
        (defmacro when-let* (bindings &rest body)
          "Process BINDINGS and if all values are non-nil eval BODY.
    Argument BINDINGS is a list of tuples whose car is a symbol to be
    bound and (optionally) used in BODY, and its cadr is a sexp to be
    evalled to set symbol's value."
          (declare (indent 1) (debug if-let*))
          `(if-let* ,bindings ,(macroexp-progn body)))))
    
    (provide 'cider-compat)
    

    I’ve done something similar for many packages and I’ve seen it in the wild countless times. But there is a better and simpler way to get access to those newer APIs - enter the compat library.

    Compat is the Elisp forwards compatibility library, which provides definitions introduced in newer Emacs versions.1 The definitions are only installed if necessary for your current Emacs version. If Compat is compiled on a recent version of Emacs, all of the definitions are disabled at compile time, such that no negative performance impact is incurred. The provided compatibility implementations of functions and macros are at least subsets of the actual implementations. Be sure to read the documentation string and the Compat manual.

    Not every function provided in newer versions of Emacs is provided here. Some depend on new features from the C core, others cannot be implemented to a meaningful degree. Please consult the Compat manual for details regarding the usage of the Compat library and the provided functionality.

    The main audience for this library are not regular users, but package maintainers. Therefore no commands, user-facing modes or user options are implemented here.

    The above description is taken verbatim from the package and I don’t really have much to add to it. Here’s also what one of the package’s maintainers has to say about it and its use-cases:2

    Over time Emacs has seen useful standard library additions, for example additional string-* functions or the new keymap-* functions in Emacs 29. Compat provides many of these new functions and closes the gap between Emacs core development and package development outside of Emacs, since new Emacs additions become available early for all package developers.

    Packages outside of Emacs core can be written in the same style as Emacs core packages by relying on Compat. Vice versa Emacs core packages can use Compat for their separate GNU ELPA releases, as is done for example by ERC, the Emacs IRC client. Compat should make it easy to move packages out of core or into the core, while still allowing separate GNU ELPA releases. Using Compat may increase the performance of your packages, since you can use optimized functions like ntake, which will only fallback to a slower compatibility version on older Emacs versions.

    In a nutshell compat bridges the gap between what’s available for built-in Emacs packages and third-party (external) packages. And this is totally awesome!

    I can recommend checking out the source code of the library and its extensive changelog. You’ll notice how internally the code is organized in files matching various Emacs versions (e.g. compat-25.el, compat-26.el, etc) and that the library makes heavy use of custom macros like compat-defun, compat-defalias and compat-defmacro (all defined in compat-macs.el) for the backported APIs. Here are a few examples from compat-29.el:

    (compat-defun list-of-strings-p (object) ;; <compat-tests:lists-of-strings-p>
      "Return t if OBJECT is nil or a list of strings."
      (declare (pure t) (side-effect-free t))
      (while (and (consp object) (stringp (car object)))
        (setq object (cdr object)))
      (null object))
    
    (compat-defun plistp (object) ;; <compat-tests:plistp>
      "Non-nil if and only if OBJECT is a valid plist."
      (let ((len (proper-list-p object)))
        (and len (zerop (% len 2)))))
    
    (compat-defun delete-line () ;; <compat-tests:delete-line>
      "Delete the current line."
      (delete-region (pos-bol) (pos-bol 2)))
    
    (compat-defmacro with-restriction (start end &rest rest) ;; <compat-tests:with-restriction>
      "Execute BODY with restrictions set to START and END.
    The current restrictions, if any, are restored upon return.
    When the optional :label LABEL argument is present, in which
    LABEL is a symbol, inside BODY, `narrow-to-region' and `widen'
    can be used only within the START and END limits.  To gain access
    to other portions of the buffer, use `without-restriction' with the
    same LABEL argument.
    \(fn START END [:label LABEL] BODY)"
      (declare (indent 0) (debug t))
      `(save-restriction
         (narrow-to-region ,start ,end)
         ;; Locking is ignored
         ,@(if (eq (car rest) :label) (cddr rest) rest)))
    

    And that’s a wrap. I think pretty much every package maintainer can benefit from this library in their packages (unless they have aversion to external dependencies that is). I have to admit that I learned about its existence only recently and I can’t believe I missed something so useful for so long. Mistake corrected! Keep hacking!

    1. “Newer” here means means Emacs 25+. Compat itself supports Emacs 24.4+. 

    2. Taken from https://www.reddit.com/r/emacs/comments/10iep0o/compat_29130 

  • Removing (Unbinding) vs Unsetting Keybindings

    Recently I wrote a short article on removing keybindings. Originally I failed to cover there one important nuance there that I’ll tackle today - namely the difference between really removing (unbinding) a keybinding versus just unsetting it (setting it to nil).1 I know what you’re thinking right now - is there really any difference between the two?

    Most of the time there’s no real difference and I guess that’s why people often use the terms “remove”, “unbind” and “unset” interchangeably. But they are not the same as there’s a subtle difference when there’s a parent keymap involved. When unsetting a key in a child map (e.g. with define-key), it will still shadow the same key in the parent keymap.2 Removing the binding will allow the key in the parent keymap to be used. That’s why one can argue that unbinding is preferable to unsetting. The only problem with unbinding is that it was kind of hard to do in Emacs until very recently, unless you were relying on third-party packages to do so (e.g. bind-key).

    Generally the best way to truly remove a keybinding is probably the new command keymap-unset that will be part of Emacs 29. It can both unset and unbind a keybinding depending on how it’s used:

    ;; unset a binding
    (keymap-unset clojure-mode-map (kbd "C-c C-z"))
    
    ;; remove a binding
    (keymap-unset clojure-mode-map (kbd "C-c C-z") 'remove)
    

    In the example above clojure-mode-map is a child map of prog-mode-map, as clojure-mode is derived from prog-mode (the standard parent for major modes related to programming languages). If prog-mode-map had some binding for C-c C-z it would not become available if you had only unset the binding in clojure-mode-map. Only removal/unbinding of the keybinding from the child map (clojure-mode-map) would allow you to use the binding in the parent map (prog-mode-map).

    By the way, you can use the keymap-unset even on older Emacs version if you install the compat package, that brings newer Emacs functionality (mostly newer APIs) to older Emacs releases.

    I hope this article cleared some of the confusion with all the overloaded terminology in the field. That’s all I have for you today. Keep hacking!

    1. Special thanks to Jonas Bernoulli for flagging my omission. 

    2. In Emacs one keymap (child) can inherit bindings from another (parent). You can read more about keymap inheritance here

  • Avoid Accidentally Minimizing Emacs

    One of the most annoying problems that newcomers experience with Emacs is that they often press C-z out of habit when they want to undo something.1 C-z (and C-x C-z), however, is bound to the command suspend-frame that works a bit differently than undo:

    Do whatever is right to suspend the current frame. Calls suspend-emacs if invoked from the controlling tty device, suspend-tty from a secondary tty device, and iconify-or-deiconify-frame from a graphical frame.

    In short - in a terminal this will suspend Emacs and in a GUI it will minimize Emacs. Both are annoying outcomes, if you didn’t aim for them. So, what can we do about it? Given the command is already bound to the “safer” C-x C-z as well, I think it’s perfectly fine to just unbind it from C-z:

    (global-unset-key (kbd "C-z"))
    

    Or you can just bind it to undo for good measure and make learning Emacs a bit easier for you:

    (global-set-key (kbd "C-z") #'undo)
    

    Given that I never use neither C-z or C-x C-z I prefer to rebind both of them to undo. So, how do you feel about those keybindings? Do you do something about them?

    That’s all I have for you today. Keep hacking!

    1. I’ve been using Emacs for almost 20 years and I still press C-z by mistake, although for a different reason. I often the use the keybinding C-c C-z and sometimes by mistake I press C-z first or C-x C-z

  • Install a Package from a VCS Repository

    Most of the time the packages we need to install are already available in some of the popular package repositories (e.g. MELPA or GNU ELPA). Occasionally, however, some Elisp code has not yet been packaged (or we want to use an unreleased version of a package) and this forces us to be a bit more creative with respect to installing it. There has always been several ways to approach this, but Emacs 29 adds one more option that’s super easy to use - package-vc-install.

    When used interactive the command will prompt you for the repository from which to install a package. Alternative you can use it programatically like this:

    (package-vc-install "https://github.com/clojure-emacs/clojure-ts-mode")
    

    The command will try to infer the name of the package from the URL of the repository you’ve supplied. Upon closer inspection you’ll also notice that the command takes a few more parameters that allow you to specify the name of the package and a particular revision (commit) you want to use:

    (package-vc-install PACKAGE &optional NAME REV BACKEND)
    

    I’ve yet to play more with this command, but I guess it might serve as a simple alternative to tools like quelpa or straight.el, if you’re not using much of their functionality. And this certainly beats copying manually Elisp files from VCS repositories.

    From my perspective the main use-case for the new command will be pinning packages to some specific revision, as sadly it is still not possible to install older revisions of Emacs packages from package repositories (they carry only the latest version of a package). A feature that’s occasionally useful when you run into regressions with the latest version.

    That’s all I have for you today. Keep hacking!

Subscribe via RSS | View Older Posts