spacemacs/core/tools/export/_worker.el
2017-12-03 17:54:55 +02:00

1021 lines
37 KiB
EmacsLisp
Raw Blame History

This file contains invisible Unicode characters

This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

;;; _worker.el --- Spacemacs docs export worker -*- lexical-binding: t -*-
;;
;; Copyright (C) 2012-2017 Sylvain Benner & Contributors
;;
;; Author: Eugene "JAremko" Yaremenko <w3techplayground@gmail.com>
;; URL: https://github.com/syl20bnr/spacemacs
;; File structure was borrowed from ox-html.el by (Carsten Dominik
;; <carsten at orgmode dot org> and Jambunathan K
;; <kjambunathan at gmail dot com>).
;;
;; This file is not part of GNU Emacs.
;;
;;; License: GPLv3
(when (and load-file-name
noninteractive)
(setq gc-cons-threshold 10000000000))
(eval-when-compile
(require 'cl)
(require 'url-util)
(require 'subr-x))
(require 'ox)
(load-file
(concat
(file-name-directory
(or load-file-name
buffer-file-name))
"../lib/toc-org.elc"))
(defconst spacemacs--root-dir
(file-truename
(concat
(file-name-directory
(or load-file-name (buffer-file-name)))
"../../../"))
"Root directory of Spacemacs")
(declare-function toc-org-hrefify-gh "../lib/toc-org.el" (str &optional hash))
(defconst spacemacs-repository "spacemacs"
"Name of the Spacemacs remote repository.")
(defconst spacemacs-repository-owner "syl20bnr"
"Name of the Spacemacs remote repository owner.")
(defconst spacemacs-readme-template-url
(concat "https://github.com/syl20bnr/spacemacs/"
"blob/develop/core/templates/README.org.template")
"URL of README.org template")
(defvar spacemacs--org-export-define-backend-funcs-alist
'((bold . spacemacs//org-edn-bold)
(center-block . spacemacs//org-edn-center-block)
(clock . spacemacs//org-edn-clock)
(code . spacemacs//org-edn-code)
(drawer . spacemacs//org-edn-drawer)
(dynamic-block . spacemacs//org-edn-dynamic-block)
(entity . spacemacs//org-edn-entity)
(example-block . spacemacs//org-edn-example-block)
(export-block . spacemacs//org-edn-export-block)
(export-snippet . spacemacs//org-edn-export-snippet)
(fixed-width . spacemacs//org-edn-fixed-width)
(footnote-definition . spacemacs//org-edn-footnote-definition)
(footnote-reference . spacemacs//org-edn-footnote-reference)
(headline . spacemacs//org-edn-headline)
(horizontal-rule . spacemacs//org-edn-horizontal-rule)
(inline-src-block . spacemacs//org-edn-inline-src-block)
(inlinetask . spacemacs//org-edn-inlinetask)
(inner-template . spacemacs//org-edn-inner-template)
(italic . spacemacs//org-edn-italic)
(item . spacemacs//org-edn-item)
(keyword . spacemacs//org-edn-keyword)
(latex-environment . spacemacs//org-edn-latex-environment)
(latex-fragment . spacemacs//org-edn-latex-fragment)
(line-break . spacemacs//org-edn-line-break)
(link . spacemacs//org-edn-link)
(node-property . spacemacs//org-edn-node-property)
(paragraph . spacemacs//org-edn-paragraph)
(plain-list . spacemacs//org-edn-plain-list)
(plain-text . spacemacs//org-edn-plain-text)
(planning . spacemacs//org-edn-planning)
(property-drawer . spacemacs//org-edn-property-drawer)
(quote-block . spacemacs//org-edn-quote-block)
(radio-target . spacemacs//org-edn-radio-target)
(section . spacemacs//org-edn-section)
(special-block . spacemacs//org-edn-special-block)
(src-block . spacemacs//org-edn-src-block)
(statistics-cookie . spacemacs//org-edn-statistics-cookie)
(strike-through . spacemacs//org-edn-strike-through)
(subscript . spacemacs//org-edn-subscript)
(superscript . spacemacs//org-edn-superscript)
(table . spacemacs//org-edn-table)
(table-cell . spacemacs//org-edn-table-cell)
(table-row . spacemacs//org-edn-table-row)
(target . spacemacs//org-edn-target)
(template . spacemacs//org-edn-template)
(timestamp . spacemacs//org-edn-timestamp)
(underline . spacemacs//org-edn-underline)
(verbatim . spacemacs//org-edn-verbatim)
(verse-block . spacemacs//org-edn-verse-block))
"plist of transcode functions names for `spacemacs-edn' backend.")
(org-export-define-backend 'spacemacs-edn
spacemacs--org-export-define-backend-funcs-alist
:filters-alist
'((:filter-final-output . spacemacs//org-edn-final-function)))
;;; Helper Functions
(defsubst spacemacs//org-edn-format-payload (format-string args)
"Format payload for JSON."
(replace-regexp-in-string
"\n"
"\r"
(if args (apply 'format format-string args) format-string)))
(defsubst spacemacs/org-edn-export-file (src-file file-path)
"Emit request for copying file at FILE-PATH. SRC-FILE will
be sent as the source of request (useful for debugging)"
(message "{\"type\":\"export\",\"text\":%S,\"source\":%S}"
(spacemacs//org-edn-format-payload
file-path)
(spacemacs//org-edn-format-payload
src-file)))
(defsubst spacemacs/org-edn-message (format-string &rest args)
"Emit specified message."
(message "{\"type\":\"message\",\"text\":%S}"
(spacemacs//org-edn-format-payload
format-string
args)))
(defsubst spacemacs/org-edn-warn (format-string &rest args)
"Emit specified warning."
(message "{\"type\":\"warning\",\"text\":%S}"
(spacemacs//org-edn-format-payload
format-string
args)))
(defsubst spacemacs/org-edn-error (format-string &rest args)
"Emit specified error and exit with code 1."
(message "{\"type\":\"error\",\"text\":%S}"
(spacemacs//org-edn-format-payload
(concat (format "current-buffer: %s\n"
(buffer-name))
(format "current-file: %s\n"
(buffer-file-name))
"error: "
format-string)
args))
(kill-emacs 1))
(defconst spacemacs-org-edn-special-chars '(("\\" . "\\\\")
("\t" . "\\t")
("\r" . "\\r")
("\"" . "\\\"")
("\n" . "\\n")))
(defsubst spacemacs/org-edn-escape-string (str)
"Escape special characters in STR."
(if str
(with-temp-buffer
(insert str)
(format-replace-strings spacemacs-org-edn-special-chars)
(buffer-string))
""))
(defsubst spacemacs/org-edn-headline-make-path-id (headline)
"Make id for org HEADLINE by chaining headlines from parent to)
child headline.
NOTE: Each headline is converted with `toc-org-hrefify-gh' but
without unification and \"#\" prefix."
(let* ((res nil)
(cur-node headline)
(parent-node (org-export-get-parent cur-node)))
(loop
t
(when (eq 'headline (car-safe cur-node))
(push (string-remove-prefix
"#"
(toc-org-hrefify-gh
(org-element-property
:raw-value
cur-node)))
res))
(if (not parent-node)
(return res)
(setq cur-node parent-node
parent-node (org-export-get-parent cur-node))))
(mapconcat 'identity res "/")))
(defun ask-user-about-lock (_ __)
"Ignore locks on files"
t)
;;; Transcode Functions
;;;; Bold
(defun spacemacs//org-edn-bold (_bold contents _info)
"Transcode BOLD From Org to Spacemacs EDN.
CONTENTS is the text with bold markup. INFO is a plist holding
contextual information."
(format "{:tag :bold :children [%s]}" contents))
;;;; Center Block
(defun spacemacs//org-edn-center-block (_center-block contents _info)
"Transcode a CENTER-BLOCK element From Org to Spacemacs EDN.))
CONTENTS holds the contents of the block. INFO is a plist
holding contextual information."
(format "{:tag :center-block :children [%s]}" contents))
;;;; Clock
(defun spacemacs//org-edn-clock (_clock _contents _info)
"Transcode a CLOCK element From Org to Spacemacs EDN.
CONTENTS is nil. INFO is a plist used as a communication
channel."
(spacemacs/org-edn-error "\"%s\" not implemented"
"spacemacs//org-edn-clock")
"")
;;;; Code
(defun spacemacs//org-edn-code (code _contents _info)
"Transcode CODE From Org to Spacemacs EDN.
CONTENTS is nil. INFO is a plist holding contextual
information.
NOTE: In Spacemacs ~code blocks~ are key sequences."
(format "{:tag :kbd :value %s}"
(format "%S"
(vconcat
(mapcar
'spacemacs/org-edn-escape-string
(split-string
(org-element-property :value code)
" "
"\\s*"))))))
;;;; Drawer
(defun spacemacs//org-edn-drawer (_drawer _contents _info)
"Transcode a DRAWER element From Org to Spacemacs EDN.
CONTENTS holds the contents of the block. INFO is a plist
holding contextual information."
(spacemacs/org-edn-error "\"%s\" not implemented"
"spacemacs//org-edn-drawer")
"")
;;;; Dynamic Block
(defun spacemacs//org-edn-dynamic-block (_dynamic-block _contents _info)
"Transcode a DYNAMIC-BLOCK element From Org to Spacemacs EDN.
CONTENTS holds the contents of the block. INFO is a plist
holding contextual information. See `org-export-data'."
(spacemacs/org-edn-error "\"%s\" not implemented"
"spacemacs//org-edn-dynamic-block")
"")
;;;; Entity
(defun spacemacs//org-edn-entity (_entity _contents _info)
"Transcode an ENTITY object From Org to Spacemacs EDN.
CONTENTS are the definition itself. INFO is a plist holding
contextual information."
(spacemacs/org-edn-error "\"%s\" not implemented"
"spacemacs//org-edn-entity")
"")
;;;; Example Block
(defun spacemacs//org-edn-example-block (example-block _contents _info)
"Transcode a EXAMPLE-BLOCK element From Org to Spacemacs EDN.
CONTENTS is nil. INFO is a plist holding contextual
information."
(format "{:tag :example-block :value \"%s\"}"
(spacemacs/org-edn-escape-string
(org-element-property :value example-block))))
;;;; Export Block
(defun spacemacs//org-edn-export-block (_export-block _contents _info)
"Transcode a EXPORT-BLOCK element From Org to Spacemacs EDN.
CONTENTS is nil. INFO is a plist holding contextual information."
(spacemacs/org-edn-error "\"%s\" not implemented"
"spacemacs//org-edn-export-block")
"")
;;;; Export Snippet
(defun spacemacs//org-edn-export-snippet (_export-snippet _contents _info)
"Transcode a EXPORT-SNIPPET object From Org to Spacemacs EDN.
CONTENTS is nil. INFO is a plist holding contextual
information."
(spacemacs/org-edn-error "\"%s\" not implemented"
"spacemacs//org-edn-export-snippet")
"")
;;;; Fixed Width
(defun spacemacs//org-edn-fixed-width (fixed-width _contents _info)
"Transcode a FIXED-WIDTH element From Org to Spacemacs EDN.
CONTENTS is nil. INFO is a plist holding contextual information."
(format "{:tag :fixed-width :value \"%s\"}"
(spacemacs/org-edn-escape-string
(org-element-property :value fixed-width))))
;;;; Footnote Reference
(defun spacemacs//org-edn-footnote-reference
(_footnote-reference _contents _info)
"Transcode a FOOTNOTE-REFERENCE element From Org to Spacemacs EDN.
CONTENTS is nil. INFO is a plist holding contextual information."
(spacemacs/org-edn-error "\"%s\" not implemented"
"spacemacs//org-edn-footnote-reference")
"")
;;;; Headline
(defun spacemacs//org-edn-headline (headline contents info)
"Transcode a HEADLINE element From Org to Spacemacs EDN.
CONTENTS holds the contents of the headline. INFO is a plist
holding contextual information."
(let* ((raw-value (org-element-property :raw-value headline))
(headline-ht (if (plist-member info :headline-hash)
(plist-get info :headline-hash)
(let ((hh (make-hash-table :test 'equal)))
(plist-put info :headline-hash hh)
hh)))
(gh-id (toc-org-hrefify-gh raw-value headline-ht))
(level (org-element-property :level headline))
(path-ids (plist-get info :path-ids))
(path-id
(spacemacs/org-edn-headline-make-path-id headline))
(file (plist-get info :input-file))
(todo? (org-element-property :todo-keyword headline))
(description? (and (= level 1)
(string= raw-value "Description"))))
(unless (or todo? contents)
(spacemacs/org-edn-error
"File %S has headline %S without children or TODO marker"
file
raw-value))
(when description?
(if (plist-member info :file-has-description?)
(spacemacs/org-edn-error
(concat "File \"%s\" has multiply top level "
"\"Description\" headlines")
file)
(plist-put info :file-has-description? 'true)))
(if (member path-id path-ids)
(spacemacs/org-edn-error
(concat "Multiply identical path IDs \"%s\" in %S file. "
"Usually it happens when headlines have child headlines "
"with similar names")
path-id
file)
(plist-put info :path-ids (push path-id path-ids)))
(puthash gh-id raw-value headline-ht)
(format
(concat "{:tag %s "
":value \"%s\" "
":gh-id \"%s\" "
":path-id \"%s\" "
":level %s "
":children [%s]}")
(cond
(todo? :todo)
(description? :description)
(t :headline))
(spacemacs/org-edn-escape-string raw-value)
(spacemacs/org-edn-escape-string (string-remove-prefix "#" gh-id))
(spacemacs/org-edn-escape-string path-id)
level
contents)))
;;;; Horizontal Rule
(defun spacemacs//org-edn-horizontal-rule (_horizontal-rule _contents _info)
"Transcode an HORIZONTAL-RULE object From Org to Spacemacs EDN.)))))
CONTENTS is nil. INFO is a plist holding contextual information."
(spacemacs/org-edn-error "\"%s\" not implemented"
"spacemacs//org-edn-horizontal-rule")
"")
;;;; Inline Src Block
(defun spacemacs//org-edn-inline-src-block (_inline-src-block _contents _info)
"Transcode an INLINE-SRC-BLOCK element From Org to Spacemacs EDN.
CONTENTS holds the contents of the item. INFO is a plist holding
contextual information."
(spacemacs/org-edn-error "\"%s\" not implemented"
"spacemacs//org-edn-inline-src-block")
"")
;;;; Inlinetask
(defun spacemacs//org-edn-inlinetask (_inlinetask _contents _info)
"Transcode an INLINETASK element From Org to Spacemacs EDN.
CONTENTS holds the contents of the block. INFO is a plist
holding contextual information."
(spacemacs/org-edn-error "\"%s\" not implemented"
"spacemacs//org-edn-inlinetask")
"")
;;;; Inner Template
(defun spacemacs//org-edn-inner-template (contents _info)
"Return body of document string after HTML conversion.
CONTENTS is the transcoded contents string. INFO is a plist
holding export options."
(format "{:tag :body :children [%s]}" contents))
;;;; Italic
(defun spacemacs//org-edn-italic (_italic contents _info)
"Transcode ITALIC From Org to Spacemacs EDN.
CONTENTS is the text with italic markup. INFO is a plist holding
contextual information."
(format "{:tag :italic :children [%s]}" contents))
;;;; Item
(defun spacemacs//org-edn-item (item contents info)
"Transcode an ITEM element From Org to Spacemacs EDN.
CONTENTS holds the contents of the item. INFO is a plist holding
contextual information."
(let ((type (org-element-property
:type
(org-export-get-parent item))))
(unless (or (eq 'ordered type)
(eq 'unordered type)
(eq 'descriptive type))
(spacemacs/org-edn-error
(concat "File \"%s\" contains plain list item of type \"%s\" but "
"it isn't implemented in spacemacs//org-edn-item")
(plist-get info :input-file)
type))
(format (concat "{:tag :list-item "
":type :%s "
":bullet %s "
":counter %s "
":checkbox %s "
":item-tag \"%s\" "
":children [%s]}")
type
(format
"\"%s\""
(spacemacs/org-edn-escape-string
(org-element-property :bullet item)))
(org-element-property :counter item)
(org-element-property :checkbox item)
(spacemacs/org-edn-escape-string
(format "%s" (org-element-property :tag item)))
contents)))
;;;; Keyword
(defun spacemacs//org-edn-keyword (keyword _contents _info)
"Transcode a KEYWORD element From Org to Spacemacs EDN.
CONTENTS is nil. INFO is a plist holding contextual information."
(format "{:tag :keyword :key \"%s\" :value \"%s\"}"
(spacemacs/org-edn-escape-string
(org-element-property :key keyword))
(spacemacs/org-edn-escape-string
(org-element-property :value keyword))))
;;;; Latex Environment
(defun spacemacs//org-edn-latex-environment (_latex-environment _contents _info)
"Transcode a LATEX-ENVIRONMENT element From Org to Spacemacs EDN.
CONTENTS is nil. INFO is a plist holding contextual information."
(spacemacs/org-edn-error "\"%s\" not implemented"
"spacemacs//org-edn-latex-environment")
"")
;;;; Latex Fragment
(defun spacemacs//org-edn-latex-fragment (_latex-fragment _contents _info)
"Transcode a LATEX-FRAGMENT object From Org to Spacemacs EDN.
CONTENTS is nil. INFO is a plist holding contextual information."
(spacemacs/org-edn-error "\"%s\" not implemented"
"spacemacs//org-edn-latex-fragment")
"")
;;;; Line Break
(defun spacemacs//org-edn-line-break (_line-break _contents _info)
"Transcode a LINE-BREAK object From Org to Spacemacs EDN.
CONTENTS is nil. INFO is a plist holding contextual information."
"{:tag :line-break}")
;;;; Link
(defconst spacemacs--org-edn-git-url-root-regexp
(format (concat "\\/\\/github\\.com\\/%s\\/%s\\/blob"
"\\/[^/]+\\/\\(.*\\.org\\)\\(\\#.*\\)?")
spacemacs-repository-owner
spacemacs-repository))
(defconst spacemacs--org-edn-embeddable-file-path-regexp
(format
"^.*\\.%s$"
(regexp-opt
'("gif" "gifv" "png" "jpg" "jpeg" "webp" "pdf" "svg" "webm" "mp4")
t))
"Regexp that matches file paths of files that can be
embedded into a web page.")
(defun spacemacs//org-edn-link (link desc info)
"Transcode a LINK object From Org to Spacemacs EDN.))
DESC is the description part of the link, or the empty string.
INFO is a plist holding contextual information. See
`org-export-data'."
(let* ((type (org-element-property :type link))
(path (org-element-property :path link))
(file (plist-get info :input-file))
(raw-link (org-element-property :raw-link link))
(local-link? (string= type "file"))
(local-org-link? (and local-link?
(string-match-p
".*\\.org\\(\\(::\\|#\\| \\).*\\)?$"
raw-link)))
(embeddable? (string-match-p
spacemacs--org-edn-embeddable-file-path-regexp
path)))
(when local-org-link?
(plist-put
info
:spacemacs-edn-warnings
(concat
(plist-get info :spacemacs-edn-warnings)
(format
(concat "Link \"%s\" "
"in \"%s\" "
"should target the org file at "
"GitHub "
"(GitHub style anchors are supported)\n"
"See footnote of %S\n")
raw-link
file
spacemacs-readme-template-url))))
(cond
((string-match spacemacs--org-edn-git-url-root-regexp
raw-link)
(let ((path (concat
spacemacs--root-dir
(url-unhex-string (match-string 1 raw-link))))
(target-id (string-remove-prefix
"#"
(match-string 2 raw-link))))
(unless (file-readable-p path)
(spacemacs/org-edn-error
(concat
"File %S has a GitHub link to the file %S but "
"it isn't readable locally.")
file
(file-truename path)))
(format (concat "{:tag :org-file-path "
":value \"%s\" "
":raw-link \"%s\" "
":target-headline-gh-id \"%s\" "
":children [%s]}")
(spacemacs/org-edn-escape-string path)
(spacemacs/org-edn-escape-string raw-link)
(spacemacs/org-edn-escape-string (url-unhex-string
target-id))
desc)))
(local-link?
(let ((path (url-unhex-string path)))
(cond
((not (file-readable-p path))
(spacemacs/org-edn-error
"File %S has a link to file %S but it isn't readable"
file
(file-truename path)))
((not (string-prefix-p spacemacs--root-dir
(file-truename path)))
(spacemacs/org-edn-error
"File %S has a link to file %S but it's outside repository"
file
(file-truename path))))
(when (not local-org-link?)
(spacemacs/org-edn-export-file file (file-truename path)))
(format "{:tag %s :value \"%s\" :children [%s]}"
(if embeddable? :embeddable-file-path :file-path)
(spacemacs/org-edn-escape-string path)
desc)))
((or (string= type "http")
(string= type "https")
(string= type "ftp"))
(format "{:tag %s :value \"%s\" :children [%s]}"
(if embeddable? :embeddable-web-link :web-link)
(spacemacs/org-edn-escape-string raw-link)
desc))
((string= type "custom-id")
(format (concat "{:tag :headline-link "
":target-headline-gh-id \"%s\" :children [%s]}")
(spacemacs/org-edn-escape-string raw-link)
desc))
(t (spacemacs/org-edn-error
(concat
"Link \"%s\" in file \"%s\" "
"has type \"%s\" "
"but the type isn't implemented in spacemacs//org-edn-link")
raw-link
file
type)))))
;;;; Node Property
(defun spacemacs//org-edn-node-property (_node-property _contents _info)
"Transcode a NODE-PROPERTY element From Org to Spacemacs EDN.
CONTENTS is nil. INFO is a plist holding contextual
information."
(spacemacs/org-edn-error "\"%s\" not implemented"
"spacemacs//org-edn-node-property")
"")
;;;; Paragraph
(defun spacemacs//org-edn-paragraph (_paragraph contents _info)
"Transcode a PARAGRAPH element From Org to Spacemacs EDN.
CONTENTS is the contents of the paragraph, as a string. INFO is
the plist used as a communication channel."
(format "{:tag :paragraph :children [%s]}" contents))
;;;; Plain List
(defun spacemacs//org-edn-plain-list (plain-list contents info)
"Transcode a PLAIN-LIST element From Org to Spacemacs EDN.
CONTENTS is the contents of the list. INFO is a plist holding
contextual information."
(let* ((type (org-element-property :type plain-list))
(parent-type
(symbol-name
(car
(org-export-get-parent
plain-list))))
(parent-hl
(org-export-get-parent-headline
plain-list))
(parent-hl-parent-hl
(org-export-get-parent-headline
parent-hl))
(file (plist-get info :input-file)))
(unless (or (eq 'ordered type)
(eq 'unordered type)
(eq 'descriptive type))
(spacemacs/org-edn-error
(concat "File \"%s\" contains plain list of type \"%s\" but "
"it isn't implemented in spacemacs//org-edn-node-property")
(plist-get info :input-file)
type))
(if (and (not
;; FIXME: We probably should use a better way to
;; tell apart nested features list and multiply
;; features list.
(string= parent-type
"item"))
(= (or (org-element-property
:level
parent-hl)
-1)
2)
(string= (org-element-property
:raw-value
parent-hl)
"Features:")
(= (or (org-element-property
:level
parent-hl-parent-hl)
-1)
1)
(string= (org-element-property
:raw-value
parent-hl-parent-hl)
"Description"))
(if (plist-member info :file-has-feature-list?)
(spacemacs/org-edn-error
(concat "File \"%s\" has multiply "
"\"Features:\" lists in the top "
"level \"Description\" headline")
file)
(plist-put info :file-has-feature-list? 'true)
(format "{:tag :feature-list :type :%s :children [%s]}"
type
contents))
(format "{:tag :plain-list :type :%s :children [%s]}"
type
contents))))
;;;; Plain Text
(defun spacemacs//org-edn-plain-text (text _info)
"Transcode a TEXT string From Org to Spacemacs EDN.
TEXT is the string to transcode. INFO is a plist holding
contextual information."
(format "{:tag :plain-text :value \"%s\"}"
(spacemacs/org-edn-escape-string text)))
;;;; Planning
(defun spacemacs//org-edn-planning (_planning _contents _info)
"Transcode a PLANNING element From Org to Spacemacs EDN.
CONTENTS is nil. INFO is a plist used as a communication
channel."
(spacemacs/org-edn-error "\"%s\" not implemented"
"spacemacs//org-edn-planning")
"")
;;;; Property Drawer
(defun spacemacs//org-edn-property-drawer (_property-drawer _contents _info)
"Transcode a PROPERTY-DRAWER element From Org to Spacemacs EDN.
CONTENTS holds the contents of the drawer. INFO is a plist
holding contextual information."
(spacemacs/org-edn-error "\"%s\" not implemented"
"spacemacs//org-edn-property-drawer")
"")
;;;; Quote Block
(defun spacemacs//org-edn-quote-block (_quote-block contents _info)
"Transcode a QUOTE-BLOCK element From Org to Spacemacs EDN.
CONTENTS holds the contents of the block. INFO is a plist
holding contextual information."
(format "{:tag :quote-block :children [%s]}" contents))
;;;; Radio Target
(defun spacemacs//org-edn-radio-target (_radio-target _text _info)
"Transcode a RADIO-TARGET object From Org to Spacemacs EDN.
TEXT is the text of the target. INFO is a plist holding
contextual information."
(spacemacs/org-edn-error "\"%s\" not implemented"
"spacemacs//org-edn-radio-target")
"")
;;;; Section
(defun spacemacs//org-edn-section (_section contents _info)
"Transcode a SECTION element From Org to Spacemacs EDN.
CONTENTS holds the contents of the section. INFO is a plist
holding contextual information."
(format "{:tag :section :children [%s]}" contents))
;;;; Special Block
(defun spacemacs//org-edn-special-block (_special-block _contents _info)
"Transcode a SPECIAL-BLOCK element From Org to Spacemacs EDN.
CONTENTS holds the contents of the block. INFO is a plist
holding contextual information."
(spacemacs/org-edn-error "\"%s\" not implemented"
"spacemacs//org-edn-special-block")
"")
;;;; Src Block
(defun spacemacs//org-edn-src-block (src-block _contents _info)
"Transcode a SRC-BLOCK element From Org to Spacemacs EDN.
CONTENTS is nil. INFO is a plist holding contextual information."
(format "{:tag :src-block :language \"%s\" :value \"%s\"}"
(spacemacs/org-edn-escape-string
(org-element-property :language src-block))
(spacemacs/org-edn-escape-string
(org-element-property :value src-block))))
;;;; Statistics Cookie
(defun spacemacs//org-edn-statistics-cookie (_statistics-cookie _contents _info)
"Transcode a STATISTICS-COOKIE object From Org to Spacemacs EDN.
CONTENTS is nil. INFO is a plist holding contextual information."
(spacemacs/org-edn-error "\"%s\" not implemented"
"spacemacs//org-edn-statistics-cookie")
"")
;;;; Strike-Through
(defun spacemacs//org-edn-strike-through (_strike-through contents _info)
"Transcode STRIKE-THROUGH From Org to Spacemacs EDN.
CONTENTS is the text with strike-through markup. INFO is a plist
holding contextual information."
(format "{:tag :strike-through :children [%s]}" contents))
;;;; Subscript
(defun spacemacs//org-edn-subscript (_subscript contents _info)
"Transcode a SUBSCRIPT object From Org to Spacemacs EDN.
CONTENTS is the contents of the object. INFO is a plist holding
contextual information."
(format "{:tag :subscript :children [%s]}" contents))
;;;; Superscript
(defun spacemacs//org-edn-superscript (_superscript contents _info)
"Transcode a SUPERSCRIPT object From Org to Spacemacs EDN.
CONTENTS is the contents of the object. INFO is a plist holding
contextual information."
(format "{:tag :superscript :children [%s]}" contents))
;;;; Table
(defun spacemacs//org-edn-table (table contents _info)
"Transcode a TABLE element From Org to Spacemacs EDN.
CONTENTS is the contents of the table. INFO is a plist holding
contextual information."
(let ((type (org-element-property :type table)))
(unless (eq type 'org)
(spacemacs/org-edn-error
"Table type \"%s\" isn't implemented in spacemacs//org-edn-table"
type))
(format "{:tag :table :type :%s :children [%s]}"
(org-element-property :type table)
contents)))
;;;; Table Cell
(defun spacemacs//org-edn-table-cell (_table-cell contents _info)
"Transcode a TABLE-CELL element From Org to Spacemacs EDN.
CONTENTS is nil. INFO is a plist used as a communication
channel."
(format "{:tag :table-cell :children [%s]}" contents))
;;;; Table Row
(defun spacemacs//org-edn-table-row (_table-row contents _info)
"Transcode a TABLE-ROW element From Org to Spacemacs EDN.
CONTENTS is the contents of the row. INFO is a plist used as a
communication channel."
(format "{:tag :table-row :children [%s]}" contents))
;;;; Target
(defun spacemacs//org-edn-target (_target _contents _info)
"Transcode a TARGET object From Org to Spacemacs EDN.
CONTENTS is nil. INFO is a plist holding contextual
information."
(spacemacs/org-edn-error "\"%s\" not implemented"
"spacemacs//org-edn-target")
"")
;;;; Template
(defun spacemacs//org-edn-template (contents info)
"Return complete document string after HTML conversion.
CONTENTS is the transcoded contents string. INFO is a plist
holding export options."
(let ((has-description?
(plist-member info :file-has-description?))
(has-feature-list?
(plist-member info :file-has-feature-list?)))
(when (plist-get info :input-file)
(let ((file (file-truename
(plist-get info :input-file))))
(when (and (string-prefix-p (file-truename
(concat
spacemacs--root-dir
"layers/"))
file)
(string-suffix-p "README.org"
file
t))
(unless has-description?
(plist-put
info
:spacemacs-edn-warnings
(concat
(plist-get info :spacemacs-edn-warnings)
(format
(concat
"File \"%s\" "
"doesn't have top level "
"\"Description\" headline\n"
"See %S\n")
file
spacemacs-readme-template-url))))
(unless has-feature-list?
(plist-put
info
:spacemacs-edn-warnings
(concat
(plist-get info :spacemacs-edn-warnings)
(format
(concat "File \"%s\" "
"doesn't have \"Features:\"(With a colon) list in the "
"top level \"Description\" headline\n"
"See %S\n")
file
spacemacs-readme-template-url)))))))
(format (concat "{:tag :root "
;; ":export-data #inst \"%s\" "
":file-has-description? %s "
":file-has-feature-list? %s "
":headline-path-ids %s "
":children [%s]}")
;; (format-time-string "%Y-%m-%dT%H:%M:%S.52Z" nil t)
(if (plist-member info :file-has-description?)
'true
'false)
(if (plist-member info :file-has-feature-list?)
'true
'false)
(map 'vector
(lambda (s)
(format "\"%s\"" (spacemacs/org-edn-escape-string s)))
(plist-get info :path-ids))
contents)))
;;;; Timestamp
(defun spacemacs//org-edn-timestamp (_timestamp _contents _info)
"Transcode a TIMESTAMP object From Org to Spacemacs EDN.)))))))))
CONTENTS is nil. INFO is a plist holding contextual
information."
(spacemacs/org-edn-error "\"%s\" not implemented"
"spacemacs//org-edn-timestamp")
"")
;;;; Underline
(defun spacemacs//org-edn-underline (_underline contents _info)
"Transcode UNDERLINE From Org to Spacemacs EDN.
CONTENTS is the text with underline markup. INFO is a plist
holding contextual information."
(format "{:tag :underline :children [%s]}" contents))
;;;; Verbatim
(defun spacemacs//org-edn-verbatim (verbatim _contents _info)
"Transcode VERBATIM From Org to Spacemacs EDN.
CONTENTS is nil. INFO is a plist holding contextual
information."
(format "{:tag :verbatim :value \"%s\"}"
(spacemacs/org-edn-escape-string
(org-element-property :value verbatim))))
;;;; Verse Block
(defun spacemacs//org-edn-verse-block (_verse-block contents _info)
"Transcode a VERSE-BLOCK element From Org to Spacemacs EDN.
CONTENTS is verse block contents. INFO is a plist holding
contextual information."
(format "{:tag :verse-block :children [%s]}" contents))
;;; Filter Functions
(defsubst spacemacs//org-edn-final-function-tidy (contents)
"Filter to compact output by removing newline symbols.
FIXME: Figure out where they come from :"
(replace-regexp-in-string "\n" "" contents))
(defsubst spacemacs//org-edn-final-function-fmt-vec-of-nil (str)
"Replace [nil] with []."
(replace-regexp-in-string "\\[nil\\]" "[]" str nil t))
(defsubst spacemacs//org-edn-final-function-lint (info)
"Warn about potential errors."
(let ((warnings (plist-get info :spacemacs-edn-warnings)))
(when (stringp warnings)
(spacemacs/org-edn-warn
"%s"
(string-remove-suffix "\n" warnings)))))
(defun spacemacs//org-edn-final-function (contents _backend info)
"Call final functions for `space-edn' backend"
(spacemacs//org-edn-final-function-lint info)
(spacemacs//org-edn-final-function-fmt-vec-of-nil
(spacemacs//org-edn-final-function-tidy contents)))
;;; End-user functions
(defun spacemacs/export-docs-to-edn (exp-dir file-list)
"Export org files in FILE-LIST into EXP-DIR."
(unwind-protect
(dolist (file file-list)
(let* ((target-file-name (concat
exp-dir
(string-remove-suffix
".org"
(string-remove-prefix
(file-truename
spacemacs--root-dir)
(file-truename file)))
".edn"))
(target-file-dir
(file-name-as-directory
(file-name-directory target-file-name))))
;; FIXME: Close enough. But it will be better if we
;; export stuff into separate folders and then merge.
(while (not (file-accessible-directory-p target-file-dir))
(condition-case err
(make-directory target-file-dir t)
(error (spacemacs/org-edn-warn
"make-directory \"%s\" failed with \"%s\". Retrying..."
target-file-dir
err))))
(spacemacs/org-edn-message
"Exporting \"%s\" into \"%s\""
file
target-file-name)
(with-temp-buffer
(find-file file)
(org-export-to-file
'spacemacs-edn
target-file-name))
(if (and (file-readable-p target-file-name)
(> (nth 7 (file-attributes target-file-name)) 0))
(spacemacs/org-edn-message
"Successfully exported \"%s\""
file)
(spacemacs/org-edn-error
"Export finished but \"%s\" doesn't exist or empty"
target-file-name))))))