Nuggets from my .emacs: Part I

Wednesday, February 13, 2013

Nuggets from my .emacs” is a series wherein I will occasionally put up small but nevertheless quite useful functions in Emacs Lisp that help enhance daily productivity. This post here is Part I.

You can also get my entire Emacs config on Github.

1. Intuitive window resizing

NOTE: “Windows” in Emacs are different from “windows” in the conventional sense used today. When you split a screen into 2 “panes” using C-x 3, the 2 panes are called “windows”. Conventional windows, created using C-x 5 2, are called “frames” in the Emacs world.

I never really got the hang of C-x { (shrink-window-horizontally), C-x } (enlarge-window-horizontally), and C-x ^ (enlarge-window) for resizing windows. When I split my screen vertically and I want to change the window sizes, I’m usually thinking of how I should move the border between the 2 windows, rather than whether I want to enlarge or shrink the current window. Fortunately I found the following nugget on the Internet (credits to the original author; I have long since lost the source link):

;; intuitive window resizing
(defun xor (b1 b2)
  (or (and b1 b2)
      (and (not b1) (not b2))))

(defun move-border-left-or-right (arg dir)
  "General function covering move-border-left and move-border-right. If DIR is
     t, then move left, otherwise move right."
  (interactive)
  (if (null arg) (setq arg 3))
  (let ((left-edge (nth 0 (window-edges))))
    (if (xor (= left-edge 0) dir)
        (shrink-window arg t)
        (enlarge-window arg t))))

(defun move-border-up-or-down (arg dir)
  "General function covering move-border-up and move-border-down. If DIR is
     t, then move up, otherwise move down."
  (interactive)
  (if (null arg) (setq arg 3))
  (let ((top-edge (nth 1 (window-edges))))
    (if (xor (= top-edge 0) dir)
        (shrink-window arg nil)
        (enlarge-window arg nil))))

(defun move-border-left (arg)
  (interactive "P")
  (move-border-left-or-right arg t))

(defun move-border-right (arg)
  (interactive "P")
  (move-border-left-or-right arg nil))

(defun move-border-up (arg)
  (interactive "P")
  (move-border-up-or-down arg t))

(defun move-border-down (arg)
  (interactive "P")
  (move-border-up-or-down arg nil))

I have the following keybindings corresponding to these functions:

;; keybindings for window resizing
(global-set-key (kbd "M-S-<left>") 'move-border-left)
(global-set-key (kbd "M-S-<right>") 'move-border-right)
(global-set-key (kbd "M-S-<up>") 'move-border-up)
(global-set-key (kbd "M-S-<down>") 'move-border-down)

2. Live hex color previews

I find this pretty handy when I’m writing CSS or customizing my Emacs theme, notwithstanding the fact that I’m colourblind.

;; CSS color values colored by themselves
;; http://news.ycombinator.com/item?id=873541
(defvar hexcolor-keywords
  '(("#[abcdef[:digit:]]+"
     (0 (put-text-property
         (match-beginning 0)
         (match-end 0)
         'face (list :background
                     (match-string-no-properties 0)))))))

(defun hexcolor-add-to-font-lock ()
  (font-lock-add-keywords nil hexcolor-keywords))

Then all you need to do is add some major mode hooks:

(add-hook 'css-mode-hook 'hexcolor-add-to-font-lock)
(add-hook 'emacs-lisp-mode-hook 'hexcolor-add-to-font-lock)
(add-hook 'less-css-mode-hook 'hexcolor-add-to-font-lock)

and see your hex colors light up right there in front of you :)

3. Comment or uncomment a region or line

This a no-nonsense function that does exactly what it says on the tin:

(defun comment-or-uncomment-region-or-line ()
  "Like comment-or-uncomment-region, but if there's no mark \(that means no
region\) apply comment-or-uncomment to the current line"
  (interactive)
  (if (not mark-active)
      (comment-or-uncomment-region
       (line-beginning-position) (line-end-position))
    (if (< (point) (mark))
        (comment-or-uncomment-region (point) (mark))
      (comment-or-uncomment-region (mark) (point)))))

Immensely useful; I have it bound to C-c C-r.

4. “Smart” Home key

This one takes the boring old Home key and puts it on steroids. The new and improved Home key toggles between the first non-whitespace character on the current line, and the very first column on the line.

;; "smart" home, i.e., home toggles b/w 1st non-blank character and 1st column
(defun smart-beginning-of-line ()
  "Move point to first non-whitespace character or beginning-of-line."
  (interactive "^") ; Use (interactive "^") in Emacs 23 to make shift-select work
  (let ((oldpos (point)))
    (back-to-indentation)
    (and (= oldpos (point))
         (beginning-of-line))))

I use it all the time, so I’ve replaced the default Home and C-a keys with this:

(global-set-key [home] 'smart-beginning-of-line)
(global-set-key (kbd "C-a") 'smart-beginning-of-line)

That’s all for Part I.


blog comments powered by Disqus