Red Green Repeat Adventures of a Spec Driven Junkie

Minimum Viable Emacs

I’ve been using emacs for a long time. Before emacs, I was a big vim user. I’ve stepped back into both but one big requirement I have when using them: have a minimum viable configuration.

What do I have to ‘add-on’ to make the editor feel comfortable for me?

Motivation

My main motivation for this: how can I be productive on a new system in the shortest amount of time?

I tear down and create new development environments constantly, how can I do something similar for my editor? What if I want to be productive in the new environment?

Emacs

I will start with emacs since it’s still my goto editor. Vim has entered my workflow again, but it fits different parts of my workflow that I will cover in a future post.

Looking at my old emacs configuration, the file, err, repository is pretty large and I even checked in additional packages installed, just to preserve the setup. (Talk about paranoid!)

So, I’m starting my emacs editor configuration from scratch. Get back to basics and build up the configuration, only taking the minimum amount possible to make it comfortable for me.

Ideal Emacs Setup

I would just have a single configuration file that I can check into a repository so I can get started on development on a system in a matter of minutes, not an hour.

After some work, this is what I have found to be the minimum viable setup for emacs.

Philosophy

I will split my text manipulation work into two different categories:

  • short burst manipulation
  • long period writing

I want to setup emacs so I can use it work on text for a long time. A file I will have open and keep it open to repeatedly edit in conjuntion with other files.

Main reason for this: emacs’ startup time is longer than vim. I keep open emacs for a long time whereas vim I start and quit constantly.

Configuration Goals:

  • programming IDE (i.e. will be comfortable to work in almost any project)
  • have convenient key configuration
  • work graphically or in the terminal
  • different modes for text I work in (i.e. programming modes, markdown)

New Configuration

The new configuration file is available in this repository.

I will go over parts of it for the rest of the article.

Packages

Almost any system complex enough will have its own packaging system. Emacs is no exception.

The following section is just to setup the right archive repositories to pull in additional packages from:

(require 'package)
(add-to-list 'package-archives
'("marmalade" .
"http://marmalade-repo.org/packages/"))
(add-to-list 'package-archives
'("melpa" . "http://melpa.milkbox.net/packages/") t)
(add-to-list 'package-archives
'("melpa-stable" . "https://stable.melpa.org/packages/"))
(package-initialize)

Addtional Packages

This is a list of additional packages to install that I find essential to my workflow:

;; === packages to install ===
;; magit
;; multiple-cursors
;; w3m ;; https://sourceforge.net/projects/w3m/files/latest/download?source=files
;; -> macOS: brew install w3m
;; -> linux: apt-get install w3m (?)

All of these are optional, but some explanation for my favorites:

  • magit: I just love having git in the editor. I just cannot go back to using git on the command line.
    • how to use: M-x magit-status
  • multiple-curors: after watching this video and practice using multiple cursors in different scenarios, I really love having this feature. I just can’t live without it.
    • how to use: select region and run command: M-x mc/edit-lines
  • w3m: having a web browser right in the editor is fantastic… having a text only terminal is even better. Ever wanted to just get the code to a problem you’re looking for? copy and paste right in emacs.
    • Install w3m in addition to the emacs package.
    • how to use: M-x w3m, then type a search term.
    • This is how Google results look w3m
preview

I will install more packages as needed, but these are the essential ones I yearn for on every fresh install of emacs.

Environment Configurations

The following settings sets emacs’ internal values to be nicer to work with.

(menu-bar-mode -1)
(column-number-mode 1)
(ido-mode -1)
(display-time-mode 1)
(show-paren-mode t)
  • menu-bar-mode: Turn off the menu bar, the one with items: File, Edit, Options, Buffers, Tools, Help. I prefer to get back one line. Also, in terminal mode, it’s not accessible (or I haven’t figured out how!)
  • column-number-mode: Nice addition to showing the number of characters in the cursor is in. Nice to show me when I am reaching the “80 char” limit.
  • ido-mode: super charge file navigation from the mini-buffer. When pressing delete, it removes the directory name instead of just a character. Fuzzy matches works.
  • display-time-mode: display the time on the status bar. Useful when I am in graphical emacs mode and tmux is not there.
  • show-paren-mode: shows the matching parenthesis [()] and highlights mismatched parenthesis.

Put Autosave Files in Separate Directory

By default, emacs has autosave files in the form: hello_world.txt~ in the same directory as the file, which can get pretty annoying when working with lots of files in a directory and source control.

;; autosave stuff
(make-directory "~/.emacs.d/autosaves/" t)
(setq backup-directory-alist '(("." . "~/.emacs.d/autosaves")))

This creates a directory for the autosaves and puts any autosave files in that directory.

Uniquely Name Buffers

(setq uniquify-buffer-name-style 'post-forward-angle-brackets)

This sets a different name in the buffer’s status when opening files with the same names.

For example, when opening file: hello_world.txt from two different directories, the status line will display:

hello_world.txt<directory_name_1> and hello_world.txt<directory_name_2>, respectively.

Instead of just: hello_world.txt<1> and hello_world.txt<2>, which is pretty confusing if the files are the same name.

Delete/Cut Configurations

Kill line or region

To cut or delete in emacs, one has to ‘kill’. Kill whole lines with C-k, by default, this works one line at a time.

When selecting a region (i.e. with C-space), C-k will only cut one line from the region, not the whole region. To cut a region, M-x kill-region is the command.

I prefer to have C-k to cut a line when there is no selection nothing or cut a region if a region is active.

(defun kill-line-or-region (beg end)
"kill region if active only or kill line normally"
(interactive "r")
(if (region-active-p)
(call-interactively 'kill-region)
(call-interactively 'kill-line)))
(global-set-key (kbd "C-k") 'kill-line-or-region)

I hate to admit, there’s a small bug with the above code. When cutting text in a new buffer, if there’s no active region, there is an error thrown. Cutting a region solves this bug. :-/

Backwards delete/cut word

By default, cut/delete/kill only works forward. Mapping the backward-kill-word function to

(global-set-key (kbd “C-w”) ‘backward-kill-word)

Conversely, M-d deletes a word forward from the cursor, so this is a nice inverse.

Commenting

I like to have keys: C-c c to comment and C-c u to uncomment regions of code. This is will comment a line at a time.

;; commenting regions
(global-set-key (kbd "C-c c") 'comment-region)
(global-set-key (kbd "C-c u") 'uncomment-region)

Before save hook

One can configure Emacs to run a program before or after file saves. One that I like to have: clean up extra whitespace in a file.

;; whitespace clean up on save (selective!)
;; nuke whitespaces when writing to a file
(add-hook 'before-save-hook 'whitespace-cleanup)

It is easy to configure the save hook for any program to run any emacs command, like Rubocop.

Navigating Windows

Splitting windows in emacs is C-x {2,3} for horizontal or vertical splits. To navigate from one window to another, C-x o is the only built-in key combination I know that moves window to window in terminal emacs.

Adding some more window navigation tools allows for more efficient navigation.

I like to reuse my vim muscle memory and utilize M-{h,j,k,l} to go from window to window, matching the vim directions.

(global-set-key (kbd "M-j") 'windmove-down)
(global-set-key (kbd "M-k") 'windmove-up)
(global-set-key (kbd "M-h") 'windmove-left)
(global-set-key (kbd "M-l") 'windmove-right)

Likewise, to resize windows (by default, splitting a window only splits it in half, vertically or horizontally), adding another set of keys to interactively resize.

;; window and cursor navigation:
(global-set-key (kbd "M-J") (lambda () (interactive) (enlarge-window 1)))
(global-set-key (kbd "M-K") (lambda () (interactive) (enlarge-window -1)))
(global-set-key (kbd "M-H") (lambda () (interactive) (enlarge-window -1 t)))
(global-set-key (kbd "M-L") (lambda () (interactive) (enlarge-window 1 t)))

ansi-term

Emacs’ ansi-term is a full fledged terminal, which even traps any special keys in it by default.

The main reason why I use ansi-term is that it handles interactive shells perfectly. Once I got it working with ruby, python, etc., I just couldn’t go back to emacs’ other terminals.

Main drawback over ansi-term over other emacs shells like eshell, shell, etc.: there’s no copy paste.

To navigate with ansi-term in a window, add additional hooks to move the cursor in and out.

The additional: scroll-{up, down} definitions are a lifesaver, especially when there enourmous terminal output.

;; add some key support for ansi-term (and other terms)
(eval-after-load "term"
'(progn
(define-key term-raw-map (kbd "M-j") 'windmove-down)
(define-key term-raw-map (kbd "M-k") 'windmove-up)
(define-key term-raw-map (kbd "M-h") 'windmove-left)
(define-key term-raw-map (kbd "M-l") 'windmove-right)

(define-key term-raw-map (kbd "M-v") 'scroll-down)
(define-key term-raw-map (kbd "C-v") 'scroll-up)
))

Auto-save on switching windows

Want to save some pinky soreness when using emacs? How about having the current buffer save when the cursor switches to another window?

Once I got auto-save configured, Pressing C-x C-s became a chore to save. Pressing M-{j,k} to was so much easier.

In order for this configuration to work effectively, set if for every window movement, {up, down, left, right}.

;; automatically save buffers associated with files on buffer switch
;; and on windows switch
(defadvice switch-to-buffer (before save-buffer-now activate)
(when buffer-file-name (save-buffer)))
(defadvice other-window (before other-window-now activate)
(when buffer-file-name (save-buffer)))
(defadvice windmove-up (before other-window-now activate)
(when buffer-file-name (save-buffer)))
(defadvice windmove-down (before other-window-now activate)
(when buffer-file-name (save-buffer)))
(defadvice windmove-left (before other-window-now activate)
(when buffer-file-name (save-buffer)))
(defadvice windmove-right (before other-window-now activate)
(when buffer-file-name (save-buffer)))

Conclusion

There it is, a basic minimum viable editor configuration for emacs. I went from a repository with an init.el file that was almost 300 lines with packages and packages to just a single init.el file that’s less than 100 lines.

In an upcoming article, I will go over a similar configuration for vim.