Tuning Emacs to Write Prose in Org and Markdown
14 Aug 2023 Charles Choi
While default (aka vanilla or un-configured) Emacs is serviceable in editing Org and Markdown files, its out-of-the-box experience feels more like I’m programming said files rather than writing them. Thankfully, Emacs has excellent features (both built-in and external packages) to help you focus on writing prose. In this post I'll go over such features. As always, these recommendations are subjective, but I don’t think they fall too far from conventional thinking on the matter.
As to the features that I think help write prose:
- The use of proportional typefaces
- Hiding markup
- Automatic spell checking
- Dictionary lookup of a selected word
- Menu-driven
- Styling of selected text
- Toggling of hidden markup
- Dynamic completion of a previously written word
- Turn-on word-wrapping
- Navigation and moving of text
- Deleting whitespace
- Word count
Of course all of the above can be keyboard-driven (this is Emacs) but I like the affordance that menus can provide for text operations, particularly for selected text. Nothing wrong with having both.
Before moving forward, I’d also clarify that I’m not defining an explicit Emacs mode for distraction-free interactions as there are other modes which offer this. This post is really about configuration. That all said, let’s configure Emacs!
Prerequisites
This post presumes you understand enough of the following:
- How Emacs is initialized
- How to use the menu-driven Customize Emacs feature
- How to install packages
- How to customize an Emacs face
- How Emacs modes and mode hooks work
- Enough Elisp to be dangerous (or at least just copy and paste)
All the configurations in this post have been tested with Emacs 28.2.
Use Proportional Typefaces
For prose, a well-chosen proportional typeface is vastly more readable than a fixed-width one. You can turn-on rendering a proportional typeface in an Emacs buffer by enabling variable-pitch-mode
, typically by adding it via a mode hook in the init file. An Elisp example that does this for both Org and Markdown modes is shown below:
1 2 |
|
When variable-pitch-mode
is turned-on, the typeface used to render overlay-free text in the buffer is defined in the Elisp variable variable-pitch
. Customize variable-pitch
to taste. A menu-driven workflow for configuring any face is conveniently done via the menu-bar flow Options → Customize Emacs → Specific Face… which will prompt you for the face to customize.
Another setting to improve readability is to increase the line spacing via the Elisp variable line-spacing
. As both the Org and Markdown major modes inherit from the Text major mode, we can add a hook to set line-spacing
for both to text-mode-hook
in the init file.
1 2 |
|
More granular approaches to adjusting line height can be achieved by configuring the height of a face.
Using a different typeface helps to distinguish headers from body text. For Markdown, that face variable is named markdown-header-face
. For Org, there is a set of faces all corresponding to the header level, org-level-N
, where N
is a value between 1 and 8 inclusive.
While the reader can always choose their own typefaces, size, and spacing, my personal preference is to use the following settings:
face | typeface | height | slant | weight | width | Notes |
---|---|---|---|---|---|---|
default |
Menlo | 150 | normal | normal | normal | |
variable-pitch |
Optima | 1.4 | height is a scaling value based of default height | |||
markdown-header-face |
Futura | 1.1 | ||||
org-level-[1-8] |
Futura | 1.1 | org-level-N inherits from to outline-N face, so actual configuration configures outline-1 face. |
This link shows my implementation of the above settings using customize-face
. Note that the above typefaces are pre-installed on macOS and may not be available for other platforms.
For reference, much of my guidance on typographic configuration is taken from zzamboni.org | Beautifying Org Mode in Emacs. Highly recommended for readers who want to delve further into this.
Hiding Markup
Both Org and Markdown modes provide variables which support hiding markup delimiters. This makes for a more distraction-free experience.
For Org mode, setting the variable org-hide-emphasis-markers
to t
will hide the markup around styled text. I also like setting the variable org-hide-leading-stars
to t
so that headers are not so noisy.
For Markdown mode, invoking the function markdown-toggle-markup-hiding
as part of the initialization Markdown hook will achieve the same.
1 |
|
Don't fret about getting back your hidden text. Later in this post we will show how to easily reveal hidden markup.
Automatic Spellchecking
While spell checking support has long existed in Emacs, automatically checking text as you type is not turned on by default. Using the flyspell and company modes can remedy this, the first to automatically spell check a buffer and the latter to provide candidate replacements for a misspelled word. Enabling this in the init file via the text-mode-hook
turns this on for both markdown-mode
and org-mode
.
1 2 |
|
Don't like company
mode? There are plenty of other completion packages to choose from.
Dictionary Lookup of a Selected Word
Mickey Peterson has an informative post on using the dictionary lookup feature in Emacs 28. However, since macOS is my daily driver, I actually prefer to use the native macOS dictionary via the osx-dictionary package. Regardless of what package you use, having immediate access to a dictionary while writing is extraordinarily useful. While both the native dictionary lookup and ox-dictionary
are built to support keyboard-driven user interfaces, they can also be mouse-driven as well. Detailed below is how I’ve implemented a common GUI UX workflow where invoking a context-menu on a selected word will offer the option to look up that word’s definition.
First off, turn on context-menu-mode
in your init file. Here I’ve turned it on via the text-mode-hook
.
1 |
|
Next up is defining your custom context menu. I’ve written an earlier post on customizing the context menu which I highly recommend reading if you are new to context menus. Adding a menu item to invoke the function osx-dictionary-search-word-at-point
from the osx-dictionary
package is shown in the code fragment below:
1 2 3 4 5 6 |
|
The above code fragment is in the custom function cc/context-menu-addons
which itself is added to the hook context-menu-functions
.
To support context sensitivity, the predicate function use-region-p
is used to determine if text is selected; if not then this menu item is not added to the context menu. Note that another custom function cc/context-menu-last-word-in-region
is used to dynamically populate the menu item label with the last word in the selected region.
1 2 3 4 5 6 7 |
|
Menu-Driven Styling of Selected Text
Another common GUI UX workflow is to select text and style it (for example bold, italic, code, underline). To implement this behavior in Emacs, I defined a custom keymap cc/emphasize-menu
whose source is shown below:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 |
|
Note the use of predicates for the :visible
and :enable
properties to support context-sensitive behavior. In the source code above, the functions that actually style the selected text each do the following: 1) test for the current major mode (in this case either Markdown or Org), and 2) invokes the mode-specific function to style the text. For example, to “bold” a text, the following function cc/emphasize-bold
is called:
1 2 3 4 5 6 7 |
|
Definitions for all the style (emphasize) functions are at this link.
Menu-Driven Toggling of Hiding Markup (aka “Reveal Codes”)
For those users familiar with WordPerfect, it had a feature called Reveal Codes which enabled the user to explicitly see the codes used to format a document. This same behavior can be emulated for Org and Markdown buffers, via the visible-mode
and markdown-toggle-markup-hiding
functions, respectively.
The following code fragment from cc/context-menu-addons
shows how visible-mode
is invoked for Org mode.
1 2 3 4 |
|
The following code fragment from cc/context-menu-addons
shows how markdown-toggle-markup-hiding
is invoked for Markdown mode.
1 2 3 4 |
|
Context-sensitivity of how the above menu items are displayed is handled by the control flow of cc/context-menu-addons
, which tests for current major mode.
Dynamic Completion of a Previously Written Word
Ever have to type a word in a document that you were going to use multiple times? The function dabbrev-expand (keyboard shortcut M-/
) is your friend. There’s nothing to turn on, you get this behavior for free. Coupled with company-mode
and you will wonder how you lived without it.
Turn-on Word Wrapping
While this is very much a personal preference, over the years I’ve found that treating a text file newline as a paragraph delimiter to be the least-surprising convention to use. With that, turning-on word-wrapping is done via visual-line-mode. I turn this on for all text mode buffers via the text-mode-hook
.
1 |
|
Source link for the above code in my init file.
Navigation and Moving of Text
Mastering both navigation and moving text in Emacs can go a long way towards helping you write better prose as you can focus more on expressing your thoughts instead of just typing.
If you’re going to spend a considerable time with either Markdown or Org, I strongly recommend that you learn the heading/block navigation commands provided by the Org and Markdown major modes. In addition, if you haven’t tried Avy yet, stop here and go make it a part of your life. Emacs Elements provides a video demo of Avy at work, and Irreal posts here on how they use it.
My previous post Moving Text Elegantly in Emacs described how to move around a text object such as a word, sentence, or balanced expression (sexp) forward or backwards, among other operations involving the transpose family of functions.
A fairly recent post on sorting text in Emacs by Susam Pal shows how you can make short work of sorting lines. Highly recommended.
Deleting Whitespace
Also useful when reviewing text is to delete whitespace, either vertically in the form of blank lines or horizontally in the form of multiple spaces. Emacs provides a number of functions to address these concerns. While those functions can always be invoked via keyboard, I find it convenient to be access them via menu as well. Shown below is a custom keymap cc/delete-space-menu
invoking some functions that I find useful in this regard.
1 2 3 4 5 6 7 8 9 10 11 12 |
|
The keymap cc/delete-space-menu
can be incorporated into a custom context menu as shown here and into the menu bar here.
Word Count
A common metric is the count of words in a document. The function count-words
can determine this, which can be called from a context menu with the code fragment below:
1 2 3 4 5 6 7 8 9 |
|
Closing
This post suggests a number of configurations to tune Emacs for writing prose, with an emphasis on support for menu-driven operations. Hope that you find them useful!
References
A lot of this post was sourced from other posts over the years. For further reading, I encourage you follow the links below.