Tempel is a tiny template package for Emacs, which uses the syntax of the Emacs Tempo library. Tempo is an ancient temple. It is 27 years old, but still in good shape since it successfully resisted change over the decades. However it may look a bit dusty here and there. Therefore I present to you, Tempel, a modernized implementation of Tempo, in the form of two commands:
tempel-expand
expands a template at point in the buffer. If called non-interactively the function behaves like a completion-at-point-function (Capf). You may want to give my Corfu completion at point UI a try.tempel-insert
selects a template by name and insert it into the current buffer.
After inserting the template you can move between the visible template fields
with the keys M-{
, M-}
or C-up/down,
which are normally bound to
forward/backward-paragraph
. Tempel temporarily remaps these commands to
tempel-next
and tempel-previous
. The key bindings are defined in the tempel-map
keymap. You can customize them there. As soon as you move before (behind) the
first (last) field, the fields are removed.
Note that this package is not a competitor to the mature and widely used YASnippet library. Try Tempel only if you like small and simple packages. With Temple you write your templates in Lisp syntax, which from my perspective fits well to the hackable nature of Emacs. Tempel took inspiration from the Tempo-Snippets package by Nikolaj Schumacher (GitHub link).
As of 2022-01-05 the package is not yet available in a package repository
and has to be installed manually with package-install-file
.
;; Bind the Tempel commands
(use-package tempel
:bind (("M-+" . tempel-expand)
("M-*" . tempel-insert)))
;; Optional: Use the Corfu completion UI
(use-package corfu
:init
(corfu-global-mode))
The template file format is a Lisp file templates
which is stored by default in
the user-emacs-directory
(~/.config/emacs/templates
). The templates are defined
as Lisp expressions in the concise form of the Emacs Tempo syntax. The first
element of the list is the name of the template. Behind the name, the Tempo
syntax elements follow.
;; -*- mode: lisp -*-
latex-mode
(begin "\\begin{" (s env) "}" > n> r> "\\end{" (s env) "}" > n)
(enumerate "\\begin{enumerate}\n\\item " r> n> "\\end{enumerate}" > n)
(itemize "\\begin{itemize}\n\\item " r> n> "\\end{itemize}" > n)
emacs-lisp-mode
(lambda "(lambda (" p ")" n> r> ")")
(var "(defvar " p "\n \"" p "\")" n n)
(const "(defconst " p "\n \"" p "\")" n n)
(custom "(defcustom " p "\n \"" p "\"" n> ":type '" p ")" n n)
(face "(defface " p " '((t :inherit font-lock-" p "-face))\n \"" p "\")" n n)
(group "(defgroup " p " nil\n \"" p "\"" n> ":group '" p n> ":prefix \"" p "-\")" n n)
(macro "(defmacro " p " (" p ")\n \"" p "\"" n> r> ")" n n)
(fun "(defun " p " (" p ")\n \"" p "\"" n> r> ")" n n)
(let "(let (" p ")" n> r> ")")
(star "(let* (" p ")" n> r> ")")
(rec "(letrec (" p ")" n> r> ")")
(command "(defun " p " (" p ")\n \"" p "\"" n> "(interactive)" n> r> ")" n n)
text-mode
(today (format-time-string "%Y-%m-%d"))
(cut "--8<---------------cut here---------------start------------->8---" n r n
"--8<---------------cut here---------------end--------------->8---" n)
(asciibox "+-" (make-string (length str) ?-) "-+" n
"| " (s str) " |" n
"+-" (make-string (length str) ?-) "-+" n)
rst-mode
(title (make-string (length title) ?=) n (s title) n (make-string (length title) ?=) n)
org-mode
(title "#+title: " p n "#+author: Daniel Mendler" n "#+language: en" n n)
All the Tempo syntax elements are fully supported. The syntax elements are
described in detail in tempo-define-template
are supported. We document the
important ones here:
"string"
Inserts a string literal.p
Inserts an unnamed placeholder field.r
Inserts the current region.(s NAME)
Inserts a named field.n
Inserts a newline.>
Indents withindent-according-to-mode
.r>
The region, but indented.n>
Inserts a newline and indents.&
Insert newline if there is only whitespace between line start and point.%
Insert newline if there is only whitespace between point and line end.o
Like%
but leaves the point before newline.
Furthermore Tempel supports syntax extensions:
(q PROMPT NAME)
Query the user viaread-string
and store the result in variableNAME
.(q (FORM ...) NAME)
ExecuteFORM
and store the result in variableNAME
.(p (FORM ...) <NAME>)
ExecuteFORM
and insert the result, optionally bind toNAME
.(FORM ...)
Other Lisp forms are evaluated. Named fields are lexically bound.
Use caution with templates which execute arbitrary code!