Every now and then I’d do something like
C-x C-f /path/to/new/dir/some-file.el. As the new folder doesn’t exist Emacs will prompt me to press
RETtwice to create it. It’s not a big deal, but it always annoys me a little bit and I’m always looking for ways to optimize my workflow.
At first I thought I’d have to advise
find-fileand just add some check in the advice whether the destination folder exists. Here’s how this typically works:
(defun er-auto-create-missing-dirs (orig-fun &rest args) (let* ((filename (car args)) (target-dir (file-name-directory filename))) (unless (file-directory-p directory) (make-directory directory t)) (apply orig-fun arg))) (advice-add 'find-file :around 'er-auto-create-missing-dirs)
That gets the job done, but I’ve never been super fond of using advices as they add some complexity to the process of debugging something. Turns out there’s a much simpler solution, though - the hook
find-file-not-found-functions. According to the docs:
List of functions to be called for
find-fileon nonexistent file. These functions are called as soon as the error is detected. Variable
buffer-file-nameis already set up. The functions are called in the order given until one of them returns non-nil.
This means all we need to do is write a simple hook function:
(defun er-auto-create-missing-dirs () (let ((target-dir (file-name-directory buffer-file-name))) (unless (file-exists-p target-dir) (make-directory target-dir t)))) (add-to-list 'find-file-not-found-functions #'er-auto-create-missing-dirs)
Basically we just need to extract the destination folder from the file we’re trying to create and invoke
make-directorywith its second param instructing it to create all the non-existing folders along the way. The advice example shown earlier is doing exactly the same thing.
Place one of the above snippets in your Emacs configuration and that’s it. I can never get enough of such small productivity improvements!
That’s all I have for you today. Keep hacking!
Operating systems, GUI toolkits and competing editors come and go, but Emacs is forever!
I’ve often said that one of the great advantages of Emacs is that it has stood the test of time1 and will likely be with us for a very long time to come. During the 25 years I’ve been into computers and programming I’ve seen a lot of editors and IDEs rise and fall:
And now Atom. Any investment you’ve made to master those tools and build additional plugins for them has been mostly wasted in the end.
This list also serves to illustrate that just being an open-source project doesn’t mean much, if there’s no real community around the project and the bulk of the development is driven by commercial interests. The moment when such projects lose their backing they typically stagnate and die. It’s not like community project don’t meet their demise from time to time as well, but they are definitely much more resilient than the typical company-driven OSS project.
Emacs is a true community-driven project and I’m certain that it will outlive many more trendy editors until all is said and done.2 If you’re playing the long game, you better pick the right tools for it.
In Emacs we trust!
Occasionally we’d have bits of configuration that are depending on whether Emacs is running in a terminal or in GUI mode. This article aims to cover how to best handle such situations.1
At first it seems the solution is super simple:
(if (display-graphic-p) ;; GUI mode (progn (your) (code)) ;; Terminal mode (your) (code))
In the past the variable
window-systemprovided another way to check for this, but it has been deprecated for a while, so I’d advise against using it.
While the above solution works, it fails to address one fundamental aspect of Emacs - you can have multiple Emacs frames (or windows, in non-Emacs terminology) associated with one Emacs instance. Some of those might be on a terminal, and others might be on a window system. That is to say, you can get different values of
display-graphics-peven within a single Emacs instance.
For example, you can start a GUI Emacs and then connect to it via
emacsclient -tin a terminal; the resulting terminal frame will see a value of
display-graphics-p. Similarly, you can start Emacs in daemon mode (
emacs --daemon), then later tell it to create a graphical frame with
What this means in practice is that it’s usually best to put code that’s GUI/terminal specific in
(add-hook 'after-make-frame-functions (lambda () ;; we want some font only in GUI Emacs (when (display-graphics-p) (set-frame-font "DejaVu Sans Mono 28")))
(add-hook 'after-make-frame-functions (lambda () ;; we do something only in terminal Emacs (unless (display-graphics-p) (xterm-mouse-mode 1)))
That way the check would happen separately for each frame and you’d be able to adjust the settings for it accordingly. And yeah - probably enabling a global mode like
xterm-mouse-modeis not the best example for a frame-specific action to take, but I hope you get the general idea.
Note that the
after-make-frame-functionshook isn’t run for the initial frame, so it’s often necessary to also add frame-related hook functions like that above to
That’s all I have for you today. Keep hacking!
Most Emacs packages need some command to display their version, as that’s useful for debugging purposes (e.g. when submitting a bug report). In the (very) old days each package would have simply some variable with a name like
package-versionthat a command like
package-display-versionwould display somehow (typically in the minibuffer). It doesn’t get simpler than this.
Then it became popular to have all sorts of package metadata in the comment headers of the Emacs packages. Here’s an example:
;; Author: Bozhidar Batsov <email@example.com> ;; URL: https://github.com/bbatsov/projectile ;; Keywords: project, convenience ;; Version: 2.6.0-snapshot ;; Package-Requires: ((emacs "25.1"))
But this opened up the question of how to best extract such metadata…
lisp-mnt.el(bundled with Emacs) has some handy functions that can help:
and so on. I hope you get the idea - there’s basically a function for each common metadata property. All of those operate either on the current buffer or an explicitly specified Elisp file. This means that are not very useful when you want to extract metadata from an installed package (usually installed via
package.el), as you have to do a bit of extra work to get a handle of the files in the package.
For a few years I used in all my packages the excellent package pkg-info, but these days both it and its underlying library epl are abandoned, so a while ago I decided I should replace them with something else - ideally, some standard
package-get-versionwas the best solution that I could find. Here’s the description of what the function does:
Return the version number of the package in which this is used. Assumes it is used from an Elisp file placed inside the top-level directory of an installed ELPA package. The return value is a string (or nil in case we can’t find it).
As the function was introduced only in Emacs 27 it might not be an option for everyone. That’s how I typically leverage it in most of my projects these days.
;;; Version information (defconst projectile-version "2.6.0-snapshot" "The current version of Projectile.") (defun projectile--pkg-version () "Extract Projectile's package version from its package metadata." ;; Use `cond' below to avoid a compiler unused return value warning ;; when `package-get-version' returns nil. See #3181. ;; FIXME: Inline the logic from package-get-version and adapt it (cond ((fboundp 'package-get-version) (package-get-version)))) ;;;###autoload (defun projectile-version (&optional show-version) "Get the Projectile version as string. If called interactively or if SHOW-VERSION is non-nil, show the version in the echo area and the messages buffer." (interactive (list t)) ((let ((version (or (projectile--pkg-version) projectile-version)))) (if show-version (message "Projectile %s" version) version)))
As you can see I still use a
projectile-versionfallback var for the cases where
package-get-versionfails for one reason or another (e.g. a package wasn’t installed using
package.el). You can also see I’m considering inlining
package-get-versionand adapting it code to make it a bit more flexible. Still, I think the basic solution outlined here is good enough for most people. For everyone else, there’s the bullet-proof approach of
(defun magit-version (&optional print-dest) "Return the version of Magit currently in use. If optional argument PRINT-DEST is non-nil, output stream (interactively, the echo area, or the current buffer with a prefix argument), also print the used versions of Magit, Git, and Emacs to it." (interactive (list (if current-prefix-arg (current-buffer) t))) (let ((magit-git-global-arguments nil) (toplib (or load-file-name buffer-file-name)) debug) (unless (and toplib (member (file-name-nondirectory toplib) '("magit.el" "magit.el.gz"))) (let ((load-suffixes (reverse load-suffixes))) ; prefer .el than .elc (setq toplib (locate-library "magit")))) (setq toplib (and toplib (magit--straight-chase-links toplib))) (push toplib debug) (when toplib (let* ((topdir (file-name-directory toplib)) (gitdir (expand-file-name ".git" (file-name-directory (directory-file-name topdir)))) (static (locate-library "magit-version.el" nil (list topdir))) (static (and static (magit--straight-chase-links static)))) (or (progn (push 'repo debug) (when (and (file-exists-p gitdir) ;; It is a repo, but is it the Magit repo? (file-exists-p (expand-file-name "../lisp/magit.el" gitdir))) (push t debug) ;; Inside the repo the version file should only exist ;; while running make. (when (and static (not noninteractive)) (ignore-errors (delete-file static))) (setq magit-version (let ((default-directory topdir)) (magit-git-string "describe" "--tags" "--dirty" "--always"))))) (progn (push 'static debug) (when (and static (file-exists-p static)) (push t debug) (load-file static) magit-version)) (when (featurep 'package) (push 'elpa debug) (ignore-errors (--when-let (assq 'magit package-alist) (push t debug) (setq magit-version (and (fboundp 'package-desc-version) (package-version-join (package-desc-version (cadr it)))))))) (progn (push 'dirname debug) (let ((dirname (file-name-nondirectory (directory-file-name topdir)))) (when (string-match "\\`magit-\\([0-9].*\\)" dirname) (setq magit-version (match-string 1 dirname))))) ;; If all else fails, just report the commit hash. It's ;; better than nothing and we cannot do better in the case ;; of e.g. a shallow clone. (progn (push 'hash debug) ;; Same check as above to see if it's really the Magit repo. (when (and (file-exists-p gitdir) (file-exists-p (expand-file-name "../lisp/magit.el" gitdir))) (setq magit-version (let ((default-directory topdir)) (magit-git-string "rev-parse" "HEAD")))))))) (if (stringp magit-version) (when print-dest (princ (format "Magit %s%s, Git %s, Emacs %s, %s" (or magit-version "(unknown)") (or (and (ignore-errors (magit--version>= magit-version "2008")) (ignore-errors (require 'lisp-mnt) (and (fboundp 'lm-header) (format " [>= %s]" (with-temp-buffer (insert-file-contents (locate-library "magit.el" t)) (lm-header "Package-Version")))))) "") (magit--safe-git-version) emacs-version system-type) print-dest)) (setq debug (reverse debug)) (setq magit-version 'error) (when magit-version (push magit-version debug)) (unless (equal (getenv "CI") "true") ;; The repository is a sparse clone. (message "Cannot determine Magit's version %S" debug))) magit-version))
And thought that extracting that version would be easy!
One more thing before we wrap up - dealing with MELPA package versions. As MELPA overwrites the actual package metadata version with the snapshot version it generates (basically a timestamp), you need to tweak a bit the original code from Projectile I’ve showed earlier. That’s how my CIDER project does the version extraction:
(defun cider--version () "Retrieve CIDER's version. A codename is added to stable versions." (if (string-match-p "-snapshot" cider-version) (let ((pkg-version (cider--pkg-version))) (if pkg-version ;; snapshot versions include the MELPA package version (format "%s (package: %s)" cider-version pkg-version) cider-version)) ;; stable versions include the codename of the release (format "%s (%s)" cider-version cider-codename)))
Basically, if the “real” version has the word “snapshot” in it, we’re appending the package version to the displayed version. This makes it easier to understand what’s the exact snapshot build that someone’s using.
After writing this article I miss
pkg-infoeven more. Dealing with package metadata should be simpler!
That’s all I have for you today. Keep hacking!
I’ve started writing this article 1 year ago and for some reason I never finished. Today I’m changing this!1
Some text terminals support mouse clicks in the terminal window (shocking, right?). Some Emacs users would like to use the mouse in terminal Emacs. This article is for them.
Most people (except GNU/Linux users) should add this to their
GNU/Linux users should add this to their
You might want to wrap this config in some check that you’re actually running terminal Emacs (e.g.
(unless (display-graphic-p) (xterm-mouse-mode 1))
Now let’s expand on this a bit.
In a terminal emulator which is compatible with
xterm, you can use
M-x xterm-mouse-modeto give Emacs control over simple uses of the mouse - basically, only non-modified single clicks are supported. Newer versions of
xtermalso support mouse-tracking. The normal
xtermmouse functionality for such clicks is still available by holding down the
Shiftkey when you press the mouse button.
xterm-mouse-modeis a global minor mode.
In the console on GNU/Linux, you can use
M-x gpm-mouse-modeto enable mouse support. You must have the gpm server installed and running on your system in order for this to work. Note that when this mode is enabled, you cannot use the mouse to transfer text between Emacs and other programs which use GPM. This is due to limitations in GPM and the Linux kernel.
xterm-mouse-modewill work on GNU/Linux system, but you’ll get better results with
Probably because I almost never use the mouse in Emacs. Or because I’m very lazy. Or because I have this tendency to start more things than I can finish. ↩