1

I have this in my init file

(use-package autoinsert
  :ensure t
  :init
  ;; Don't want to be prompted before insertion:
  (setq auto-insert-query nil)

  (setq auto-insert-directory (locate-user-emacs-file "templates"))
  (add-hook 'find-file-hook 'auto-insert)
  (auto-insert-mode 1)

  :config
  (define-auto-insert "poolchem.org?$" "poolchem.org"))

IOW, I have the template file poolchem.org in ~/.emacs.d/templates/, which contains six tables. I went this route because it seemed easier than hand-tooling such a big thing in (customize-variable 'auto-insert-alist). But I would like various bits of embedded initialization code to run upon creating poolchem.org, e.g.,

(org-read-date nil nil "++mon" nil (org-time-string-to-time "2020-03-31"))

should place the date of the next Monday after 2020-03-31 in the text upon file open. How can I do this? I've experimented with eval of org-sbe in # local variables: ... but that was handy for running code blocks upon file open, not individual embedded functions.

3
  • Might I ask you to clarify what you mean by "embedded functions" here? Embedded where? – RichieHH Feb 24 '20 at 21:44
  • If I have #+DATE: (org-read-date nil nil "++mon" nil (org-time-string-to-time "2020-03-31")) I would like the function evaluated and the result substituted in. – 147pm Feb 25 '20 at 0:08
  • Ah ok, embedded function calls. Thanks. – RichieHH Feb 25 '20 at 8:01
2

You can specify a vector of actions for each entry in auto-insert-alist.
This way you can insert the contents of the template file with the first action and then use a function that searches the new file for special elisp forms that are to be replaced with their evaluated results.

Below you find the source code for one such function.
You just wrap your code in the template file with (auto-insert-init-form ...) and that form will be evaluated like progn.
The last form of the code must return a string that is used to replace the code in the target file.

(defcustom auto-insert-init-form 'auto-insert-init-form
  "Symbol identifying init forms in template files."
  :group 'auto-insert
  :type 'symbol)

(defun my-eval-auto-insert-init-form ()
  "Evaluate (AUTO-INSERT-INIT-FORM ...) in autoinsert templates.
Thereby, AUTO-INSERT-INIT-FORM stands for the symbol defined by
the customizable variable `auto-insert-init-form'.
\(auto-insert-init-form ...) works like `progn'.
Applied in the newly created file it should return the string
that replaces the form."
  (goto-char (point-min))
  (cl-letf (((symbol-function auto-insert-init-form) #'progn))
    (while (re-search-forward "(auto-insert-init-form[[:space:]]" nil t)
      (let* ((beg (goto-char (match-beginning 0)))
         (end (with-syntax-table emacs-lisp-mode-syntax-table
            (forward-sexp)
            (point)))
         (str (eval (read (buffer-substring beg end)))))
    (delete-region beg end)
    (insert str)))))

(define-auto-insert
  "poolchem.org?\\'"
  ["poolchem.org"
   my-eval-auto-insert-init-form])

Example of the contents of a template file:

| first | table |

#+DATE: (auto-insert-init-form (org-read-date nil nil "++mon" nil (org-time-string-to-time "2020-03-31")))

#+AUTHOR: (auto-insert-init-form (read-string "Author: "))

| SOME | OTHER | TABLE |
|      |       |       |
2
  • Thanks. This worked straight out of the box. Curious, though. Why did you create the symbol auto-insert-init-form with a defcustom when there doesn't seem to be anything to customize about it? Would a defvar have sufficed? – 147pm Feb 26 '20 at 6:12
  • @147pm The defcustom allows you to use something else than auto-insert-init-form as form to be evaluated after auto-insert. Whether this makes sense or not is up to the user. – Tobias Feb 28 '20 at 4:57

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.