Emacs Redux

Return to the Essence of Text Editing

Removing/Altering Key Bindings From Minor Mode Keymaps

| Comments

Often minor modes don’t respect standard keybinding conventions and use some user reserved keys (like C-c a). Occasionally two minor modes would have conflicting keybindings or a minor mode would keybindings conflicting with a major mode. I guess you can imagine similar problems. Dealing with them is fairly straight-forward - we have to either unbind or rebind the offending binding:

1
2
3
4
5
;; remove keybinding
(define-key minor-mode-map (kbd "C-c c") nil)

;; change keybinding
(define-key minor-mode-map (kbd "C-c c") (kbd "C-c C-c"))

Generally speaking you can use define-key to alter the keymap of a major mode as well, but those are rarely offenders when it comes to picking appropriate keybindings for their keymaps.

Normally you’d want to invoke the above code right after the related minor (or major) mode is loaded:

1
2
(eval-after-load "minor-mode"
  '(define-key minor-mode-map (kbd "C-c c") nil))

Making a minor mode have different keymaps in different major modes is tricky, but possible. Here’s an example that disables some keybindings in the minor prelude-mode, that are conflicting with the major org-mode:

1
2
3
4
5
6
7
8
9
10
11
(defun my-org-mode-hook ()
  (let ((oldmap (cdr (assoc 'prelude-mode minor-mode-map-alist)))
        (newmap (make-sparse-keymap)))
    (set-keymap-parent newmap oldmap)
    (define-key newmap (kbd "C-c +") nil)
    (define-key newmap (kbd "C-c -") nil)
    (make-local-variable 'minor-mode-overriding-map-alist)
    (push `(prelude-mode . ,newmap) minor-mode-overriding-map-alist))
)

(add-hook 'org-mode-hook 'my-org-mode-hook)

Dired Jump

| Comments

Most Emacs users know that they can start dired (Emacs’s file browser) with M-x dired or C-x d. That would display a prompt in the minibuffer asking which directory to open with dired (the current directory will be suggested as a default).

More often than not you’ll probably want dired to display the directory of file you’re currently editing. You might even want to have the cursor positioned over that very same file in the dired buffer. There’s a cool command that does exactly that - dired-jump. To use it you have to first load the built-in library dired-x:

1
(require 'dired-x)

You can run the command with C-x C-j (M-x dired-jump). No prompts, no wasted time. You’re instantly teleported to the currently edited file’s position in a dired buffer.

This command works out-of-the-box in Prelude.

A Proper Replacement for Flet

| Comments

The popular flet macro was deprecated in Emacs 24.3 and replaced with two similar macros - cl-flet and cl-letf.

flet was used to temporarily override function definitions. This was an analogue of a dynamically scoped let that operates on the function cell of symbols rather than their value cell.

The ability to dynamically rebind a functions was very useful for stubbing purposes in unit tests (you do write unit tests, don’t you?).

1
2
3
(flet ((projectile-project-root () "/path/to/project")
       (projectile-project-name () "project"))
  ...)

projectile-project-root and projectile-project-name are impure functions (they depend on the current directory) and testing functions that use them internally would normally be problematic. However, flet gives us the ability to override their actual definitions in our tests. flet’s official replacement cl-flet is lexically bound and this is no longer possible with it.

Fortunately Nic Ferrier created a true drop-in flet replacement (with some extra magic baked in) - noflet. If you’re missing flet, I suggest you to give noflet a try.

Version Checks

| Comments

Often the code you’re writing would be depending on the version of some external tool (say git) or Emacs itself. Version checks in Emacs are pretty easy - just use the built-in functions version=, version<= or version=.

Let’s illustrate this with an example. Prelude requires at least GNU Emacs 24.1 to run and on startup it performs the following check:

1
2
(when (version< emacs-version "24.1")
  (error "Prelude requires at least GNU Emacs 24.1"))

Simple and effective. The version functions are pretty smart and recognize most popular version formats correctly. Note that version string “1” is equal to “1.0”, “1.0.0”, “1.0.0.0”, etc. That is, the trailing “.0”s are insignificant. Also, version string “1” is higher (newer) than “1pre”, which is higher than “1beta”, which is higher than “1alpha”. Also, “-CVS” and “-NNN” are treated as alpha versions.

If you’re writing an Emacs package you can also add an explicit Emacs version dependency in the packge metadata:

1
;; Package-Requires: ((emacs "24.1"))

That way users of older Emacsen would not see a version of your package targeting newer Emacsen.

Search Youtube

| Comments

Some time ago I showed you how to do Google queries from Emacs. The approach used in that articles is pretty generic and can be used for the creation of various similar commands. Let’s create a command that searches in YouTube:

1
2
3
4
5
6
7
8
9
(defun youtube ()
  "Search YouTube with a query or region if any."
  (interactive)
  (browse-url
   (concat
    "http://www.youtube.com/results?search_query="
    (url-hexify-string (if mark-active
                           (buffer-substring (region-beginning) (region-end))
                         (read-string "Search YouTube: "))))))

This command will display the query results in your default browser.

I’d suggest binding the command to C-c y if you plan to use it regularly.

1
(global-set-key (kbd "C-c y") 'youtube)

youtube is available in Prelude(but with a prelude- prefix).

Color Themes: Redux

| Comments

Prelude

This is a slightly refreshed version of an article originally published on my personal blog.

If there is something that people love as much as tweaking their editing configurations it’s probably the selection of color themes. A good color theme can make your work much more pleasant and a bad one that literally impair your vision. It’s a fact of life that I’m a firm supporter of low-contrast color themes with dark backgrounds - I find them easy on the eyes and I feel that they don’t strain the eyes as much as most themes. I’ve even ported a couple of popular themes to Emacs - Zenburn and Solarized.

In this short article we’ll see how color theming has changed in Emacs 24 and I’ll share with you a few tips on theme creation and distribution.

Increment and Decrement Integer at Point

| Comments

While editing you often have to increment or decrement some number (usually an integer) by some step. Obviously this is trivial when the number is something like 10, but not pretty pleasant when the number is 2343566 and you want to increment it by 943. Most of the time, however, you’ll probably be incrementing or decrementing by 1.

A long time ago I found a bit of code by Ryan Thompson to help us deal with such tasks. Here’s a slightly modified version of the original code:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
(require 'thingatpt)

(defun thing-at-point-goto-end-of-integer ()
  "Go to end of integer at point."
  (let ((inhibit-changing-match-data t))
    ;; Skip over optional sign
    (when (looking-at "[+-]")
      (forward-char 1))
    ;; Skip over digits
    (skip-chars-forward "[[:digit:]]")
    ;; Check for at least one digit
    (unless (looking-back "[[:digit:]]")
      (error "No integer here"))))
(put 'integer 'beginning-op 'thing-at-point-goto-end-of-integer)

(defun thing-at-point-goto-beginning-of-integer ()
  "Go to end of integer at point."
  (let ((inhibit-changing-match-data t))
    ;; Skip backward over digits
    (skip-chars-backward "[[:digit:]]")
    ;; Check for digits and optional sign
    (unless (looking-at "[+-]?[[:digit:]]")
      (error "No integer here"))
    ;; Skip backward over optional sign
    (when (looking-back "[+-]")
        (backward-char 1))))
(put 'integer 'beginning-op 'thing-at-point-goto-beginning-of-integer)

(defun thing-at-point-bounds-of-integer-at-point ()
  "Get boundaries of integer at point."
  (save-excursion
    (let (beg end)
      (thing-at-point-goto-beginning-of-integer)
      (setq beg (point))
      (thing-at-point-goto-end-of-integer)
      (setq end (point))
      (cons beg end))))
(put 'integer 'bounds-of-thing-at-point 'thing-at-point-bounds-of-integer-at-point)

(defun thing-at-point-integer-at-point ()
  "Get integer at point."
  (let ((bounds (bounds-of-thing-at-point 'integer)))
    (string-to-number (buffer-substring (car bounds) (cdr bounds)))))
(put 'integer 'thing-at-point 'thing-at-point-integer-at-point)

(defun increment-integer-at-point (&optional inc)
  "Increment integer at point by one.

With numeric prefix arg INC, increment the integer by INC amount."
  (interactive "p")
  (let ((inc (or inc 1))
        (n (thing-at-point 'integer))
        (bounds (bounds-of-thing-at-point 'integer)))
    (delete-region (car bounds) (cdr bounds))
    (insert (int-to-string (+ n inc)))))

(defun decrement-integer-at-point (&optional dec)
  "Decrement integer at point by one.

With numeric prefix arg DEC, decrement the integer by DEC amount."
  (interactive "p")
  (increment-integer-at-point (- (or dec 1))))

The code is based on the popular built-in library thing-at-point and extends it to make it aware of integer numbers. The commands increment-integer-at-point and decrement-integer-at-point operate with a step of 1 by default, but with a prefix argument you can select any step you desire. Unlike other similar commands floating in the Internet, these two handle correctly numbers like -3434 and +343.

I’d suggest binding these commands to C-c + and C-c -:

1
2
(global-set-key (kbd "C-c +") 'increment-integer-at-point)
(global-set-key (kbd "C-c -") 'decrement-integer-at-point)

Both commands are available in Prelude(but with a prelude- prefix).

Highlight Comment Annotations

| Comments

Programming code is often filled with comment annotations indicating stuff that should be done in the future.

1
2
3
# REFACTOR: Decouple and clean up this crap.

# crappy code omitted

Normally Emacs doesn’t highlight such comment annotations, unless you’re using some minor mode like fic-mode. I find such mode overkill given the fact we can cook a pretty decent solution in just about 5 lines of code:

1
2
3
4
5
6
7
8
9
(defun font-lock-comment-annotations ()
  "Highlight a bunch of well known comment annotations.

This functions should be added to the hooks of major modes for programming."
  (font-lock-add-keywords
   nil '(("\\<\\(FIX\\(ME\\)?\\|TODO\\|OPTIMIZE\\|HACK\\|REFACTOR\\):"
          1 font-lock-warning-face t))))

(add-hook 'prog-mode-hook 'font-lock-comment-annotations)

And that’s all there is to it. This code is not perfect, since it would highlight FIXME: everywhere in the source code (as opposed to only in comments), but it’s extremely highly unlikely that it’ll appear outside of the source comments anyways.

As usual Prelude users get this functionally for free out-of-the-box.

Make Use of the Super Key

| Comments

Emacs users have a lot of power at their disposal, but in one department they are always short - the number of available non-complex keybindings that they can leverage.

Obviously nobody likes pressing keybindings like C-p C-v k (or something like that). One way to get your hands on some extra keybindings is to utilize the Super key (it’s the Windows key on Win keyboards and the Command key on Mac keyboards (although most people remap Command to Meta and Option to Super)). One great thing about Super is that you generally have two of them, which makes them touch-typing friend. Since almost no packages use those keys you’re left with plenty of options.

Prelude defines a bunch of global keybindings that use the Super key.

1
2
3
4
5
6
7
8
9
10
11
12
13
;; make some use of the Super key
(define-key global-map [?\s-d] 'projectile-find-dir)
(define-key global-map [?\s-e] 'er/expand-region)
(define-key global-map [?\s-f] 'projectile-find-file)
(define-key global-map [?\s-g] 'projectile-grep)
(define-key global-map [?\s-j] 'prelude-top-join-line)
(define-key global-map [?\s-k] 'prelude-kill-whole-line)
(define-key global-map [?\s-l] 'goto-line)
(define-key global-map [?\s-m] 'magit-status)
(define-key global-map [?\s-o] 'prelude-open-line-above)
(define-key global-map [?\s-w] 'delete-frame)
(define-key global-map [?\s-x] 'exchange-point-and-mark)
(define-key global-map [?\s-p] 'projectile-switch-project)

If you find pressing Super comfortable obviously you have the potential to add quite a lot more keybindings to this list.

P.S. Some keyboards (notably laptop ones) have a Fn key as well that’s also usable in Emacs keybindings. Somewhat funny that key is known in Emacs as Hyper (Star Wars fans are undoubtedly adding a Hyper-Space keybinding to their setups right about now).

Advise Multiple Commands in the Same Manner

| Comments

One of the well known features of Prelude is that it saves buffers with changes in them automatically when you jump between windows. This is achieved with several simple defadvices and without going into many details the advice code for that feature might look like this:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
;; automatically save buffers associated with files on buffer switch
;; and on windows switch
(defadvice switch-to-buffer (before switch-to-buffer-auto-save activate)
  (prelude-auto-save))
(defadvice other-window (before other-window-auto-save activate)
  (prelude-auto-save))
(defadvice windmove-up (before other-window-auto-save activate)
  (prelude-auto-save))
(defadvice windmove-down (before other-window-auto-save activate)
  (prelude-auto-save))
(defadvice windmove-left (before other-window-auto-save activate)
  (prelude-auto-save))
(defadvice windmove-right (before other-window-auto-save activate)
  (prelude-auto-save))

Ouch - that a lot of redundant code! Luckily we can take care of the redundancy by introducing a macro to generate multiple advices with the same body:

1
2
3
4
5
6
7
8
9
(defmacro advise-commands (advice-name commands &rest body)
  "Apply advice named ADVICE-NAME to multiple COMMANDS.

The body of the advice is in BODY."
  `(progn
     ,@(mapcar (lambda (command)
                 `(defadvice ,command (before ,(intern (concat (symbol-name command) "-" advice-name)) activate)
                    ,@body))
               commands)))

Looks a bit scary, doesn’t it? But it allows us to reduce the original code down to:

1
2
3
4
;; advise all window switching functions
(advise-commands "auto-save"
                 (switch-to-buffer other-window windmove-up windmove-down windmove-left windmove-right)
                 (prelude-auto-save))

macroexpand can show us how the macro gets expanded:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
(macroexpand '(advise-commands "auto-save"
                 (switch-to-buffer other-window windmove-up windmove-down windmove-left windmove-right)
                 (prelude-auto-save)))

(progn
  (defadvice switch-to-buffer
    (before switch-to-buffer-auto-save activate)
    (prelude-auto-save))
  (defadvice other-window
    (before other-window-auto-save activate)
    (prelude-auto-save))
  (defadvice windmove-up
    (before windmove-up-auto-save activate)
    (prelude-auto-save))
  (defadvice windmove-down
    (before windmove-down-auto-save activate)
    (prelude-auto-save))
  (defadvice windmove-left
    (before windmove-left-auto-save activate)
    (prelude-auto-save))
  (defadvice windmove-right
    (before windmove-right-auto-save activate)
    (prelude-auto-save)))

Obviously if we want the macro to be truly universal we should factor out the hardcoded before and activate defadvice params, but that’s beside the point. The point is that when you need to generate some code Emacs Lisp’s macros have your back.