Emacs Hacks II

June 12, 2015
Updated: May 13, 2016

This is second part of my Emacs tips series. The contents of this post are written in no particular order. It explores session management, packages, managing indents, and other things.

Table of contents

Desktop

An indispensable tool that I use now is desktop. It saves the state of my Emacs session, so that in the event of crash, power outage, or anything that will make me lose my session, I can back to it. Desktop comes built-in with the recent versions of GNU Emacs. Here's my snippet:

(require 'desktop)

(desktop-save-mode)

(setq desktop-dirname "~/.emacs.d"
      desktop-base-file-name "desktop"
      desktop-base-lock-name "desktop.lock"
      desktop-restore-frames t
      desktop-restore-reuses-frames t
      desktop-restore-in-current-display t
      desktop-restore-forces-onscreen t)

(defun desktop-save ()
  (interactive)
  (if (eq (desktop-owner) (emacs-pid))
      (desktop-save desktop-dirname)))

Savehist

Another important functionality that I use is savehist. It saves the minibuffer history. It’s roughly similar to saving the command line history. Here’s my snippet

(savehist-mode t)

(setq savehist-file "~/.emacs.d/savehist")

Consolidation

No, that is not the name of a library. There are a lot of times, when I want to manually save the state of as much session information that I could save. I’d want to save the buffers, minibuffer history, bookmarks, and comint mode histories. To do that, I have the following:

(defun save-defaults ()
  (desktop-save desktop-dirname)
  (savehist-save)
  (bookmark-save))

(defun save-histories ()
  (let ((buf (current-buffer)))
    (save-excursion
      (dolist (b (buffer-list))
        (switch-to-buffer b)
        (save-history)))
    (switch-to-buffer buf)))

(defun save ()
  (interactive)
  (save-desktop)
  (save-defaults)
  (save-histories))

This gives you a nice:

M-x save RET

Packages

ELPA

If you aren’t using the package system yet, use it now. All you need to get started is the following:

(require 'package)

(setq package-archives
      '(("gnu" . "http://elpa.gnu.org/packages/")
        ("marmalade" . "http://marmalade-repo.org/packages/")
        ("melpa" . "http://melpa.milkbox.net/packages/")))

(package-initialize)

(defalias 'pi 'package-install)
(defalias 'pl 'package-list-packages)

To list all the available packages, hit:

M-x pl RET

If you know the name of package, hit:

M-x pi RET package RET

use-package

This one is a real gem. It’s like require, but on steroids. When “requiring” a package, you have the option to specify to install that package, if it does not exist, yet. It also enables you to configure that package, in a unified expression. But unlike require, use-package does not come built-in with Emacs. You need to install it via package-install:

M-x pi RET use-package RET

You can then require it, on subsequent uses:

(require 'use-package)

To install markdown-mode, even if it doesn’t exist yet, and configure its related options, after loading it, have:

(use-package markdown-mode
    :ensure t
    :config
    (progn
      (push '("\\.text\\'" . markdown-mode) auto-mode-alist)
      (push '("\\.markdown\\'" . markdown-mode) auto-mode-alist)
      (push '("\\.md\\'" . markdown-mode) auto-mode-alist)))

Line numbers

I really like to have the line numbers displayed at the left margin. It gives me a rough idea how big the file is, and where am I currently. Turning on linum-mode achieves it:

(setq linum-format "%4d")

(defun my-linum-mode-hook ()
  (linum-mode t))

(add-hook 'find-file-hook 'my-linum-mode-hook)

Timestamps

I frequently find the need to insert timestamps, especially when I'm editing my daily log file. Here are some snippets to help you with it:

(defun format-date (format)
  (let ((system-time-locale "en_US.UTF-8"))
    (insert (format-time-string format))))

(defun insert-date ()
  (interactive)
  (format-date "%A, %B %d %Y"))

(defun insert-date-and-time ()
  (interactive)
  (format-date "%Y-%m-%d %H:%M:%S"))

The code above sets the correct value for system-time-locale, and binds keys for insert-date/long and insert-date/short.

Keys

When your key bindings are not organized, it’s not easy to find what key did you bind to what. Fortunately, you have bind-key, which comes as part of use-package.

An example would look like:

(bind-keys
 :map global-map
 ("C-;" . eval-expression)
 ("C-j" . delete-indentation))

Newline sans indent

This command creates a newline, then moves the cursor. It simulates a behavior wherein the new line doesn’t indent.

(defun newline-and-no-indent (&optional arg)
  (interactive "p")
  (open-line arg)
  (next-line arg))

Filling

This snippet works great when working when working with plain text. It indent a paragraph, or the current paragraph context. If there is a mark, the region becomes filled.

(defun fill-region-or-paragraph ()
  (interactive)
  (if (region-active-p)
      (fill-region)
      (fill-paragraph)))

Yanking

Emacs, by default, pastes (yanks) from the secondary, or clipboard selection. This command yanks from the primary selection — mouse highlights.

(defun yank-primary ()
  (interactive)
  (insert-for-yank (x-get-selection 'PRIMARY)))

Cursor movement

The command move-to-window-line-top-bottom, bound by default to M-r is great when you want to move the cursor from the center, top, and bottom position, relative to the window, similar to Vim’s H, M, and L commands. However, it’s not very efficient when specifically targetting areas of the screen. The commands below position point, specifically to the top, center, and bottom window positions, respectively.

(defun move-to-window-line-top ()
  (interactive)
  (move-to-window-line 0))

(defun move-to-window-line-center ()
  (interactive)
  (move-to-window-line nil))

(defun move-to-window-line-bottom ()
  (interactive)
  (move-to-window-line -1))

Git status in dired

This small snippet gives visual indications of the status of git-managed files in a Dired buffer. Pressing g reloads the buffer, then updates the status.

(use-package dired-k
    :ensure t
    :config
  (progn
    (add-hook 'dired-initial-position-hook 'dired-k)))

Key bindings

The key bindings for the commands above, are listed below:

(bind-keys
 :map global-map
 ("C-c d"   . insert-date)
 ("C-c C-d" . insert-date-and-time)

 ("S-<return>" . newline-and-no-indent)

 ("M-q" . fill-region-or-paragraph)

 ("C-M-y" . yank-primary)

 ("M-1" . move-to-window-line-top)
 ("M-2" . move-to-window-line-center)
 ("M-3" . move-to-window-line-bottom))

(bind-keys
 :map dired-mode-map
 ("K" . dired-k)
 ("g" . dired-k))

Closing remarks

In this post, it was demonstrated that small tweaks can generate huge benefits.

The rest of the configuration can be found at https://github.com/ebzzry/dotfiles/tree/master/emacs. If you an Emacs hack to share, send a pull request.