Pages
  • one.el
  • Install one.el
  • Getting started
  • How does one.el work?
  • one-default render function
  • Miscellaneous
  • one-ox
  • one-ox | headline
  • one-ox | src-block
  • one-ox | quote-block
  • one-ox | fixed-width and example-block
  • one-ox | links
  • one-ox | plain-list and item
one.el
  • one.el
  • Install one.el
  • Getting started
  • How does one.el work?
  • one-default render function
  • Miscellaneous
  • one-ox
  • one-ox | headline
  • one-ox | src-block
  • one-ox | quote-block
  • one-ox | fixed-width and example-block
  • one-ox | links
  • one-ox | plain-list and item

Miscellaneous

Table of content
  • Page at point
  • onerc.el file
  • one-add-to-global
  • one-hook
    • feed.xml example
    • robot.txt and sitemap.txt
      • robot.txt
      • sitemap.txt
  • Async commands
  • Extend one-ox org backend
    • Extend one-ox with horizontal-rule org elements

Page at point

If we need to render only the page at point, meaning the headline of level 1 with ONE and CUSTOM_ID org properties set, we can use the commands one-render-page-at-point and one-render-page-at-point-async.

onerc.el file

We can use an Emacs Lisp file called onerc.el to customize our website. It must be in the same directory of the org file containing the content of our website.

This file is loaded first in one-render-pages before rendering the webpages.

This is a good place to set one-add-to-global and one-hook variables or to define our own render functions.

one-add-to-global

Render functions takes 3 arguments:

  • page-tree: the parsed tree of the page being rendered,

  • pages: the list of pages,

  • global: a plist of global informations that are computed once in one-render-pages before rendering the pages using one-add-to-global variable.

That means that if a render function needs extra informations, we can use one-add-to-global variable to pass those informations to the render function.

Specifically, elements in one-add-to-global list are plist with the following properties:

  • :one-global-property: a keyword that is used as proprety in the global argument passed to the render functions,

  • :one-global-function: a function that takes two arguments pages (list of pages, see one-list-pages) and tree (see one-parse-buffer). That function is called once in one-render-pages and its result is used as the value of the property :one-global-property in the global argument passed to the render functions.

For instance, if one-add-to-global is set to

((:one-global-property :one-tree
  :one-global-function (lambda (pages tree) tree)))

then global local variable will be set to

((:one-tree tree))

where tree is the value returned by one-parse-buffer function.

one-hook

Each function in one-hook is called once in one-render-pages.

Those functions take three arguments:

  • pages: list of pages (see one-list-pages),

  • tree: see one-parse-buffer,

  • global: see one-add-to-global.

As those functions take global argument they are called after that argument has been let binded using one-add-to-global.

feed.xml example

This hook is used to build feed.xml file of minibuffer.tonyaldon.com website. You can check onerc.el file of tonyaldon/minibuffer.tonyaldon.com repository to see how it is done.

robot.txt and sitemap.txt

If we want to add a sitemap.txt file to our website we can do so using one-hook.

robot.txt

First we need to indicate in a robots.txt where our sitemap.txt is located.

Assuming our website is https://example.com and our sitemap.txt file is at the root of it, we can add the following robots.txt file in the assets directory (./assets/robots.txt):

User-Agent: *
Allow: /
Sitemap: https://domain.com/sitemap.txt

sitemap.txt

Now in onerc.el file:

  1. we set our domain with protocol in the variable domain,

  2. then we define make-sitemap function which will create the file sitemap.txt in the public directory (./public/sitemap.txt) each time be build our website,

  3. Finally, to tell one.el to actually create sitemap.txt file using make-sitemap function each time be build our website, we add it to one-hook:

(defvar domain "https://example.com"
  "Domain with protocol to be used to produce sitemap file.

See `make-sitemap'.")

(defun make-sitemap (pages tree global)
  "Produce file ./public/sitemap.txt

Global variable `domain' is used as domain with protocol.
This function is meant to be added to `one-hook'."
  (with-temp-file "./public/sitemap.txt"
    (insert
     (mapconcat 'identity
                (mapcar
                 (lambda (page)
                   (let* ((path (plist-get page :one-path))
                          (link (concat domain path)))
                     link))
                 pages)
                "\n"))))

(add-hook 'one-hook 'make-sitemap)

Thanks @tanrax for the code snippet (see issue #6).

Async commands

The function one-render-pages-async and one-build-async spawn an emacs subprocess in order to build html pages asynchronously. The arguments passed to emacs depends on one-emacs-cmd-line-args-async value.

By default, when one-emacs-cmd-line-args-async is nil, we run emacs in "batch mode", we load the user's initialization file and we evaluate a specific sexp that builds html pages. Specifically, we pass the following command (emacs file name followed by command line arguments) to make-process function like this:

(let* ((emacs (file-truename
               (expand-file-name invocation-name invocation-directory)))
       (command `(,emacs "--batch"
                         "-l" ,user-init-file
                         "--eval" ,sexp))
       (sexp ...))
  (make-process
   :name ...
   :buffer ...
   :command command))

If one-emacs-cmd-line-args-async is non-nil, we no longer load the user's initialization file and replace "-l" ,user-init-file in command above by the elements of one-emacs-cmd-line-args-async. For instance, if one-emacs-cmd-line-args-async is equal to

'("-l" "/path/to/some-elisp-file.el")

then command becomes

(let* (...
       (command `(,emacs "--batch"
                         "-l" "/path/to/some-elisp-file.el"
                         "--eval" ,sexp))
       ...)
  ...)

Extend one-ox org backend

When we use the default render functions, the org content of the webpages is exported using one-ox org backend like this

(org-export-data-with-backend
 (org-element-contents page-tree)
 'one-ox nil)

where page-tree is the parsed tree of the headline containing the page being rendered (see one-default render function).

While one-ox exports enough org elements for my use cases (see Why one.el?) this might not be the case for you.

I think this is not a big problem because we can extend one-ox (precisely we can derive a new org backend from one-ox org backend) with other transcoder functions for the org elements that miss transcoder functions.

Let's see how we can do that with an example.

Extend one-ox with horizontal-rule org elements

Lines consisting of only dashes (at least 5) are parsed by the org parser as horizontal-rule org elements. one-ox doesn't provide a transcoder function for horizontal-rule so we can't use it directly if we want to have them exported as <hr> tags in our website.

In that section we see how to derived an org backend one-ox-with-hr from one-ox org backend that exports horizontal-rule org elements with <hr> tags.

To do that we define a transcoder function my-horizontal-rule which takes 3 arguments (not used) and return the string "<hr>":

(defun my-horizontal-rule (_ _ _) "<hr>")

Then we use that function in the :translate-alist alist in the body of the function org-export-define-derived-backend to define one-ox-with-hr org backend:

(org-export-define-derived-backend 'one-ox-with-hr 'one-ox
  :translate-alist
  '((horizontal-rule . my-horizontal-rule)))

Then we can export the org content of the webpages (including the horizontal-rule) using one-ox-with-hr org backend like this

(org-export-data-with-backend
 (org-element-contents page-tree)
 'one-ox-with-hr nil)

where page-tree is the parsed tree of the headline containing the page being rendered.

Now that we saw how to derive one-ox-with-hr org backend and use it, let's build a website with only a home page with two horizontal-rule.

In an empty directory let's add the following files:

  • one.org:

    * Home page
    :PROPERTIES:
    :ONE: my-render-function
    :CUSTOM_ID: /
    :END:
    
    foo
    
    -----
    
    bar
    
    -----
    
    baz
  • onerc.el:

    (defun my-horizontal-rule (_ _ _) "<hr>")
    
    (org-export-define-derived-backend 'one-ox-with-hr 'one
      :translate-alist
      '((horizontal-rule . my-horizontal-rule)))
    
    (defun my-render-function (page-tree pages _global)
      ""
      (let* ((title (org-element-property :raw-value page-tree))
             (content (org-export-data-with-backend
                       (org-element-contents page-tree)
                       'one-ox-with-hr
                       nil)))
        (jack-html
         "<!DOCTYPE html>"
         `(:html
           (:head (:title ,title))
           (:body
            (:h1 ,title)
            ,content)))))

Now while visiting one.org file we call one-build to build our website with <hr> tags.

PREVRANDOMNEXT