
We are in the thick of summer. That’s for sure. That means I’m spending afternoons strategically in the shade—and writing.
As I’ve mentioned—probably—in other posts, most of the work of writing gets done in the head while doing other things. But at some point, all those notes and thoughts will get collected into the text editor and chopped up and re-arranged and eventually exported to the world.
That inevitable process of creative typing should be as painless as possible. Unless you like pain, which is fine too. Here I’ve collected some of my favorite Emacs configurations for streamlining, simplifying, or otherwise sweetening my workflow.
My blog explores writing techniques, especially how Emacs boosts your productivity and performance. Sign up for my newsletter to unlock the real cheat codes and some DRM-free reading material:
Table of Contents
Replace punctuation at point
How many times have you been editing a sentence, decide to change the punctuation, type a period, question mark, or exclamation point, and then have to delete the punctuation you just replaced? It happens to me all the time. It happened so frequently, I demanded a little Emacs magic to save me the extra step of deleting the unwanted punctuation. I wanted to just keep writing right on through!
So this little function here does just that. If Emacs detects your point on a punctuation mark, and you type a punctuation mark, the inserted mark will write over the existing mark.
(defun csm/replace-punctuation-at-point () "Replace punctuation at point (., !, ?) with the character typed by the user." (interactive) (let ((char (this-command-keys))) ;; Get the key pressed by the user (if (and (member (char-after) '(?. ?! ??)) ;; Check if current char is ., !, or ? (member (string-to-char char) '(?. ?! ??))) ;; Check if typed char is ., !, or ? (progn (delete-char 1) ;; Delete existing punctuation (insert char)) ;; Insert new punctuation (self-insert-command 1)))) ;; Default behavior: insert character ;; Bind this function to punctuation keys (define-key global-map "." 'csm/replace-punctuation-at-point) (define-key global-map "!" 'csm/replace-punctuation-at-point) (define-key global-map "?" 'csm/replace-punctuation-at-point)
A more Org-friendly word counter
As I’ve mentioned ad nauseam, word counts are important for writers. The more accurate the better. Word counts help us plan, stay sharp, on point, and provide important data to editors. But what if your document is full of Org comments, cold (unexported, or ignored) headings?
This modified word counter function gives you a more accurate count by ignoring lines start with ’*’ or ’#’.
(defun csm/org-word-count () "Count words in region/buffer, estimate pages, and reading time. Excludes lines beginning with * or #. Prints result in echo area." (interactive) (let* ((start (if (use-region-p) (region-beginning) (point-min))) (end (if (use-region-p) (region-end) (point-max))) (word-count (save-excursion (goto-char start) (let ((count 0) (inhibit-field-text-motion t)) (while (< (point) end) (beginning-of-line) (unless (looking-at-p "^[*#<]") (let ((line-end (line-end-position))) (while (re-search-forward "\\w+\\W*" line-end t) (setq count (1+ count))))) (forward-line 1)) count))) (words-per-page 400) (reading-speed 215) (page-count (/ (+ word-count words-per-page -1) words-per-page)) (reading-time (/ (+ word-count reading-speed -1) reading-speed))) (message "%d words, ~%d pages, ~%d min read" word-count page-count reading-time)))
It seems like a lot of code just to count some words, but it’s worth it. I mapped it to M-+
.
Completion frameworks
As I mentioned in my video on “your first config”, having a solid completion framework will change your game. These packages are essential for how I work in Emacs now; I could not get by without them. They are critical for note-taking and make it a helluva lot easier to find files and search text.
(use-package vertico :ensure t :init (vertico-mode)) (use-package orderless :ensure t :custom (completion-styles '(orderless basic)) (completion-category-overrides '((file (styles basic partial-completion)))))
Pick a theme
Get yourself a theme, or set of themes, that are easier on the eyes. I like Prot’s ef-themes.
(use-package ef-themes :ensure t :config (load-theme 'ef-day t))
Integrated dictionary
That’s right. Emacs has a built-in dictionary. That should come as no surprise. By default, the dictionary reaches out to a server, so you need an Internet connection. But it can be configured to hit a local server. I just haven’t got that far with it yet.
(require 'dictionary) (global-set-key "\C-cs" 'dictionary-search) (global-set-key "\C-cm" 'dictionary-match-words)
Org Mode scratch buffer
For many years, I bypassed the scratch buffer entirely and loaded something else on startup. But then I started liking the scratch buffer when I had it load up Org instead of a lisp mode.
Make Org your default mode:
(setq initial-major-mode 'org-mode)
Spacious padding
Writers generally like to see less clutter in their workspace. (Not always true, certainly.) But if you want to get some nice open space in your editor, Prot’s “spacious padding” mode accomplishes this nicely.
Here is how I have it configured:
(setq spacious-padding-widths '( :internal-border-width 20 :header-line-width 4 :mode-line-width 1 :tab-width 4 :right-divider-width 15 :scroll-bar-width 8)) (spacious-padding-mode 1)
Simplify Org export options
For years I wrote my favorite options into the header section of my Org documents. After writing these out a few hundred times I figured there must be a better way. So I hard-coded these options into the config and never looked back.
All of these settings can be overridden in an individual file, of course:
;; org export options (setq org-export-with-toc nil) ; No table of contents (setq org-export-with-section-numbers nil) ; No section numbers (setq org-export-with-smart-quotes t) ; Use smart quotes (setq org-export-with-sub-superscripts nil) ; No superscripts
I love the Org table of contents as much as a the next guy, but I don’t wanted it inserted arbitrarily at the top. I’d like to insert myself using #+toc: headlines 2
. The no-toc option above allows for this.
Likewise, I rarely find section numbers helpful in an export. But when I do, I can enable it manually.
I use smart quotes for the HTML exports, because those will end up on my website, where smart quotes are acceptable. I used to disable those for standard manuscript formatting, but that’s a convention of the past that doesn’t seem to matter anymore. Smart quotes are welcome now.
Superscripts and subscripts were annoying for technical writing. For example, if I wanted to write “public_html” without turning “html” into a subscript, I had to jump through some additional hoops. Then I realized this was something that could be turned on or off. Saved me a lot of time.
Back and forward buttons
I did a whole post on the magic of the backward and forward functionality. But for completeness, I wanted to reiterate it here. If you accidentally fat-finger a command or go on a long excursion and want to get right back to where you were before, this:
(use-package backward-forward :ensure t :demand t :config (backward-forward-mode t) :bind (:map backward-forward-mode-map ("<left>" . backward-forward-previous-location) ("<right>" . backward-forward-next-location)))
Wrap region
Highlight a region and put something around it. Helpful if you wanted to put a larger section in parenthesis or formatting marks and save yourself a step.
(defun csm/wrap-region (start end) "Prompt for a string and wrap the selected region with it." (interactive "r") ;; 'r' ensures the function operates on the selected region (let ((input (read-string "Enter the surrounding character or string: "))) (save-excursion (goto-char end) (insert input) (goto-char start) (insert input))))
Thanks for reading. I hope these functions provide you some nice options for Emacs-sweetening or at the very least some inspiration for own custom functions.
Reminders:
- My Emacs For Writer handbook is available here
- You can also subscribe to my newsletter here for extended digressions on certain topics and exclusive snippets from writing projects I’m working on.
Leave a Reply