commit e29814c366314c64c69caae631a2dc31965b5180 Author: Correl Roush Date: Fri Aug 31 11:59:56 2018 -0400 Initial commit diff --git a/README.org b/README.org new file mode 100644 index 0000000..dee1926 --- /dev/null +++ b/README.org @@ -0,0 +1,51 @@ +#+TITLE: ox-confluence-en +#+STARTUP: indent +#+TODO: NONE + +An enhanced Confluence wiki markup exporter for Org-mode. + +This exporter is based on (and therefore requires) =ox-confluence=, +which is included in org-contrib. It extends and improves upon it in +several ways: + +- The exported wiki syntax is cleaned up, resolving various rendering quirks. +- An entry is added to the exporter menu for ease of use. +- Status badge macros are used when exporting todo keywords. +- Support is added for exporting PlantUML graphs as a confluence macro. + +* Features +** TODO keywords exported as status badges + +If your document exports TODO keywords (=todo:t= in =#+OPTIONS=), they +will be rendered using Confluence's status badge macro. TODO keywords +will be colored red, and DONE keywords will be colored green. + +** PlantUML, Graphviz, and Ditaa graphs + +if =ox-confluence-en-use-plantuml-macro= is set to =t=, PlantUML, +Graphviz, and Ditaa source code blocks will be exported using the +Confluence PlantUML macro, allowing them to be included in exported +documents without having to upload the resulting images separately +(instead including the PlantUML source in the document, to be rendered +on the server). This requires the free [[https://marketplace.atlassian.com/plugins/de.griffel.confluence.plugins.plant-uml][Confluence PlantUML plugin]] to +be installed on the server. + +** Lists as tables + +Any list can be exported as a table, by setting =:as-table= to =t= +using =#+ATTR_CONFLUENCE=: + +#+BEGIN_SRC org + ,#+ATTR_CONFLUENCE: :as-table t + - Thing one + - Thing two +#+END_SRC + +This is even more useful when using a description list, as the first +column will be rendered as headings: + +#+BEGIN_SRC org + ,#+ATTR_CONFLUENCE: :as-table t + - Author :: John Doe + - Published :: 2018-08-09 +#+END_SRC diff --git a/ox-confluence-en.el b/ox-confluence-en.el new file mode 100644 index 0000000..30e4b38 --- /dev/null +++ b/ox-confluence-en.el @@ -0,0 +1,243 @@ +;;; ox-confluence-en.el --- Enhanced Confluence Wiki Back-End for Org Export -*- lexical-binding: t; -*- + +;; Copyright (C) 2015-2018, Correl Roush + +;; Author: Correl Roush +;; URL: https://github.com/correl/ox-confluence-en +;; Version: 1.0 +;; Keywords: outlines, confluence, wiki +;; Package-Requires: ((emacs "24") (org "8.2") (s "1")) + +;; This file is not part of GNU Emacs. + +;; This program is free software: you can redistribute it and/or modify +;; it under the terms of the GNU General Public License as published by +;; the Free Software Foundation, either version 3 of the License, or +;; (at your option) any later version. + +;; This program is distributed in the hope that it will be useful, +;; but WITHOUT ANY WARRANTY; without even the implied warranty of +;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +;; GNU General Public License for more details. + +;; You should have received a copy of the GNU General Public License +;; along with GNU Emacs. If not, see . + +;;; Commentary: +;; +;; ox-confluence.el lets you convert Org files to confluence wiki +;; markup using the ox.el export engine. +;; +;; Put this file into your load-path and the following into your ~/.emacs: +;; (require 'ox-confluence-en) +;; +;; Export Org files to confluence: +;; M-x ox-confluence-en-export-as-confluence +;; or use the org-export-dispatch UI. +;; +;;; Code: +(require 'ox) +(require 'ox-confluence) +(require 's) + +(defgroup ox-confluence-en nil + "Options for exporting to Confluence" + :tag "Org Confluence (Enhanced)" + :group 'org-export) + +(defcustom ox-confluence-en-use-plantuml-macro t + "Embed PlantUML graphs using the PlantUML macro. + +When exporting the results of a PlantUML, dot, or ditaa source +block, use the Confluence PlantUML macro to render the graph +rather than linking to the resulting image generated locally. + +Requires the free confluence PlantUML plugin to be installed: +https://marketplace.atlassian.com/plugins/de.griffel.confluence.plugins.plant-uml" + :group 'ox-confluence-en + :type 'boolean) + +(org-export-define-derived-backend 'confluence-en 'confluence + :translate-alist '((headline . ox-confluence-en-headline) + (paragraph . ox-confluence-en-paragraph) + (src-block . ox-confluence-en-src-block) + (quote-block . ox-confluence-en-quote-block) + (special-block . ox-confluence-en-special-block) + (verbatim . ox-confluence-en-verbatim) + (code . ox-confluence-en-verbatim) + (fixed-width . ox-confluence-en-verbatim) + (table-cell . ox-confluence-en-table-cell) + (item . ox-confluence-en-item) + (timestamp . ox-confluence-en-timestamp) + (property-drawer . ox-confluence-en-property-drawer)) + :menu-entry + '(?C "Export to Confluence" + ((?C "As Wiki buffer" + (lambda (a s v b) + (ox-confluence-en-export-as-confluence a s v b)))))) + +(defun ox-confluence-en-headline (headline contents info) + (let* ((low-level-rank (org-export-low-level-p headline info)) + (text (org-export-data (org-element-property :title headline) + info)) + (todo (org-export-data (org-element-property :todo-keyword headline) + info)) + (level (org-export-get-relative-level headline info)) + (todo-text (if (or (not (plist-get info :with-todo-keywords)) + (string= todo "")) + "" + (let* ((todo-type (org-element-property :todo-type headline)) + (status-color (cond + ((equal todo-type 'todo) "red") + (t "green")))) + (format "%s " (ox-confluence-en--macro "status" nil `((color . ,status-color) (title . ,todo)))))))) + ;; Else: Standard headline. + (format "h%s. %s%s\n%s" level todo-text text + (if (org-string-nw-p contents) contents "")))) + +(defun ox-confluence-en-paragraph (paragraph contents info) + "Strip newlines from paragraphs. + +Confluence will include any line breaks in the paragraph, rather +than treating it as reflowable whitespace." + (replace-regexp-in-string "\n" " " contents)) + +(defun ox-confluence-en-src-block (src-block contents info) + "Embed source block results using available macros. + +Currently, PlantUML, Graphviz, and Ditaa graphs will be embedded +using the macros provided by the PlantUML plugin, if it is +available." + (let ((lang (org-element-property :language src-block)) + (code (org-export-format-code-default src-block info)) + (caption (if (org-export-get-caption src-block) + (org-trim (org-export-data (org-export-get-caption src-block) info))))) + (if (and ox-confluence-en-use-plantuml-macro + (member lang '("plantuml" "dot" "ditaa"))) + (ox-confluence-en--macro "plantuml" code `((type . ,lang))) + (ox-confluence-en--block lang "Emacs" caption code)))) + +(defun ox-confluence-en--block (language theme caption contents) + (concat "\{code:theme=" theme + (when language (format "|language=%s" language)) + (when caption (format "|title=%s" caption)) + "}\n" + contents + "\{code\}\n")) + +(defun ox-confluence-en-quote-block (quote-block contents info) + (ox-confluence-en--macro "quote" contents)) + +(defun ox-confluence-en-special-block (special-block contents info) + (let ((block-type (downcase (org-element-property :type special-block)))) + (if (member block-type '("info" "note" "warning")) + (ox-confluence-en--macro block-type contents) + (org-ascii-special-block special-block contents info)))) + +(defun ox-confluence-en-verbatim (verbatim contents info) + (format "{{%s}}" + (org-trim (org-element-property :value verbatim)))) + +(defun ox-confluence-en--macro (name contents &optional arguments) + (let ((open-tag (concat "\{" name + (when arguments + (concat ":" + (mapconcat (lambda (pair) (format "%s=%s" + (car pair) + (cdr pair))) + arguments + "|"))) + "}")) + (close-tag (concat "{" name "}"))) + (if contents (concat open-tag "\n" contents "\n" close-tag) + open-tag))) + +;;;###autoload +(defun ox-confluence-en-export-as-confluence + (&optional async subtreep visible-only body-only ext-plist) + "Export the current org-mode buffer as Confluence wiki markup. + +The markup is exported to a temporary buffer, which you can use +to copy the content to be pasted within Confluence." + (interactive) + (let ((org-babel-default-header-args:plantuml '((:exports . "code"))) + (org-babel-default-header-args:dot '((:exports . "code"))) + (org-babel-default-header-args:ditaa '((:exports . "code")))) + (org-export-to-buffer 'confluence-en "*org CONFLUENCE Export*" + async subtreep visible-only body-only ext-plist (lambda () (text-mode))))) + +(defun ox-confluence-en-table-cell (table-cell contents info) + "Wrap table cell contents in whitespace. + +Without the extra whitespace, cells will collapse together thanks +to confluence's table header syntax being multiple pipes." + (let ((table-row (org-export-get-parent table-cell))) + (concat + (when (org-export-table-row-starts-header-p table-row info) + "|") + " " contents " |"))) + +(defun ox-confluence-en--checkbox (item info) + "Return checkbox string for ITEM or nil. +INFO is a plist used as a communication channel." + (cl-case (org-element-property :checkbox item) + (on "☑ ") + (off "☐ ") + (trans "☒ "))) + +(defun ox-confluence-en-item (item contents info) + (let ((as-table (or (org-export-read-attribute :attr_confluence + (org-export-get-parent item) + :as-table)))) + (if as-table (ox-confluence-en--item-as-table item contents info) + (ox-confluence-en--item-as-list item contents info)))) + +(defun ox-confluence-en--item-as-list (item contents info) + (let ((list-type (org-element-property :type (org-export-get-parent item))) + (checkbox (ox-confluence-en--checkbox item info)) + (depth (1+ (ox-confluence-en--li-depth item info)))) + (cl-case list-type + (descriptive + (concat (make-string depth ?-) " " + (org-export-data (org-element-property :tag item) info) ": " + (org-trim contents))) + (ordered + (concat (make-string depth ?#) " " + (org-trim contents))) + (t + (concat (make-string depth ?-) + " " + (org-trim contents)))))) + +(defun ox-confluence-en--item-as-table (item contents info) + (let* ((list-type (org-element-property :type (org-export-get-parent item))) + (checkbox (ox-confluence-en--checkbox item info)) + (depth (ox-confluence-en--li-depth item info)) + (info (plist-put info :ox-confluence-en-nested (1+ depth)))) + (cl-case list-type + (descriptive + (concat (s-repeat depth "| | ") + "|| " (org-export-data (org-element-property :tag item) info) + " |" (org-export-data (org-trim contents) info))) + (t + (concat (s-repeat depth "| | ") + "|" (org-export-data (org-trim contents) info) " |"))))) + +(defun ox-confluence-en--li-depth (item info) + (let ((nested (plist-get info :ox-confluence-en-nested))) + (message "Nested: %s" nested) + (- (org-confluence--li-depth item) + (or nested 0)))) + +(defun ox-confluence-en-timestamp (timestamp contents info) + (s-replace-all + '(("[" . "") + ("]" . "")) + (org-ascii-timestamp timestamp contents info))) + +(defun ox-confluence-en-property-drawer (property-drawer contents info) + (and (org-string-nw-p contents) + (ox-confluence-en--macro "info" contents))) + +(provide 'ox-confluence-en) +;;; ox-confluence-en.el ends here