More on editing Django templates in XEmacs
March 27th, 2008 by Eddie SullivanPreviously, I wrote about how I set up syntax-highlighting for Django template files using MMM (multiple major modes) in XEmacs. 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 completion.
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 tempo. 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 reader.
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-\ (control-backslash).
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 (mmm-add-classes '((my-django-expr :submode python-mode :face mmm-declaration-submode-face :front "{%" :back "%}" :include-front t :include-back t))) (mmm-add-classes '((my-django-var :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 () (interactive) (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) (add-templates-menu)))