When I chose a text editor, nearly fifteen years ago, I chose emacs because I liked the idea of using something that was deeply customizable. While I didn't intend to start using that customization immediately, it seemed to me like it would be much more future-proof to learn something flexible. I've never actually used this very much, but a couple weeks ago I wrote a new mode for the first time, so I thought I'd write that up.

I keep my calendar as an html table, and every so often I go over it to move activities that have happened to the past. One could automate this completely, but I I like having an opportunity to review things and make fixes. So about five years ago I wrote a little function:

(defun move-to-past () (interactive) (setq debug-on-error t) (search-forward "<tr>") (beginning-of-line) (let ((mtp-killed-text (delete-and-extract-region (point) (progn (forward-line 5) (point))))) (find-file "~/jtk/past.html") (beginning-of-buffer) (search-forward "<tr>") (beginning-of-line) (insert mtp-killed-text)))

This was easier than what I used to do: manually finding the line, pressing ctrl+k ten times, opening past.html , finding the right line, pressing ctrl+y . But it was still kind of annoying: I needed to type meta-x then move-to-p[tab][enter] , and do this for each entry I was moving. It wasn't so annoying that I couldn't stand it, but it was irritating enough that I often put off moving things from future.html to past.html for months at a time.

I wanted to make this easier to invoke, so that I could just press a simple keyboard shortcut and move the entry to the past. I had set shortcut keys before, like:

(global-set-key "\C-xg" 'goto-line)

This means I can type ctrl+g 53 and jump to line 53, which is great. Except this is a global shortcut, and if I set a nice short shortcut for move-to-past that would get in the way when I was in other contexts. I needed to make something that only applied to future.html , so I defined a new mode:

(define-derived-mode procsched-future-mode html-mode "ProcScheduleFuture")

So far, all this does is create procsched-future-mode , which is just an alias for the mode for editing html.

Next we can define a shortcut that applies only to this mode:

(define-key procsched-future-mode-map "\C-p" 'move-to-past)

Now if I'm in procsched-future-mode and press ctrl+p , it will trigger move-to-past .

Manually enabling procsched-future-mode mode is annoying, though, so I can set it to enable automatically for files named future.html :

(add-to-list 'auto-mode-alist '("future\\.html\\'" . procsched-future-mode))

Now whenever I'm in a context when I would want to press ctrl+p for move-to-past it will just work, but ctrl+p is still available for other uses in other contexts.

We can go a step farther, and define a few more useful things, so we can easily delete entries or switch back from past to future after moving something:

(defun delete-event () (interactive) (setq debug-on-error t) (search-forward "<tr>") (beginning-of-line) (delete-and-extract-region (point) (progn (forward-line 5) (point)))) (defun switch-to-future () (interactive) (setq debug-on-error t) (switch-to-buffer "future.html")) (define-derived-mode procsched-past-mode html-mode "ProcSchedulePast") (define-key procsched-future-mode-map "\C-o" 'delete-event) (define-key procsched-past-mode-map "\C-p" 'switch-to-future) (add-to-list 'auto-mode-alist '("past\\.html\\'" . procsched-past-mode))

Now I can press ctrl+p to move something to past , then ctrl+p again to move back to future . Or I can press ctrl+o to delete the event if it didn't actually happen.