I wrote this post to demonstrate how I’m using Emacs Lisp to do some useful things. This post is aimed at beginners and those interested (e.g., Vim users potentially) in how Emacs can be extended to automate some simple tasks. Advanced users will probably have more elegant (or more complete) solutions than what I have here,1 so with that in mind I will focus more on the motivations, thought processes, and progressions I’ve gone through with these functions. I also discuss some future directions and how these functions could be improved.
About a year ago I made a point to complete the built-in Emacs Lisp tutorial. For those looking for a good place to start with Emacs Lisp, this is undoubtedly it. It’s one of the best programming tutorials I’ve ever gone through, and I thoroughly enjoyed it. While navigating through the tutorial, I created a .org file with subsections for each chapter and individual code blocks for each set of examples/exercise. I frequently go to this file to find snippets, and I often find this more effective than Googling solutions.2
The functions below and all associated code are in my dotfile which can be found in this repo. Note that I’m using Spacemacs, hence the associated keybindings and Vim-like conventions.
open-html-firefox
I created this function since I often render .org and .Rmd files into .html files within Emacs. Then, I use the command
:! firefox my-newly-rendered-file.html
to open the file in a browser. Once the .html file is open, it can simply be
refreshed to reflect any changes. But, I often use Emacs as a navigation tool
(e.g., SPC f f
; i.e. lazy-helm/spacemacs/helm-find-files
) by first opening a
.org or .Rmd in Emacs, then opening the .html in a browser with a command like
the one above. This becomes tedious since most materials I create for courses
(syllabi, assignments, handouts, discussion questions, etc.) are served as .html
files, and I have to open these all the time. I could open the .html file in
Emacs instead and then use
:! firefox %
but the .html files created by org-reveal
(a very nice package) are quite
large and cause Emacs to hang. So, I sought to create something that would (a)
get the full file path to the current buffer and strip the extension, (b) slap
“.html” to the end of this string, (c) open the file in Firefox, and (d)
assign this function to a keybinding. Here is what I came up with:
(defun open-html-firefox ()
(interactive)
; create the new string of the file to open
(setq file-string (concat (file-name-sans-extension (buffer-file-name)) ".html"))
; execute command
(shell-command (concat "firefox " file-string)))
; assign this function to a keybinding in markdown mode
(add-hook 'markdown-mode-hook
(lambda ()
(local-set-key (kbd "C-c f") 'open-html-firefox)))
; assign this function to a keybinding in org mode
(add-hook 'org-mode-hook
(lambda ()
(local-set-key (kbd "C-c f") 'open-html-firefox)))
In my dotfile, the function has documentation, but I removed it for this post
since I’m explaining everything in detail. The function itself is quite short
and consists of mainly two things: (a) creating a variable called
file-string
3 and (b) opening this string (which is an .html
file) in Firefox with a command.
Originally I was using
(setq file-string (replace-regexp-in-string "\.Rmd" ".html" (buffer-file-name)))
to create the string, but this obviously only works for .Rmd files. Also, I was
not initially aware of the file-name-sans-extension
function which turned out
to be much easier than what I was doing anyway.
The two add-hook
’s just assign open-html-firefox
to keybindings in
markdown-mode
and org-mode
. The reason why I use lambdas is because the
internet told me to;4 lo and behold, it doesn’t work without lambdas.
It is possible to assign this function to a global keybinding, but I don’t want
to override keybindings on other modes. Something like C-c f
is common enough
that I assume it’s being used elsewhere.
What would be even better (and simpler) is a function/keybinding that opens a
file under point directly from helm-find-files
.
add-src-elements
This function adds the text
#+BEGIN_SRC
#+END_SRC
to the current buffer and places the cursor just after “#+BEGIN_SRC”. This block structure is used to embed code .org files, which I use to create presentations. For example, a block may contain something like
#+BEGIN_SRC python
import numpy
import scipy
x = 'Emacs Rocks' # i hope this phrase isn't trademarked
#+END_SRC
Manually typing #+BEGIN_SRC...
, etc. etc. is tedious, so I simply created a
function and keybinding to automate this. Here it is:
(defun add-src-elements ()
"Make adding #+BEGIN/END _SRC elements easier"
(interactive)
(insert "#+BEGIN_SRC\n#+END_SRC")
(forward-line -1)
(evil-append-line 1)
(insert " "))
; set it to a keybinding
(with-eval-after-load 'org
(add-hook 'org-mode-hook
(lambda ()
(local-set-key (kbd "C-c s") 'add-src-elements)))
My dotfile looks a little different since I have other org-mode
hooks, but
this is the gist of it. Again, the internet insists I use
with-eval-after-load
,4 so I obey. This could be improved by looking
for a previous codeblock (i.e. search-backward
) in the current buffer if one
exists, getting the language used for the block if it’s listed (Python in my
example), and inserting this language name just after #+BEGIN_SRC
. In most
presentations I only demonstrate concepts in one language, so it would make
sense to use the previous source block’s language if it is listed.
Emacs Lisp programming strats
When using Emacs Lisp, I’ve often had difficultly locating proper functions to
do simple things. For example, in my second function, add-src-elements
, I
utilize (forward-line -1)
, which serves to move the cursor to the previous
line. This is something we do all the time in text editors manually. As a
Spacemacs user, for example, I use j
/k
to navigate between single lines.
This is where a beautiful feature of Emacs is exposed: describe-key
, which
will show the function called by any keybinding. To find out what function is
called by k
(which navigates to the previous line in evil-mode
), I use C-h k
to call describe-key
, and then I simply press k
.
The function appearing in the help buffer is called evil-previous-line
. While
this wasn’t what I used directly in my custom function, this process often
points me to the function I need. Similar useful features include
describe-function
and describe-variable
. All of these describe-
functions
contain links to the source code, which demonstrate what’s going on under the
hood.