Emacs Hacks II
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
- Line numbers
- Newline sans indent
- Cursor movement
- Git status in dired
- Key bindings
- Closing remarks
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)))
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")
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
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
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
use-package does not come built-in with Emacs. You need to install it via
M-x pi RET use-package RET
You can then require it, on subsequent uses:
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)))
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)
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
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
An example would look like:
(bind-keys :map global-map ("C-;" . eval-expression) ("C-j" . delete-indentation))
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))
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)))
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)))
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))
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)))
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))
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.