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 ")")