The ox-extend
package requires ox-publish.el
to advise org-publish-file
and use the org-publish-property
:
(require 'ox-publish)
The ox-extend-extensions-alist
is an association list for registered extensions:
Each extension must register itseld in this list when it's loaded to be available for use in publishing projects.
(setq ox-extend-extensions-alist '())
Each element consists of a symbol that identifies the extension and a list with an :add
function to add the extension's advise and a :remove
function to remove it.
'('ox-html-git-mtime :add (lambda () (advice-add 'org-html-title :around #'ox-html-upcase-title)) :remove (lambda () (advice-remove 'org-html-title #'ox-html-upcase-title))
To extend the functionality of the org-publish-file
function, ox-extend--advise
provides advise to add and remove the registered extensions.
It finds the :add
and :remove
functions for all extensions added to the project's :extensions
list in the ox-extend-extensions-alist
.
For each extenson, the :add
function is executed before org-publish-file
, and :remove
is called immediately after.
This adds the extensions when they're needed, and removes them to prevent them from interfering with future publishing:
(defun ox-extend--advise (orig-fun &rest args) "Advise org-publish-file (ORIG-FUN) to add and remove each extension contained in ARGS." (let ((extensions (org-publish-property :extensions (nth 1 args)))) (dolist (extension extensions) (ox-extend--apply extension :add)) (apply orig-fun args) (dolist (extension extensions) (ox-extend--apply extension :remove)))) (defun ox-extend--apply (extension add_or_remove) "Call the ADD_OR_REMOVE function for an EXTENSION." (apply (plist-get (cdr (assoc extension ox-extend-extensions-alist)) add_or_remove) ()))
The ox-extend-add
and ox-extend-remove
add and remove the main advise, enabling and disabling all extensions completely.
When loading ox-extend.el
, ox-extend-add
is automatically called to install the main advise.
The ox-extend-remove
function exists for convenience and shouldn't have to be used regularly, if ever.
(defun ox-extend-add () (advice-add 'org-publish-file :around #'ox-extend--advise)) (defun ox-extend-remove () (advice-remove 'org-publish-file #'ox-extend--advise)) (ox-extend-add)
Finally, use the provide
fucntion to announce ox-extend.el
:
(provide 'ox-extend)
Example
The hello world example adds advise to print "hello, world!" before org-publish-file
is called, and "goodbye, world!" after.
Start by loading ox-extend.el
by adding its directory to the load-path
and calling require
:
(add-to-list 'load-path ".") (require 'ox-extend)
With ox-extend.el
loaded, add the extension to ox-extend-extensions-alist
by passing an association list with an :add
and a :remove
key.
Instead of actually altering the publishing behavior, both functions print a message to the *Messages*
buffer:
(add-to-list 'ox-extend-extensions-alist '('hello-world :add (lambda () (message "hello, world!")) :remove (lambda () (message "goodbye, world!"))))
To try the extension, call org-publish-file
with a project that lists 'hello-world
as one of its :extensions
:
(org-publish-file "ox-extend.org" '("ox-extend-example" :base-directory "." :publishing-directory "dist" :extensions ('hello-world)))
The *Messages*
buffer prints both messages:
hello, world! Publishing file ox-extend.org using ‘org-html-publish-to-html’ goodbye, world!
Writing extensions
As an example, we're writing an extension named ox-md-title
, which adds document titles to markdown files generated with ox-md
.
Writing an extension involves advising one or more functions and registering the extension to be available to publishing projects.
This extension will advise org-md-template
, which currently only returns the generated document contents:
(defun org-md-template (contents _info) contents)
Our aim is to prepend the document's title with the correct markup.
First, require ox-extend
.
Unlike the example above, actual extensions don't alter the load path:
(require 'ox-extend)
Then, write an :around
advice for org-md-template
, which gets the original funcion and arguments.
In the function body, we call out to org-md--headline-title
to generate the title with arguments we find from the second argument in args
:
(defun ox-md-title--advise-template (orig-fun &rest args) (let ((info (nth 1 args))) (let ((style (plist-get info :md-headline-style)) (title (org-export-data (plist-get info :title) info))) (concat (org-md--headline-title (plist-get info :md-headline-style) 1 (org-export-data (plist-get info :title) info) nil) (apply orig-fun args)))))
To enable the extension, add ox-md-title-add
and ox-md-title-remove
and add them to the ox-extend-extensions-alist
.
We're also setting the org-md-toplevel-hlevel
to 2
, as the extension adds an extra headline to the root of the page:
(defun ox-md-title-add () (setq org-md-toplevel-hlevel 2) (advice-add 'org-md-template :around #'ox-md-title--advise-template)) (defun ox-md-title-remove () (setq org-md-toplevel-hlevel 1) (advice-remove 'org-md-template #'ox-md-title--advise-template)) (add-to-list 'ox-extend-extensions-alist '('ox-md-title :add ox-md-title-add :remove ox-md-title-remove))
Finally, provide
the ox-md-title.el
package:
(provide 'ox-md-title)
And use the extension when publishing1:
(add-to-list 'load-path ".") (require 'ox-md-title) (org-publish-file "ox-extend.org" '("ox-extend-markdown" :base-directory "." :publishing-directory "." :publishing-function org-gfm-publish-to-gfm :extensions ('ox-md-title)))
The exporter now prepends the document title in the Markdown export:
head ox-extend.md
# ox-extend: Structured extensions for ox.el - [Example](#example) - [Writing extensions](#writing-extensions) The `ox-extend` package requires `ox-publish.el` to advise `org-publish-file` and use the `org-publish-property`: ```emacs-lisp (require 'ox-publish)