Chicken Scratches

More on editing Django templates in XEmacs

Previously, I wrote about how I set up syntax-highlighting for
Django template files using MMM (multiple major modes) in
. This entry builds on the previous one, so if you haven’t
read that one, I suggest doing so now.

This post addresses the age old question, “If (X)Emacs is so
good, why can’t it do the typing for me?” Well, the answer, of
course, is it can. You just have to write a few lines of Lisp
first. Or you can copy and paste the Lisp code off of sites like
this one. ;)

Introducing dynamic abbreviations

Pressing M-/, (that is, holding down the Alt key and
pressing the forward slash key), runs the command
dabbrev-expand, which tries to finish whatever word you
are in the middle of typing. For example, if as I’m typing this
entry, I type the letter d, then press M-/,
“dabbrev-expand” shows up, because that was the last word I
typed that started with d. If I then type M-/
again, “dabbrev-expand” changes to “down”. If I keep pressing
it, the word cycles through different guesses for what I’m going
for. If you’ve ever used VisualStudio, you may see some
similarities to the Intellisense feature. I find I almost never
type a whole word anymore, I’ve become so dependent on dynamic

Templates and more abbreviations

dabbrev-expand is useful to avoid having to type long
words over and over, but there are also longer patterns that
seem to need typing frequently. Thats where the tempo
package comes in handy, especially when combined with the
abbrev library. Here is some documentation for
. Here is some documentation for abbrev.

Essentially, tempo allows you to specify “templates,” or
blocks of standard text that can be parameterized as they are
filled in: the same concept as Django templates, but meant for
interactive use. From now on, I will say “tempo template” or
“Django template” to avoid confusing the two types.

abbrev lets you define your own pre-set abbreviations,
which can be filled in automatically as you type or upon
request. This can be combined with tempo to do some
pretty powerful stuff very easily.

I have a few Django-specific tempo templates and abbrevs set up
in my XEmacs initialization file. For example, as soon as I type
“{% block” followed by a space, the entire framework of a Django
template block is filled in for me. I’ve also added a special
menu to the menu bar for tempo templates I use frequently.

HTML and templates can be very repetitive, so I’ve found this
saves me a lot of typing.

My initialization file

Here is the subset of my ~/.xemacs/init.el file. This includes
the mmm-mode stuff I discussed last time, as well as the
tempo templates and abbrevs. I haven’t put a tempo template for
every possible Django template tag, just the ones I use most
frequently. I’ll leave further extension as an exercise for the

Also, some people don’t like the expansion to happen
automatically as they are typing. To turn this off, comment out
the line that says “(setq abbrev-mode t)” by putting a semicolon
(;) in front of it. Then you can
manually expand tempo templates by pressing C-\

Once again, this is known to work in XEmacs version 21.4 on
Windows XP. It will most likely work in other versions of
XEmacs, and possibly in GNU Emacs.

;; CSS-Mode
(autoload 'css-mode "css-mode" "Mode for editing CSS files" t)
(add-to-list 'auto-mode-alist '("\\.css\\'" . css-mode))
(setq cssm-indent-function #'cssm-c-style-indenter)
(setq cssm-indent-level '2)

;; Use hm--html-mode for files that end in .tmpl (Django templates)
(add-to-list 'auto-mode-alist '("\\.tmpl\\'" . hm--html-mode))

;; Multiple Major Modes.
(require 'mmm-vars)
(require 'mmm-mode)
(require 'mmm-sample)
(setq mmm-global-mode 'maybe)

;; Custom MMM classes for Django templates
    :submode python-mode
    :face mmm-declaration-submode-face
    :front "{%"
    :back "%}"
    :include-front t
    :include-back t)))

    :submode python
    :face mmm-output-submode-face
    :front "{{"
    :back "}}"
    :include-front t
    :include-back t)))

(mmm-add-mode-ext-class nil "\\.tmpl\\'" 'embedded-css)
(mmm-add-mode-ext-class nil "\\.tmpl\\'" 'my-django-var)
(mmm-add-mode-ext-class nil "\\.tmpl\\'" 'my-django-expr)
(mmm-add-mode-ext-class nil "\\.tmpl\\'" 'html-js)

;; Use different colors for different sub-modes.
(setq mmm-submode-decoration-level 2)
;; Make the code submode a little more readable.
(set-face-background 'mmm-code-submode-face "#EEEEFF")

;; Tempo templates and abbrevs

;; Control-backslash to expand a tempo template manually.
(global-set-key "\C-\\" 'tempo-complete-tag)

(require 'adapt) ; Must be done before hm--html for some reason.
(require 'hm--html-mode) ; Needed for hm--html-mode-abbrev-table
(require 'tempo) ; Tempo templates.

;; Expands <span into an HTML span with a class defined.
(tempo-define-template "span"
                       '("<span class=\"" (p "Class? ") "\">" r "</span>" >)
                       "<span "
                       "Insert a template for a span with a class")
(define-abbrev hm--html-mode-abbrev-table
  "<span" "" 'tempo-template-span)

;; Expands <script into an HTML javascript block.
(tempo-define-template "script"
                       '(> "<script type=\"text/javascript\">" r "</script>" > %)
                       "<script "
(define-abbrev hm--html-mode-abbrev-table
  "<script" "" 'tempo-template-script)

;; Expands a Django template block.
(tempo-define-template "block"
                       '("{% block " (p "Block name? ") " %}" p "{% endblock %}")
                       "{% block "
(define-abbrev hm--html-mode-abbrev-table
  "{% block" "" 'tempo-template-block)

;; Expands a Django template if tag.
(tempo-define-template "django-if"
                       '("{% if " (p "Conditional? ") " %}" p "{% endif %}")
                       "{% if "
(define-abbrev hm--html-mode-abbrev-table
  "{% if" "" 'tempo-template-django-if)

;; Expands a Django template for tag.
(tempo-define-template "django-for"
                       '("{% for "
                         (p "Variable? ") " in "
                         (p "List? ") " %}" p
                         "{% endfor %}")
                       "{% for "
(define-abbrev hm--html-mode-abbrev-table
  "{% for" "" 'tempo-template-django-for)

;; Create a menu for inserting these templates.
(defun add-templates-menu ()
  (add-submenu nil '("Tem%_plates"
                     ["{%% %_block %%}" tempo-template-block]
                     ["{%% %_if %%}" tempo-template-django-if]
                     ["{%% %_for %%}" tempo-template-django-for]
                     ["<%_span>" tempo-template-span]
                     ["<s%_cript>" tempo-template-script])))

;; When entering hm--html-mode, turn on abbrevs and add the template menu.
(add-hook 'hm--html-mode-hook
          (lambda ()
            (setq abbrev-mode t)