From be0d907de78c4689708573c03105059e04d2419f Mon Sep 17 00:00:00 2001 From: Kévin Le Gouguec Date: Mon, 28 Sep 2020 22:10:56 +0200 Subject: Factor some code out To make it easier to add a pre-processing step for Org files. --- repo/www/helpers.py | 44 +++++++++++++++++++++++++++----------------- 1 file changed, 27 insertions(+), 17 deletions(-) (limited to 'repo/www/helpers.py') diff --git a/repo/www/helpers.py b/repo/www/helpers.py index 48ebccf..dbab622 100644 --- a/repo/www/helpers.py +++ b/repo/www/helpers.py @@ -2,8 +2,9 @@ from collections import defaultdict from dataclasses import dataclass, field from itertools import chain from os import environ, path +from pathlib import Path from subprocess import run -from typing import Iterator +from typing import Dict, Iterator, Union @dataclass @@ -56,26 +57,35 @@ def deserialize_directories(directories): } -def pandoc(page, output, template, filters, stylesheets, include_after=(), - variables=None, metadata=None): - cmd = ( - 'pandoc', '-s', page, '-o', output, '--template', template, - *chain(*(('--lua-filter', f) for f in filters)), - *chain(*(('--css', s) for s in stylesheets)), - *chain(*(('--include-after-body', f) for f in include_after)) - ) +_PathArg = Union[Path, str, bytes] + +@dataclass +class PandocRunner: + output: _PathArg + template: _PathArg + filters: Iterator[_PathArg] + stylesheets: Iterator[_PathArg] + variables: Dict[str, str] = field(default_factory=dict) + + def run(self, page, include_after=(), metadata=None): + cmd = ( + 'pandoc', '-s', page, '-o', self.output, + '--template', self.template, + *chain(*(('--lua-filter', f) for f in self.filters)), + *chain(*(('--css', s) for s in self.stylesheets)), + *chain(*(('--include-after-body', f) for f in include_after)) + ) - if variables is not None: - cmd += tuple(chain( - *(('-V', f'{k}={v}') for k, v in variables.items()) - )) - if metadata is not None: cmd += tuple(chain( - *(('-M', f'{k}={v}') for k, v in metadata.items()) + *(('-V', f'{k}={v}') for k, v in self.variables.items()) )) + if metadata is not None: + cmd += tuple(chain( + *(('-M', f'{k}={v}') for k, v in metadata.items()) + )) - environ['LUA_PATH'] = '.cache/?.lua;;' - run(cmd, check=True) + environ['LUA_PATH'] = '.cache/?.lua;;' + run(cmd, check=True) def generate_crumbs(target): -- cgit v1.2.3 From 3e230d40ab1255aec292df17d7b127b681a55710 Mon Sep 17 00:00:00 2001 From: Kévin Le Gouguec Date: Thu, 1 Oct 2020 22:40:43 +0200 Subject: DAMMIT ox-md does not syntax-highlight source blocks, and trips over definition lists. --- repo/www/helpers.py | 50 ++++++++++++++++++++++++++++++++++++++++++---- repo/www/preprocess-org.el | 20 +++++++++++++++++++ 2 files changed, 66 insertions(+), 4 deletions(-) create mode 100644 repo/www/preprocess-org.el (limited to 'repo/www/helpers.py') diff --git a/repo/www/helpers.py b/repo/www/helpers.py index dbab622..34f274f 100644 --- a/repo/www/helpers.py +++ b/repo/www/helpers.py @@ -3,7 +3,8 @@ from dataclasses import dataclass, field from itertools import chain from os import environ, path from pathlib import Path -from subprocess import run +from subprocess import CalledProcessError, run +from tempfile import NamedTemporaryFile from typing import Dict, Iterator, Union @@ -57,6 +58,42 @@ def deserialize_directories(directories): } +class _NullPreprocessor: + def __init__(self, source_path): + self._source_path = source_path + + def __enter__(self): + self.output = self._source_path + return self + + def __exit__(self, *args): + pass + +class _OrgPreprocessor: + def __init__(self, source_path): + self._source_path = source_path + + def __enter__(self): + self._output = NamedTemporaryFile(mode='w+', suffix='.md') + try: + run(( + 'emacs', '-Q', '--batch', '--load', 'preprocess-org.el', + '--eval', f'(preprocess-org "{self._source_path}")' + ), check=True, stdout=self._output) + except CalledProcessError: + self._output.close() + raise + + self.output = self._output.name + return self + + def __exit__(self, *args): + self._output.close() + +_PREPROCESSORS = defaultdict(lambda: _NullPreprocessor, + (('org', _OrgPreprocessor),)) + + _PathArg = Union[Path, str, bytes] @dataclass @@ -69,8 +106,7 @@ class PandocRunner: def run(self, page, include_after=(), metadata=None): cmd = ( - 'pandoc', '-s', page, '-o', self.output, - '--template', self.template, + 'pandoc', '-s', '-o', self.output, '--template', self.template, *chain(*(('--lua-filter', f) for f in self.filters)), *chain(*(('--css', s) for s in self.stylesheets)), *chain(*(('--include-after-body', f) for f in include_after)) @@ -85,7 +121,13 @@ class PandocRunner: )) environ['LUA_PATH'] = '.cache/?.lua;;' - run(cmd, check=True) + + _, ext = path.splitext(page) + preprocessor = _PREPROCESSORS[ext[1:]] + + with preprocessor(page) as preproc: + cmd = cmd + (preproc.output,) + run(cmd, check=True) def generate_crumbs(target): diff --git a/repo/www/preprocess-org.el b/repo/www/preprocess-org.el new file mode 100644 index 0000000..f7be936 --- /dev/null +++ b/repo/www/preprocess-org.el @@ -0,0 +1,20 @@ +(defun preprocess-org (input) + (with-temp-buffer + (insert-file-contents input) + (org-mode) + (while (re-search-forward org-heading-regexp nil t) + (save-excursion + (save-match-data + (when-let ((tags (org-get-tags (point)))) + (insert "\n#+begin_tags\n") + (dolist (tag tags) + (insert "- " tag "\n")) + (insert "#+end_tags\n"))))) + (let ((org-export-with-properties t) + (org-export-with-section-numbers nil) + (org-export-with-sub-superscripts '{}) + (org-export-with-tags nil) + (org-export-with-title nil) + (org-export-with-toc nil)) + (org-md-export-as-markdown)) + (princ (buffer-string)))) -- cgit v1.2.3 From 348ac65f367ec3b0ce4a517a281810e5c82bd135 Mon Sep 17 00:00:00 2001 From: Kévin Le Gouguec Date: Tue, 6 Oct 2020 10:30:42 +0200 Subject: Bang on Org export some more --- repo/www/helpers.py | 2 +- repo/www/preprocess-org.el | 48 ++++++++++++++++++++++++++++++++++++++-------- 2 files changed, 41 insertions(+), 9 deletions(-) (limited to 'repo/www/helpers.py') diff --git a/repo/www/helpers.py b/repo/www/helpers.py index 34f274f..12d9a41 100644 --- a/repo/www/helpers.py +++ b/repo/www/helpers.py @@ -74,7 +74,7 @@ class _OrgPreprocessor: self._source_path = source_path def __enter__(self): - self._output = NamedTemporaryFile(mode='w+', suffix='.md') + self._output = NamedTemporaryFile(mode='w+', suffix='.org') try: run(( 'emacs', '-Q', '--batch', '--load', 'preprocess-org.el', diff --git a/repo/www/preprocess-org.el b/repo/www/preprocess-org.el index f7be936..bad9f90 100644 --- a/repo/www/preprocess-org.el +++ b/repo/www/preprocess-org.el @@ -1,5 +1,41 @@ +;; How I Convert Org Files To HTML. +;; ================================ +;; +;; Or: Why We Can't Have Nice Things: Exhibit #42. +;; ------------------------------------------- +;; +;; Or: I Got Way Too Much Time On My Hands, Apparently. +;; ------------------------------------------------ +;; +;; I see two straightforward ways to export Org files to HTML: +;; +;; 1. ox-html.el, Org's HTML backend: even with all the settings and +;; filters available, there are still a few things that annoy me: +;; lots of extra
s, unstable section IDs… +;; +;; Also, I want to squeeze pandoc somewhere in the pipeline, to run +;; my Lua filters. +;; +;; 2. pandoc: does not cover all of Org's features. Org is so crammed +;; with constructs that don't exist in other markup formats +;; (agendas, logbooks, spreadsheets, properties…) and so many knobs +;; can be tweaked on a per-file basis (link abbreviations, tags, +;; TODO cycles) that Elisp remains the least painful way to process +;; these files, IMO. +;; +;; A less-straightforward, but still reasonably simple way to go would +;; be to use Org's markdown backend, then run pandoc on the result. +;; Unfortunately, AFAICT ox-md.el does not implement definition lists, +;; nor syntax-highlighting in fenced code blocks. +;; +;; So here's where I'm at: using Elisp, I'll preprocess Org files to +;; add a bunch of #+OPTIONS pandoc recognizes, "dumb down" the stuff +;; pandoc does not recognize, format some other stuff arbitrarily, +;; *then* I'll run pandoc on the result. + (defun preprocess-org (input) (with-temp-buffer + (insert "#+OPTIONS: ^:{} tags:nil\n") (insert-file-contents input) (org-mode) (while (re-search-forward org-heading-regexp nil t) @@ -10,11 +46,7 @@ (dolist (tag tags) (insert "- " tag "\n")) (insert "#+end_tags\n"))))) - (let ((org-export-with-properties t) - (org-export-with-section-numbers nil) - (org-export-with-sub-superscripts '{}) - (org-export-with-tags nil) - (org-export-with-title nil) - (org-export-with-toc nil)) - (org-md-export-as-markdown)) - (princ (buffer-string)))) + ;; TODO: dump properties + ;; TODO: fontify TODO keywords + ;; TODO: expand #+LINK abbreviations + (princ (buffer-string)))) -- cgit v1.2.3