On Emacs

2020-05-03 • 2019-12-06

This post is a short love letter to emacs, the text editor that has changed the way I do my daily computing for a few years now. You can find my config here.

Disclaimer: At the end of the day, a text editor is just a preference, just like mechanical keyboards, vim bindings, window managers and what have you.

Programmable state

Emacs state is a long running emacs lisp repl, with all variable and function assignments tracked in a global environment. This has a few negatives, such as the naming conflict potential of all elisp code, and that any running elisp can affect emacs state (say, freeze the entire experience). However, the benefit of being able to peek and tweak any elisp code live is huge. You can connect or fix elisp packages together in ways not imagined by the authors through that global repl, and see changes instantly, with a very low bar for hackery. The resulting footgun is both the best and worst computing experience I think I'll have for quite awhile.

Blended environment

Emacs can be thought of as a toolkit for integrating textual data into a higher level interface, with an API for shaping that data into emacs primitives. Things like buffers, windows, the point, overlays, and major modes are all programmatically available in the expressive emacs lisp language. Combine this with the programmable global state in emacs and you get a very 'flowey' feeling when you switch between different interfaces all using the same UI primitives. I like to contrast this to the rise of many TUI tools for doing things in the terminal in recent years – having to learn different keybinds and mental models for each of them (ncmpcpp, tig, mutt, ranger, weechat, …) is more overhead for me than using the emacs equivalents and getting the benefit of a consistent interface.

Emacs lisp

Emacs lisp is the first lisp I've used for more than 10 seconds, because you're forced to if you want to configure emacs. Having used it for a few years within emacs now, the expressive nature of lisp has grown on me to the extent it shapes how I program in most other languages (possibly in danger of being a smug lisp weenie). The semantic nature of lisp means you can always reshape things to get a better view of the problem you are trying to solve, and macros allow you to do so cheaply.

Fun things I've done with emacs

Shell stuff

shell-mode as my terminal, with a staged shell buffer

When I first start emacs, I create an 'on-deck' staged shell buffer with an interactive shell. Then when I 'spawn a terminal', what I'm actually doing is:

  • making a new emacs frame
  • picking up the staged shell buffer and renaming it
  • staging the next shell buffer for a future pickup

This means there is no startup time or delay on the part of the shell for me to get going. It also means I can pickup the staged shell from other contexts, like dired (spawn a shell in the current directory from the existing staged buffer).

Shell $CWD history

Everytime my prompt prints, it prints a key string for emacs shell to pickup, setting the current directory of the emacs shell buffer sync'd from the bash shell. These values are tracked in a persisent list, so that I can jump to any folder location I've ever been using ivy. Sorting order keeps frequently picked folders near the top with the help of ivy-prescient.

Scripts and functions

An elisp script that obfuscates the details of connecting to the running emacs server to interact with it, allowing me to peek at emacs state or do things in emacs from a script or shell:

$ elisp '(message "hello from the shell")'

A function shellshot that lets me take a 'text screenshot' of the current shell window contents for pastebins or sharing output:

$ uname -a
Linux bridge 4.19.86 #1-NixOS SMP Sun Nov 24 07:21:09 UTC 2019 x86_64 GNU/Linux
$ ps
  PID TTY          TIME CMD
 7217 pts/19   00:00:00 bash
 7538 pts/19   00:00:00 ps
$ emacs --version
GNU Emacs 26.3
Copyright (C) 2019 Free Software Foundation, Inc.
GNU Emacs comes with ABSOLUTELY NO WARRANTY.
You may redistribute copies of GNU Emacs
under the terms of the GNU General Public License.
For more information about these matters, see the file named COPYING.
$ shellshot

A script fzf that intercepts fzf calls and redirects them to be emacs ivy-read calls

$ echo $ESHELL
true
$ mpc listall | fzf
import/Vapor Memory/Windows彡96  - Gradient Horizont.opus

Org pomodoro status

Org mode is a markup format deeply integrated into emacs (the elisp code is the reference implementation). It's what I'm writing the post in. At it's core, org-mode is about headings and metadata around headings. I have a bind to toggle an 'active' heading, and with org-pomodoro I can toggle commands to signal pomodoro breaks, or query the current state in a script for my panel:

$ org_task
Write 'On Emacs' ■■■□□□□□□□

Contextual inline eval for lisps

I have a lisp eval function that will have different targets in different situations. When on an empty line, it will eval the last s expression. When on a not-empty line, it will eval the top s expression. And if there is anything highlighted, it will eval the region. This means I have just one eval keybind to mash. And with eros I get sexy inline eval results!:

eros.png

IRC + highlight buffer

I created a derived text mode for irc highlights that allows me to jump to mentions.

circe.png

Meta file switcher

I created a 'goto file' function that combines:

  • recent files
  • files in current project (or optionally files in all open projects)
  • open files

And then I just have to fuzzy type to get to a matching file.

Meta GOTO thing

I have a function that will follow 'thing' at point, handling:

  • urls
  • filepaths (relative or absolute, and jump to line number)
  • definitions for various languages (see smart jump)

Other