emacs-orgmode
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

[O] Templating with Org


From: Eric Abrahamsen
Subject: [O] Templating with Org
Date: Thu, 03 Sep 2015 16:49:37 +0800
User-agent: Gnus/5.130014 (Ma Gnus v0.14) Emacs/25.0.50 (gnu/linux)

A while ago I asked about creating a system that repeats body text for
many Org headings -- essentially writing an export template that is
re-used for many headings. Search through Gmane is tedious and strangely
inaccurate, so I'm not bothering to find the original thread.

I've come up with a solution that others might find useful -- I'm also
hoping for some tips on improving it. I suppose I can add it to Worg
later.

I'll paste the function at the bottom, but what I'm talking about is
this:

#+BEGIN_SOURCE org
Templating Test
:PROPERTIES:
:EXPORT_BODY_TEMPLATE: template-heading
:END:
** Bob Jones
:PROPERTIES:
:SALUTATION: Dear Mr Jones
:MARMOTS:  390
:END:
** Janet Smith
:PROPERTIES:
:SALUTATION: Dear Prof. Smith
:MARMOTS:  9
:END:
** Unknown
:PROPERTIES:
:SALUTATION: Dear Sir/Madame
:MARMOTS:  42
:END:
Also, would you at your earliest convenience please remind us of your
name?
* Template body                                                    :noexport:
:PROPERTIES:
:ID:       template-heading
:END:
{{{property(SALUTATION)}}},

This is an automatically-generated form letter, informing you that you
have {{{property(MARMOTS)}}} marmots remaining in your account at the
United Bank of Marmots.

@@body@@

Yours truly,\\
Director of the United Bank of Marmots
#+END_SOURCE

When this is exported, the body of the "Template body" heading is
switched in for the bodies of each of the children of "Templating test".
That lets you use property macros to fill in the template context. As a
special case, the string "@@body@@" will be replaced with the original
body of the exported heading, if there is one.

The function below works fine, though I'd sure like to know if anyone
has any suggestions for cleaning it up, particular the bits about
finding and extracting heading bodies.

More unfortunately, it doesn't work if you restrict the export scope to
the "Templating Test" subtree, because the "EXPORT_BODY_TEMPLATE"
property isn't seen. I'd sure like to find a way to fix that.

I suppose one solution would be to explicitly add EXPORT_BODY_TEMPLATE
to the list of inherited properties, and then remove the inner
`org-map-entries'. But one of the things I like about the current
arrangement is that it is limited to direct children of the heading with
that property set.

Anyway, comments and improvements welcome!

Eric


#+BEGIN_SOURCE emacs-lisp
(defun org-template-replace (backend)
  "Do template body replacement in the exported region.

For any heading that has the EXPORT_BODY_TEMPLATE property set,
treat the value of that property as an org heading id, find that
heading, get its body text, and replace the body text of each of
this heading's children with that text.

This can be used to write a single export template which is then
used for many headings."
  (let ((org-use-property-inheritance nil))
    (org-map-entries
     (lambda ()
       (let ((targ (org-entry-get (point) "EXPORT_BODY_TEMPLATE"))
             (level (org-current-level))
             original-body template-body)
         (when targ
           (setq template-body
                 (save-excursion
                   (org-id-goto targ)
                   (org-end-of-meta-data t)
                   (when (or (looking-at org-heading-regexp)
                             (= (point) (point-max)))
                     (user-error "Template heading has no body text."))
                   (buffer-substring-no-properties
                    (point)
                    (progn (org-next-visible-heading 1)
                           (point)))))
           (save-restriction
             (org-narrow-to-subtree)
             (org-map-entries
              (lambda ()
                (org-end-of-meta-data t)
                (cond
                 ((looking-at org-heading-regexp)
                  (open-line 1))
                 ((= (point) (point-max))
                  (newline))
                 (t (setq original-body
                          (delete-and-extract-region
                           (point)
                           (progn
                             (save-excursion
                               (org-next-visible-heading 1)
                               (point)))))))
                
                (insert
                 (replace-regexp-in-string
                  (if original-body
                      "@@body@@"
                    "@@body@@\n\n") (or original-body "") template-body))
                (setq org-map-continue-from (1- (point))))
              (format "LEVEL=%d" (1+ level)))))))
     "EXPORT_BODY_TEMPLATE<>\"\"")))

(add-hook 'org-export-before-processing-hook #'org-template-replace)

#+END_SOURCE




reply via email to

[Prev in Thread] Current Thread [Next in Thread]