Due to some bad computer habits, I end up opening and closing editor instances a lot instead of starting my editor and using it for the duration of the project. In particularly bad cases, I end up closing my editor for every code change to run a compiler or check some files in the same terminal.
The proper solution to this problem is to get rid of bad habits and start using multiple windows like a modern human in 2021. But the easier solution is to make my editor startup time faster in order to mitigate some of the pain in using it.
This is not the fault of Emacs of course, as Emacs is expected to be running for at least the whole programming session. This doesn’t change the fact that I need to speed it up to make my life better though.
Profiling
The first step to making a program faster is to run a profiler to see which parts are slowing it down. Since running emacs -Q
(which makes Emacs start without loading the user config) is instant, this means my customization is causing Emacs to start up slower.
I used two methods for profiling. The first method is to run ProfileDotEmacs, which is a small Emacs Lisp script that prepares a report on how long each section of your .emacs
file takes to execute. If all your configurations are done in your .emacs
file, in a mostly top-level fashion, ProfileDotEmacs will probably be sufficient to know what is causing the slowdown.
The second method, which actually provided more useful information for me, is to wrap your config in profiler statements. This can be done like this.
(profiler-start 'cpu)
;; Your existing config
(profiler-end)
Now you will be able to run M-x profiler-report
whenever you want in order to a nested profiler report that you can interactively drill down to.
Speeding everything up
The title is a little dishonest, as we won’t actually be improving the run-time of any code. What we will be doing is to take the blocking code that runs on startup, and make it run once the editor is idle for a few seconds. The most important thing is that the editor starts up quickly, displays the contents of the file instantly and allows me to move around. Less crucial settings and comfort plugins can be loaded once I stop pressing the keys to think for a few seconds.
The way to schedule a command to run when the editor is idle is to call run-with-idle-timer. You can choose how many idle seconds you want to wait before executing your callback and what arguments to pass to you callback. I ended up writing these two helper functions for loading a file after the editor becomes idle.
(defun leo/load-file (file)
"Load an elisp file from .emacs.d"
(load (concat "~/.emacs.d/" file)))
(defun leo/load-idle (sec file)
"Load a file after N idle seconds"
(run-with-idle-timer sec nil 'leo/load-file file))
Delaying everything by one second was enough for my needs, but you can choose a tiered approach where the essentials are loaded immediately and heavier, less-important plugins get loaded over time.