		 ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
		  TEMPEL - SIMPLE TEMPLATES FOR EMACS
		 ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━


Table of Contents
─────────────────

1. Template expansion
2. Configuration
3. Template file format
4. Template syntax
5. Adding template sources
6. Hooking into the Abbrev mechanism
7. Binding important templates to a key
8. Alternatives
9. Contributions


Tempel is a tiny template package for Emacs, which uses the syntax of
the Emacs Tempo library. Tempo is an ancient temple of the church of
Emacs. 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 we present Tempel, a modernized implementation of
Tempo.

Table of Contents
─────────────────

1. Template expansion
2. Configuration
3. Template file format
4. Template syntax
5. Adding template sources
6. Hooking into the Abbrev mechanism
7. Binding important templates to a key
8. Alternatives
9. Contributions


1 Template expansion
════════════════════

  Tempel comes with three commands for template expansion:

  ⁃ `tempel-complete' completes a template name at point in the buffer
    and subsequently expands the template. If called non-interactively
    the function behaves like a Capf and can be added to
    `completion-at-point-functions'.
  ⁃ `tempel-expand' expands an exactly matching template name at point
    in the buffer.  If called non-interactively the function behaves
    like a Capf and can be added to `completion-at-point-functions'.
  ⁃ `tempel-insert' selects a template by name and insert it into the
    current buffer.

  For the completion at point commands `tempel-complete' and
  `tempel-expand', you may want to give my [Corfu] completion at point
  popup UI a try. 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/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 finalized.


[Corfu] <https://github.com/minad/corfu>


2 Configuration
═══════════════

  The package is available on GNU ELPA and MELPA and can be installed
  with `package-install'. The following example configuration relies on
  `use-package'.

  ┌────
  │ ;; Configure Tempel
  │ (use-package tempel
  │   ;; Require trigger prefix before template name when completing.
  │   ;; :custom
  │   ;; (tempel-trigger-prefix "<")
  │ 
  │   :bind (("M-+" . tempel-complete) ;; Alternative tempel-expand
  │ 	 ("M-*" . tempel-insert))
  │ 
  │   :init
  │ 
  │   ;; Setup completion at point
  │   (defun tempel-setup-capf ()
  │     ;; Add the Tempel Capf to `completion-at-point-functions'.
  │     ;; `tempel-expand' only triggers on exact matches. Alternatively use
  │     ;; `tempel-complete' if you want to see all matches, but then you
  │     ;; should also configure `tempel-trigger-prefix', such that Tempel
  │     ;; does not trigger too often when you don't expect it. NOTE: We add
  │     ;; `tempel-expand' *before* the main programming mode Capf, such
  │     ;; that it will be tried first.
  │     (setq-local completion-at-point-functions
  │ 		(cons #'tempel-expand
  │ 		      completion-at-point-functions)))
  │ 
  │   (add-hook 'prog-mode-hook 'tempel-setup-capf)
  │   (add-hook 'text-mode-hook 'tempel-setup-capf)
  │ 
  │   ;; Optionally make the Tempel templates available to Abbrev,
  │   ;; either locally or globally. `expand-abbrev' is bound to C-x '.
  │   ;; (add-hook 'prog-mode-hook #'tempel-abbrev-mode)
  │   ;; (global-tempel-abbrev-mode)
  │ )
  │ 
  │ ;; Optional: Use the Corfu completion UI
  │ (use-package corfu
  │   :init
  │   (global-corfu-mode))
  └────


3 Template file format
══════════════════════

  The templates are defined in a Lisp data file configured by
  `tempel-path'. Lisp data files are files containing Lisp s-expressions
  (see `lisp-data-mode'). By default the file
  `~/.config/emacs/templates' is used. The templates are grouped by
  major mode with an optional `:when' condition. Each template is a list
  in the concise form of the Emacs Tempo syntax. The first element of
  each list is the name of the template. Behind the name, the Tempo
  syntax elements follow.

  In addition, each template may specify a `:pre' and/or `:post' key
  with a FORM that is evaluated before the template is expanded or after
  it is finalized, respectively. The `:post' form is evaluated in the
  lexical scope of the template, which means that it can access the
  template's named fields.

  ┌────
  │ ;; ~/.config/emacs/templates
  │ 
  │ fundamental-mode ;; Available everywhere
  │ 
  │ (today (format-time-string "%Y-%m-%d"))
  │ 
  │ prog-mode
  │ 
  │ (fixme (if (derived-mode-p 'emacs-lisp-mode) ";; " comment-start) "FIXME ")
  │ (todo (if (derived-mode-p 'emacs-lisp-mode) ";; " comment-start) "TODO ")
  │ (bug (if (derived-mode-p 'emacs-lisp-mode) ";; " comment-start) "BUG ")
  │ (hack (if (derived-mode-p 'emacs-lisp-mode) ";; " comment-start) "HACK ")
  │ 
  │ latex-mode
  │ 
  │ (begin "\\begin{" (s env) "}" r> n> "\\end{" (s env) "}")
  │ (frac "\\frac{" p "}{" q "}")
  │ (enumerate "\\begin{enumerate}\n\\item " r> n> "\\end{enumerate}")
  │ (itemize "\\begin{itemize}\n\\item " r> n> "\\end{itemize}")
  │ 
  │ lisp-mode emacs-lisp-mode ;; Specify multiple modes
  │ 
  │ (lambda "(lambda (" p ")" n> r> ")")
  │ 
  │ emacs-lisp-mode
  │ 
  │ (autoload ";;;###autoload")
  │ (pt "(point)")
  │ (lambda "(lambda (" p ")" n> r> ")")
  │ (var "(defvar " p "\n  \"" p "\")")
  │ (local "(defvar-local " p "\n  \"" p "\")")
  │ (const "(defconst " p "\n  \"" p "\")")
  │ (custom "(defcustom " p "\n  \"" p "\"" n> ":type '" p ")")
  │ (face "(defface " p " '((t :inherit " p "))\n  \"" p "\")")
  │ (group "(defgroup " p " nil\n  \"" p "\"" n> ":group '" p n> ":prefix \"" p "-\")")
  │ (macro "(defmacro " p " (" p ")\n  \"" p "\"" n> r> ")")
  │ (alias "(defalias '" p " '" p ")")
  │ (fun "(defun " p " (" p ")\n  \"" p "\"" n> r> ")")
  │ (iflet "(if-let (" p ")" n> r> ")")
  │ (whenlet "(when-let (" p ")" n> r> ")")
  │ (iflet* "(if-let* (" p ")" n> r> ")")
  │ (whenlet* "(when-let* (" p ")" n> r> ")")
  │ (andlet* "(and-let* (" p ")" n> r> ")")
  │ (cond "(cond" n "(" q "))" >)
  │ (pcase "(pcase " (p "scrutinee") n "(" q "))" >)
  │ (let "(let (" p ")" n> r> ")")
  │ (let* "(let* (" p ")" n> r> ")")
  │ (rec "(letrec (" p ")" n> r> ")")
  │ (dotimes "(dotimes (" p ")" n> r> ")")
  │ (dolist "(dolist (" p ")" n> r> ")")
  │ (loop "(cl-loop for " p " in " p " do" n> r> ")")
  │ (command "(defun " p " (" p ")\n  \"" p "\"" n> "(interactive" p ")" n> r> ")")
  │ (advice "(defun " (p "adv" name) " (&rest app)" n> p n> "(apply app))" n>
  │ 	"(advice-add #'" (p "fun") " " (p ":around") " #'" (s name) ")")
  │ (provide "(provide '" (file-name-base (or (buffer-file-name) (buffer-name))) ")" n
  │ 	 ";;; " (file-name-nondirectory (or (buffer-file-name) (buffer-name))) " ends here" n)
  │ 
  │ eshell-mode
  │ 
  │ (for "for " (p "i") " in " p " { " q " }")
  │ (while "while { " p " } { " q " }")
  │ (until "until { " p " } { " q " }")
  │ (if "if { " p " } { " q " }")
  │ (ife "if { " p " } { " p " } { " q " }")
  │ (unl "unless { " p " } { " q " }")
  │ (unle "unless { " p " } { " p " } { " q " }")
  │ 
  │ text-mode
  │ 
  │ (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)
  │ (rot13 (p "plain text" text) n "----" n (rot13 text))
  │ (calc (p "taylor(sin(x),x=0,3)" formula) n "----" n (format "%s" (calc-eval formula)))
  │ 
  │ rst-mode
  │ 
  │ (title (make-string (length title) ?=) n (p "Title: " title) n (make-string (length title) ?=) n)
  │ 
  │ java-mode
  │ 
  │ (class "public class " (p (file-name-base (or (buffer-file-name) (buffer-name)))) " {" n> r> n "}")
  │ 
  │ c-mode :when (re-search-backward "^\\S-*$" (line-beginning-position) 'noerror)
  │ 
  │ (inc "#include <" (p (concat (file-name-base (or (buffer-file-name) (buffer-name))) ".h")) ">")
  │ (incc "#include \"" (p (concat (file-name-base (or (buffer-file-name) (buffer-name))) ".h")) "\"")
  │ 
  │ org-mode
  │ 
  │ (title "#+title: " p n "#+author: Daniel Mendler" n "#+language: en" n n)
  │ (quote "#+begin_quote" n> r> n> "#+end_quote")
  │ (example "#+begin_example" n> r> n> "#+end_example")
  │ (center "#+begin_center" n> r> n> "#+end_center")
  │ (comment "#+begin_comment" n> r> n> "#+end_comment")
  │ (verse "#+begin_verse" n> r> n> "#+end_verse")
  │ (src "#+begin_src " p n> r> n> "#+end_src" :post (org-edit-src-code))
  │ (elisp "#+begin_src emacs-lisp" n> r> n "#+end_src" :post (org-edit-src-code))
  │ 
  │ ;; Local Variables:
  │ ;; mode: lisp-data
  │ ;; outline-regexp: "[a-z]"
  │ ;; End:
  └────


4 Template syntax
═════════════════

  All the Tempo syntax elements are fully supported. The syntax elements
  are described in detail in the docstring of `tempo-define-template' in
  tempo.el. We document the important ones here:

  • "string" Inserts a string literal.
  • `p' Inserts an unnamed placeholder field.
  • `n' Inserts a newline.
  • `>' Indents with `indent-according-to-mode'.
  • `r' Inserts the current region.  If no region is active, quits the
    containing template when jumped to.
  • `r>' Acts like `r', but indent region.
  • `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.
  • `(s NAME)' Inserts a named field.
  • `(p PROMPT <NAME> <NOINSERT>)' Insert an optionally named field with
    a prompt.  The `PROMPT' is displayed directly in the buffer as
    default value. If `NOINSERT' is non-nil, no field is inserted. Then
    the minibuffer is used for prompting and the value is bound to
    `NAME'.
  • `(r PROMPT <NAME> <NOINSERT>)' Insert region or act like `(p ...)'.
  • `(r> PROMPT <NAME> <NOINSERT>)' Act like `(r ...)', but indent
    region.

  Furthermore Tempel supports syntax extensions:

  • `(p FORM <NAME> <NOINSERT>)' Like `p' described above, but `FORM' is
    evaluated.
  • `(FORM ...)' Other Lisp forms are evaluated. Named fields are
    lexically bound.
  • `q' Quits the containing template when jumped to.

  Use caution with templates which execute arbitrary code!


5 Adding template sources
═════════════════════════

  Tempel offers a flexible mechanism for providing the templates, which
  are applicable to the current context. The variable
  `tempel-template-sources' specifies a list of sources or a single
  source. A source can either be a function, which should return a list
  of applicable templates, or the symbol of a variable, which holds a
  list of templates, which apply to the current context.  By default,
  Tempel configures only the source `tempel-path-templates'. You may
  want to add global or local template variables to your user
  configuration:

  ┌────
  │ (defvar my-global-templates
  │   '((example "Global example template"))
  │   "My global templates.")
  │ (defvar-local my-local-templates nil
  │   "Buffer-local templates.")
  │ (add-to-list 'tempel-template-sources 'my-global-templates)
  │ (add-to-list 'tempel-template-sources 'my-local-templates)
  └────


6 Hooking into the Abbrev mechanism
═══════════════════════════════════

  Tempel can hook into Abbrev by enabling the `tempel-abbrev-mode' in a
  buffer or by enabling the `global-tempel-abbrev-mode'. Then the Tempel
  templates will be available via `expand-abbrev' which is usually bound
  to `C-x ''.


7 Binding important templates to a key
══════════════════════════════════════

  Important templates can be bound to a key with the small utility macro
  `tempel-key' which accepts three arguments, a key, a template or name
  and optionally a map.

  ┌────
  │ (tempel-key "C-c t f" fun emacs-lisp-mode-map)
  │ (tempel-key "C-c t d" (format-time-string "%Y-%m-%d"))
  └────

  Internally `tempel-key' uses `tempel-insert' to trigger the
  insertion. Depending on the style of your user configuration you may
  want to write your own helper macros, which allow you to conveniently
  bind templates via [use-package], [general] or similar keybinding
  packages.


[use-package] <https://github.com/jwiegley/use-package>

[general] <https://github.com/noctuid/general>


8 Alternatives
══════════════

  Tempel does not come with readily available snippet collections,
  unlike the YASnippet library. Try Tempel if you like small and simple
  packages. With Tempel 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]).

  There are plenty of alternative packages which provide abbreviation or
  snippet expansion.

  • abbrev.el: Abbreviation expansion, builtin
  • skeleton.el: Lisp syntax for templates, builtin
  • tempo.el: Lisp syntax for templates, builtin
  • [aas.el]: Auto activating snippets
  • [cdlatex.el]: Fast LaTeX insertion
  • [laas.el]: Latex auto activating snippets
  • [muban.el]: Lightweight template expansion
  • [placeholder.el]: Treat buffers as templates
  • [skempo.el]: Unifies the Skeleton and Tempo configuration
  • [snippet.el]: Original snippet mode
  • [tempo-snippets.el]: snippet.el-like interface for Tempo
  • [yasnippet.el]: The most popular template system


[Tempo-Snippets] <https://nschum.de/src/emacs/tempo-snippets/>

[GitHub link] <https://github.com/nschum/tempo-snippets.el>

[aas.el] <https://github.com/ymarco/auto-activating-snippets>

[cdlatex.el] <https://github.com/cdominik/cdlatex>

[laas.el] <https://github.com/tecosaur/LaTeX-auto-activating-snippets>

[muban.el] <https://github.com/jiahaowork/muban.el>

[placeholder.el] <https://github.com/oantolin/placeholder>

[skempo.el] <https://github.com/xFA25E/skempo>

[snippet.el] <https://github.com/pkazmier/snippet.el>

[tempo-snippets.el] <https://nschum.de/src/emacs/tempo-snippets/>

[yasnippet.el] <https://github.com/joaotavora/yasnippet>


9 Contributions
═══════════════

  Since this package is part of [GNU ELPA] contributions require a
  copyright assignment to the FSF.


[GNU ELPA] <https://elpa.gnu.org/packages/tempel.html>
