dotfiles/emacs-lisp/tempel.org
2023-09-16 19:54:12 +02:00

168 lines
5.1 KiB
Org Mode

:PROPERTIES:
:ID: a0514202-b2ef-41a4-9d77-01efaa7e8d64
:END:
#+title: Tempel
#+filetags: emacs-load
# SPDX-FileCopyrightText: 2022 Richard Brežák <richard@brezak.sk>
#
# SPDX-License-Identifier: LGPL-3.0-or-later
#+begin_quote
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 to you, Tempel, a modernized
implementation of Tempo, in the form of three commands.
#+end_quote
#+begin_src emacs-lisp :noweb yes
(use-package tempel
:straight '(tempel :type git :host github :repo "minad/tempel")
:config
<<tempel-path>>
:init
<<tempel-hooks>>
<<tempel-keymaps>>)
#+END_SRC
Set the template file to the result of tangling [[id:3e8f0e02-dbfe-4f34-9b00-8b7ecd0a238d][Tempel - Templates]].
#+name: tempel-path
#+begin_src emacs-lisp
(setq tempel-path (expand-file-name "~/roam/emacs-lisp/templates.lisp"))
#+end_src
Hook ~tempel-capf~ on both ~prog-mode~ and ~text-mode~.
#+name: tempel-hooks
#+begin_src emacs-lisp
(defun tempel-setup-capf ()
(add-hook 'completion-at-point-functions #'tempel-complete -100 'local))
(add-hook 'prog-mode-hook 'tempel-setup-capf)
(add-hook 'text-mode-hook 'tempel-setup-capf)
(add-hook 'lsp-mode-hook 'tempel-setup-capf)
#+end_src
Define keymaps, the defaults are unnecessarily hard to trigger.
#+name: tempel-keymaps
#+begin_src emacs-lisp
(general-define-key
:keymaps '(insert normal)
"C-n" 'nil
"C-p" 'nil)
(general-define-key
:keymaps 'tempel-map
"M-{" nil
"M-}" nil
"C-n" 'tempel-next
"C-p" 'tempel-previous)
#+end_src
Fix LSP not getting notified about changes, can be fixed by notifying it at the end of template expansion.
#+begin_src emacs-lisp
(advice-add
'tempel--disable
:before
(lambda (&rest r)
(when lsp-mode
(let* ((region-start (tempel--beginning))
(region-end (tempel--end)))
(lsp-on-change region-start region-end (- region-end region-start))))))
#+end_src
To setup a post template return point, use ~(tempel-retpoint-here)~ in a template.
#+begin_src emacs-lisp
(defun org-edit-special-latex-preview (&rest _)
(let ((datum (org-element-context)))
(when (and (memq (org-element-type datum) '(latex-environment latex-fragment))
(let ((beg (org-element-property :begin datum))
(end (org-element-property :end datum)))
(when (org-clear-latex-preview beg end)
(setq-local tempel-latex-preview t)))))))
(advice-add
'org-edit-special
:before
#'org-edit-special-latex-preview)
#+end_src
#+begin_src emacs-lisp
(defvar-local tempel-retpoint (make-marker))
(defvar-local tempel-latex-preview nil)
(defun tempel-retpoint-here ()
"Place a marker at `point' to allow for return on tempel exit."
(set-marker tempel-retpoint (point))
"")
(defun tempel-retpoint-goto ()
"Move `point' to `tempel-retpoint'."
(when (marker-position tempel-retpoint)
(goto-char (marker-position tempel-retpoint))
(set-marker tempel-retpoint nil)))
(add-hook
'tempel--disable
#'tempel-retpoint-goto)
(defvar org-src-mode-exit-hook nil)
(defun org-edit-src-exit-run-hooks (&rest _)
"Run hooks from `org-edit-src-exit-hook' upon exiting org-src edit buffer."
(run-hooks 'org-src-mode-exit-hook))
(advice-add
'org-edit-src-exit
:after
#'org-edit-src-exit-run-hooks)
(defun org-edit-src-exit-tempel-retpoint ()
"Return to `tempel-retpoint' if set."
(tempel-retpoint-goto))
(defun org-edit-src-exit-tempel-latex-preview ()
"Toggle LaTeX preview of templated LaTeX fragment."
(when tempel-latex-preview
(org-latex-preview)
(setq-local tempel-latex-preview nil)))
(add-hook
'org-src-mode-exit-hook
#'org-edit-src-exit-tempel-latex-preview)
(add-hook
'org-src-mode-exit-hook
#'org-edit-src-exit-tempel-retpoint)
(defun tempel-post-edit-latex (&optional preview move-back)
"Move `point' back and run `org-edit-special'.
If PREVIEW is non-nil then `org-latex-preview' will be called on
the resulting LaTeX block. Move point that MOVE-BACK lines back to
reach a good spot in the LaTeX block, defaults to `-2'."
(forward-line (or move-back -2))
(end-of-line)
(setq-local tempel-latex-preview preview)
(org-edit-special))
#+end_src
To allow for ~=>~ as template keys, ~'symbol~ won't work, but ~'evil-word~ will.
#+begin_src emacs-lisp
(defun tempel--prefix-bounds ()
"Return prefix bounds."
(if tempel-trigger-prefix
(let ((end (point))
(beg (save-excursion
(search-backward tempel-trigger-prefix
(line-beginning-position) 'noerror))))
(when (and beg (save-excursion
(not (re-search-backward "\\s-" beg 'noerror))))
(cons (+ beg (length tempel-trigger-prefix)) end)))
(bounds-of-thing-at-point 'symbol)))
#+end_src