Emacs Tips and Tricks 2: Sessions and Packages
A bell that doesn’t ring has no purpose.
—Keel Lorenz, Neon Genesis Evangelion
Table of contents
- Introduction
- Desktop
- Savehist
- Consolidation
- Packages
- Line numbers
- Timestamps
- Keys
- Newline sans indent
- Filling
- Cursor movement
- Git status in dired
- Key bindings
- Closing remarks
Introduction
This is the continuation of the series on Emacs tips and tricks. In this article, we explore session management, packages, managing indents, and other nice little things.
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)
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
There were 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
ELPA is the package management system of Emacs. 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)
(defalias 'pr 'package-refresh-contents)
To list all the available packages, hit:
M-x pl REV
If you know the name of package, hit:
M-x pi RET package RET
To update your local database, hit:
M-x pr RET
use-package
This one is a real gem. It’s like require
, but on steroids. When require-ing 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
, for example, 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 "%5d │ ")
(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"))
Change the value of system-time-locale
as appropriate.
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 usage of bind-key
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 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)))
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 to the center, top, and bottom positions, 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, I demonstrated that small tweaks can generate huge benefits. The rest of the configuration can be found here. If you have an Emacs hack to share, send a pull request!