tricks I learned to make using tempel smoother

Having gotten to a more stable state with my Emacs configuration, I have been focused less on its structure and more on enhancing the features that I have neglected. One of these is text completion or as Emacs calls it "auto-typing". This had lead me to revisit and enhance my configuration for tempel. And in the process I collected several useful tricks which I share here.

make tempel-map an overriding map

Frustratingly, when I first began using tempel the keybindings to tempel-map in evil-insert-state were not working. It took me forever to fix this. The problem was that despite binding insert state keys for tempel-map, default evil bindings still took precedence. The solution is to tell evil to make those keybindings precedence make tempel-map an intercept map.

(eval-after-load 'tempel
  '(eval-after-load 'evil
     (evil-make-overriding-map tempel-map)))

ensure insert state after inserting a template

You can be certain you will be typing text right after inserting a template because there will be fields you have to fill out. That is why I recommend advising tempel-insert to enter insert state after it is done. In general, configuring functions to enter insert state is so common when using evil that I recommend a dedicated function for this.

(setq-local completion-at-point-functions '(cape-dabbrev t))
(defun oo--enter-evil-insert-state-maybe (&rest _)
  "Enter insert state if `evil-mode' is enabled."
  (when (bound-and-true-p evil-mode)
    (evil-insert-state 1)))

(advice-add 'tempel-insert :after #'oo--enter-evil-insert-state-maybe)

properly use map an abbrev to a tempel expansion

First let me mention the solution that tempel provides: tempel-abbrev-mode. That mode defines abbrevs for every named template, puts them in an abbrev table. This solution is too crude and opinionated for my taste. It assumes that you want the abbrevs to be the same name you defined for your tempel templates. And it decides how to set up the abbrev table for you. This is designed for someone who just wants something working fast.

If you are not in a rush. What I recommend is just doing it explicitly with good old define-abbrev. Specify the circumstances when an abbrev should be active in the :enable-function property.

(defun oo-expand-elisp-defun ()
  (interactive)
  (tempel-insert '"(defun " p " (" p ")" n> "\"" p "\"" n> r ")")
  ;; This is important, the will still be inserted despite having added the
  ;; `no-self-insert' property if this function does not return a non-nil value.
  ;; Note `tempel-insert' returns nil.  I learned this the hard-way.
  t)

(put 'oo-expand-elisp-defun 'no-self-insert t)

(define-abbrev global-abbrev-table "dfn" "" #'oo-expand-elisp-defun :enable-function #'oo-in-elisp-mode-p)

simplify creating templates with a macro

I recommend making a macro similar to define-skeleton. When I dabbled with skeletons I became quite endeared to the define-skeleton macro. Despite being simple it made things more convenient.

(defmacro deftempel! (name &rest body)
  "Define a tempel template."
  (declare (doc-string 2) (indent defun))
  (setq documentation (when (stringp (car body)) (list (pop body))))
  `(progn (defun ,name ()
            ,@documentation
            (interactive)
            (tempel-insert ',body)
            t)
          (put ',name 'no-self-insert t)
          ',name))

remember to use the region

Remember to use the r element. This makes it so that when a region is active when you invoke the command it will wrap the snippet around the region. Also noteworthy is. As in afte the region but I would prefer the cursor still in the snippet.

(deftempel! oo-expand-to-defun
  "Expand to defun."
  "(defun " p " (" p ")" n> "\"" p "\"" n> r ")")