I use Rmarkdown and Blogdown to write the posts on this blog, but I use Emacs to edit the posts instead of Rstudio.
Software
All the posts on the blog are written in Rmarkdown files and edited with a software called polymode in Emacs. Polymode lets Emacs users run multiple major modes at once in a buffer, and I usually need to run ESS and markdown-mode at once. It’s certainly possible to edit the Rmd directly with any text editor, but combining all these modes together with Polymode gives me a lot of extras that I can use while I blog. For example, I can insert URLs more easily due to some functionality in markdown-mode, and I can evaluate R code interactively due to ESS.
Without Polymode, I would need to have one window to run the R code, and another to edit Markdown, but with Polymode I can mix and match code and words, just like in Rstudio.
Goodies
Here is one of the snippets that controls how I use markdown-mode in Emacs. It’s a slice of code from my Emacs customization file.
(use-package markdown-mode
:straight t
:blackout (markdown-mode . "ϻ")
:custom
(markdown-enable-math t)
(markdown-hide-urls t)
:mode
("\\.md\\'" . markdown-mode)
:hook
(markdown-mode . flyspell-mode)
(markdown-mode . visual-line-mode)
(markdown-mode . olivetti-mode)
:config
;; omitted a bunch of defun's
)
The use-package
declaration indicates a package that I want to download and configure. The keyword :straight
makes sure that the package is installed, and the keywords :custom
and :config
basically control all of my markdown mode configurations. I omitted the :config
block because it is basically a lot of custom e-lisp functions that I curated over the years to help make it easier to write Markdown. For example, I have a custom function that I use to insert local images, because I can’t remember the syntax for how to do that. I have another custom function that insert yaml headers for me automatically. Finally, I use :mode
to make sure that markdown-mode starts up when I open the right files, and I use :blackout
to keep the mode-line clean and tidy (see the screenshot below).
The hooks are some of the most important bits. I turn on flyspell, visual-line-mode, and olivetti. Flyspell is an Emacs package that just highlights spelling errors while I’m writing, much like MS Word. Olivetti makes the margins on Emacs extra large, so that I don’t have to scan very far from left to right. This make reading much better. Finally, visual-line-mode makes it so that I can write all paragraphs in one line of text, while still having correct line wrapping.
Hands down, the best thing about editing prose in Emacs is dynamic abbreviations. Basically, Emacs will keep track of all the words I type and suggest them back to me. This is very useful when writing a paper with many long words. For example, in this post, I use the word ‘functionality’ a few times, and after typing it out once, I can just type ‘fun’, then a menu will popup that I can tab through to insert ‘functionality’. The result is that I rarely need to type long words.
In the end, the editing environment looks like this:
Editing R code
My ESS configuration is much longer since I’ve been working with it for many years now. I reproduce it below mainly for anyone who would like to know what customizations I use, but many of these are common.
(use-package ess
:defer t
:straight t
:hook
(ess-help-mode . evil-normal-state)
:custom
(ess-auto-width 'window)
(ess-eldoc-show-on-symbol t)
(ess-gen-proc-buffer-name-function 'ess-gen-proc-buffer-name:projectile-or-directory)
(ess-eval-visibly 'nil)
(ess-style 'RStudio)
(ess-use-flymake nil)
(ess-tab-complete-in-script nil)
(ess-use-ido nil)
(ess-history-directory (expand-file-name "ESS-history/" no-littering-var-directory))
(ess-ask-for-ess-directory nil)
(ess-indent-with-fancy-comments nil))
(use-package ess-r-mode
:defer t
:blackout (ess-r-mode . "ϱ")
:custom
(inferior-R-args "--no-save" "Do not save R session")
(ess-R-font-lock-keywords
(quote
((ess-R-fl-keyword:keywords . t)
(ess-R-fl-keyword:constants . t)
(ess-R-fl-keyword:modifiers . t)
(ess-R-fl-keyword:fun-defs . t)
(ess-R-fl-keyword:assign-ops . t)
(ess-R-fl-keyword:%op% . t)
(ess-fl-keyword:fun-calls . t)
(ess-fl-keyword:numbers . t)
(ess-fl-keyword:operators)
(ess-fl-keyword:delimiters)
(ess-fl-keyword:=)
(ess-R-fl-keyword:F&T))))
:config
;; Make sure that underscore inserts the "<-"
(general-define-key
:states 'insert
:keymaps '(ess-r-mode-map inferior-ess-r-mode-map)
"_" 'ess-smart-underscore)
(general-define-key
:states '(normal visual)
:prefix ","
:keymaps '(ess-r-mode-map inferior-ess-mode-map)
"z" 'ess-switch-to-inferior-or-script-buffer
"s" 'ess-switch-process
"C" 'comint-interrupt-subjob
"b" 'ess-eval-buffer
"1" 'ess-eval-buffer-from-beg-to-here
"0" 'ess-eval-buffer-from-here-to-end
"f" 'ess-eval-function
"h" 'ess-help
"d" 'ess-describe-object-at-point
"m" 'my/add-pipe
"R" 'inferior-ess-reload
"," 'ess-eval-region-or-function-or-paragraph-and-step
"." 'ess-eval-region-or-function-or-paragraph
"a" 'ess-display-help-apropos
"i" 'ess-install-library
"n" 'ess-eval-region-or-line-and-step))
This is an example of one of the programming modes from my config that has its own local leader key map, which I configure with general..
Basically, in Normal state, when I press ,
I get a popup menu with a bunch of quick actions that are time savers for me. For example, ,b
evaluates the whole buffer, ,,
evaluates a function or paragraph of R code, etc. All of these are handy, and they make editing much more enjoyable.
You will notice a new keyword in this code block, :defer
, which makes it so all my configurations are recorded, but none of them are executed until I need to use R. This keeps my Emacs start up time to a minimum.
Writing
I don’t have many tips here. Writing is hard and I don’t have a good method, though I did recently learn about topic sentences and I will try to apply that from now on.
Publishing
I don’t use git or any other version control system to track the source files, and I do not use a continuous integration/deployment system to publish the posts from the raw Rmd files I write.
Instead, I create the Public HTML folder on my local machines, and upload the folder to Netlify using their folder upload dialog. This is so easy that I don’t see any reason to make it more complicated with intermediary software (like Git.)
I keep a single file called blog.R
in the blog folder with a list of possible topics that I could blog about, and some instructions for how to create the blog. For the most part, I just have to run blogdown::hugo_build()
and then upload the result to Netlify.
Why not Org-mode?
Because this website is a static site with a bit of code, generated using Emacs from a markup language, one might wonder why I don’t use Org-mode, since Org can do all of this (and more) and is distributed with Emacs.
I like some features of Org mode, in particular, I like org-capture and org-agenda for quickly saving and viewing my todo items. For writing a website with code, I find that Org falls short. For one, I dislike the publication method. The built-in publishing functionality is very basic and finicky, and while some corrective actions have been taken by the Emacs community, such as the org-page package, it has been on life support for several years now. Blogdown is much better, and there is a lot of effort behind it these days. And for me, one of the worst aspects of Org is that it cannot base64 encode HTML without a hack, so sharing webpages is very painful.
Writing in Org mode also guarantees that I will never have another person collaborate with me on this blog, because ~all statisticians know Rmarkdown and Rstudio, but very few know Emacs and Org. Statisticians have standardized on markdown, which is excellent. Org is better, but the delta between Org markup and Markdown markup is so small these days, we should just use Markdown instead.
Finally, I just find org to be very tedious to configure. There is always some dimension that needs to be tweaked to get it to suit me well, and I don’t have that problem when I’m writing in Markdown.
Org-mode admittedly has much more functionality than Markdown, and has broader language coverage. But, for the sliver of functionality that I require, markdown and blogdown are better, even though there are some warts. And I’m not a strong believer in literate programming, so Org babel doesn’t do it for me.
For general writing, I prefer TeX.