Today and tomorrow I will talk how I write R code. This is too big a topic. But before that, I want to talk a bit about hooks.
Before I dive into today’s topic. I would like to give an introduction to a concept called hooks.
According to the official definition, “a hook is a Lisp variable which holds a list of functions, to be called on some well-defined occasion.” The first question you might ask: Can we assign function(s) to a variable? The answer is of course. Function is a first class citizen in emacs lisp. This is an example:
(fset 'say 'message)
(say "I am hooked.")
In emacs lisp, one needs to quote a function in this kind of situations. Actually, except when you define a function with defun
1 and call the function, you probably always need to quote a function. In general, if one passes a function as “thing” (or operand), the function should be quoted. You might sometimes see I quote a function with a hash, i.e. '#message
. With or without the hash is more or less the same. It only makes a difference when the emacs lisp is byte-compiled (which I usually don’t do). In my usage, I will consider them the same.
Now, a hook as a variable holds a list of functions and those functions are called on a specific occasion. The commonest type of hooks is “mode hooks”. A mode hook holds some functions (or commands; I will talk about the distinction in a later blog post in this series) that are called when the mode is activated.
This is an example: flyspell
is a minor mode for doing on-the-fly spell checking. One can activate the flyspell
mode by
(flyspell-mode)
Now, I want to always activate flyspell
when I edit markdown document. I can put the above statement as quoted lambda into the mode hook of markdown-mode
using the add-hook
function.
(add-hook 'markdown-mode-hook 'flyspell-mode)
There are other kinds of hooks. For example, after-save-hook
holds a list of functions to be called when a file is saved. For example, rust-mode
puts a function into after-save-hook
to run the famous rustfmt
(Rust code formatter) before saving. That’s one of the reason why you really see poorly formatted Rust code.
R code has a lot of parentheses. Not as many Lisp, but still too many to be distracting. I like rainbow-delimiters by Fanael Linithien et al. This feature has been in place in the two major editors, vi(m) and emacs, for over a decade. 2 I can’t imagine editing R code without rainbow-delimiters
.
But my point actually isn’t we really need rainbow-delimiters to navigate our eyes through all the parentheses in some random R code. Instead, my suggestion is to turn it on as an alert so that R programmers (include me) won’t write any R code with more than 3 levels of parentheses. Actually 2 levels are probably my aesthetic limit. 3
In order to enable rainbow-delimiters
, I need to put rainbow-delimiters into mode hooks. And that’s why I needed to talk about mode hooks first.
(use-package rainbow-delimiters
:init
(add-hook 'ess-mode-hook #'rainbow-delimiters-mode)
(add-hook 'emacs-lisp-mode-hook #'rainbow-delimiters-mode)
)
I wrote about this previously. I am still dogfooding myself for using my own ess_rproj.
The idea is to read the Rproj file producing by our RStudio using friends and adjust the level of indentation to their liking. Again, it needs to be added to the ESS mode hook. And I should make this a minor mode.
(load-file "~/dev/ess_rproj/ess_rproj.el")
(add-hook 'ess-mode-hook #'ess-rproj)
Tomorrow I will talk about issues related to R package development.
Actually, defun
is what we called “special form”. And unlike other Lisp dialects such as Scheme (“lisp 1”), emacs lisp is “lisp 2” (functions and variables have two different namespaces). Therefore, you can’t assign a lambda (anonymous function) to a symbol like one can do with define
in scheme. ↩
RStudio the IDE has recently also introduced this feature (2020). ↩
If I have a chance, I will talk about how to refactoring R code. But I am now talking about emacs. ↩