Browse Source

org-odt.el: Add support for annotation blocks

* contrib/lisp/org-lparse.el (org-lparse-special-blocks): New
variable.  Add "annotation" blocks in addition to the already
existing "list-table" blocks.
(org-lparse-get-block-params): New helper routine to read
params passed to a special block.  Used in conjunction with
OpenDocument annotations and with parsing of "#+ATTR_ODT:..."
lines attached to images.
(org-lparse-par-open-stashed): New let-bound variable.
(org-do-lparse): Bind `org-lparse-par-open-stashed'.  Treat
all blocks listed in `org-lparse-special-blocks' as special
environments.  Honor options passed as part of
"#+begin_<block-name>[options]".
(org-lparse-preprocess-after-blockquote-hook): Handle all
blocks listed in `org-lparse-special-blocks' specially.
(org-lparse-strip-experimental-blocks-maybe-hook): New hook
that hooks up to `org-export-preprocess-hook'.  Removes blocks
listed under `org-lparse-special-blocks' while exporting to
formats other than "odt" or "xhtml".
(org-lparse-begin-environment, org-lparse-end-environment):
Modified signature to accomodate block params.
(org-lparse-stash-save-paragraph-state)
(org-lparse-stash-pop-paragraph-state): New helper routines
for use with emitting of OpenDocument annotations.
(org-lparse-list-table-enable): Removed.  "list tables" are
now always enabled.

* contrib/lisp/org-odt.el (org-odt-begin-annotation)
(org-odt-end-annotation): New routines.
(org-odt-begin-environment, org-odt-end-environment): Handle
block params.  Handle the new "annotation" block.
(org-odt-format-author, org-odt-iso-date-from-org-timestamp):
New helper routnes for emitting author and comment timestamps
with annotation blocks.
(org-odt-update-meta-file): Use above routines.
(org-export-odt-format-image): Use
`org-lparse-get-block-params' to parse inline image attributes.
(org-odt-format-date): Removed.  Superceded by
`org-odt-iso-date-from-org-timestamp'.

See http://lists.gnu.org/archive/html/emacs-orgmode/2011-10/msg01251.html
Jambunathan K 7 years ago
parent
commit
2e0e462d14
2 changed files with 108 additions and 64 deletions
  1. 65 29
      contrib/lisp/org-lparse.el
  2. 43 35
      contrib/lisp/org-odt.el

+ 65 - 29
contrib/lisp/org-lparse.el

@@ -305,6 +305,16 @@ OPT-PLIST is the export options list."
 	    start (+ start (length rpl))))
     line))
 
+(defvar org-lparse-par-open-stashed)	; bound during `org-do-lparse'
+(defun org-lparse-stash-save-paragraph-state ()
+  (assert (zerop org-lparse-par-open-stashed))
+  (setq org-lparse-par-open-stashed org-lparse-par-open)
+  (setq org-lparse-par-open nil))
+
+(defun org-lparse-stash-pop-paragraph-state ()
+  (setq org-lparse-par-open org-lparse-par-open-stashed)
+  (setq org-lparse-par-open-stashed 0))
+
 (defmacro with-org-lparse-preserve-paragraph-state (&rest body)
   `(let ((org-lparse-do-open-par org-lparse-par-open))
      (org-lparse-end-paragraph)
@@ -543,6 +553,15 @@ and then converted to \"doc\" then org-lparse-backend is set to
 (defvar org-lparse-to-buffer nil
   "Bind this to TO-BUFFER arg of `org-lparse'.")
 
+(defun org-lparse-get-block-params (params)
+  (save-match-data
+    (when params
+      (setq params (org-trim params))
+      (unless (string-match "\\`(.*)\\'" params)
+	(setq params (format "(%s)" params)))
+      (ignore-errors (read params)))))
+
+(defvar org-lparse-special-blocks '("list-table" "annotation"))
 (defun org-do-lparse (arg &optional hidden ext-plist
 			  to-buffer body-only pub-dir)
   "Export the outline to various formats.
@@ -572,6 +591,7 @@ version."
 					; collecting styles
 	 org-lparse-encode-pending
 	 org-lparse-par-open
+	 (org-lparse-par-open-stashed 0)
 
 	 ;; list related vars
 	 (org-lparse-list-level 0)	; list level starts at 1. A
@@ -902,13 +922,19 @@ version."
 	    (throw 'nextline nil))
 
 	  ;; Blockquotes, verse, and center
-	  (when (string-match  "^ORG-\\(.+\\)-\\(START\\|END\\)$" line)
+	  (when (string-match
+		 "^ORG-\\(.+\\)-\\(START\\|END\\)\\([ \t]+.*\\)?$" line)
 	    (let* ((style (intern (downcase (match-string 1 line))))
+		   (env-options-plist (org-lparse-get-block-params
+				       (match-string 3 line)))
 		   (f (cdr (assoc (match-string 2 line)
 				  '(("START" . org-lparse-begin-environment)
 				    ("END" . org-lparse-end-environment))))))
-	      (when (memq style '(blockquote verse center list-table))
-		(funcall f style)
+	      (when (memq style
+			  (append
+			   '(blockquote verse center)
+			   (mapcar 'intern org-lparse-special-blocks)))
+		(funcall f style env-options-plist)
 		(throw 'nextline nil))))
 
 	  (run-hooks 'org-export-html-after-blockquotes-hook)
@@ -1713,48 +1739,58 @@ information."
   (org-lparse-end-paragraph)
   (org-lparse-end-list-item (or type "u")))
 
-(defcustom org-lparse-list-table-enable nil
-  "Specify whether a list be exported as a table.
-When this option is enabled, lists that are enclosed in
-\"#+begin_list-table...#+end_list-table\" are exported as
-tables. Otherwise they are exported normally."
-  :type 'boolean
-  :group 'org-lparse)
-
 (defun org-lparse-preprocess-after-blockquote-hook ()
-  "Treat #+begin_list-table...#+end_list-table blocks specially.
-When `org-lparse-list-table-enable' is non-nil, enclose these
-blocks within ORG-LIST-TABLE-START...ORG-LIST-TABLE-END."
-  (when org-lparse-list-table-enable
-    (goto-char (point-min))
-    (while (re-search-forward "^[ \t]*#\\+\\(begin\\|end\\)_\\(.*\\)$" nil t)
-      (when (string= (downcase (match-string 2)) "list-table")
-	(replace-match (if (equal (downcase (match-string 1)) "begin")
-			   "ORG-LIST-TABLE-START"
-			 "ORG-LIST-TABLE-END") t t)))))
+  "Treat `org-lparse-special-blocks' specially."
+  (goto-char (point-min))
+  (while (re-search-forward
+	  "^[ \t]*#\\+\\(begin\\|end\\)_\\(\\S-+\\)[ \t]*\\(.*\\)$" nil t)
+    (when (member (downcase (match-string 2)) org-lparse-special-blocks)
+      (replace-match
+       (if (equal (downcase (match-string 1)) "begin")
+	   (format "ORG-%s-START %s" (upcase (match-string 2))
+		   (match-string 3))
+	 (format "ORG-%s-END %s" (upcase (match-string 2))
+		 (match-string 3))) t t))))
 
 (add-hook 'org-export-preprocess-after-blockquote-hook
 	  'org-lparse-preprocess-after-blockquote-hook)
 
+(defun org-lparse-strip-experimental-blocks-maybe-hook ()
+  "Strip \"list-table\" and \"annotation\" blocks.
+Stripping happens only when the exported backend is not one of
+\"odt\" or \"xhtml\"."
+  (when (not org-lparse-backend)
+    (message "Stripping following blocks - %S" org-lparse-special-blocks)
+    (goto-char (point-min))
+    (let ((case-fold-search t))
+      (while
+	  (re-search-forward
+	   "^[ \t]*#\\+begin_\\(\\S-+\\)\\([ \t]+.*\\)?\n\\([^\000]*?\\)\n[ \t]*#\\+end_\\1\\>.*"
+	   nil t)
+	(when (member (match-string 1) org-lparse-special-blocks)
+	  (replace-match "" t t))))))
+
+(add-hook 'org-export-preprocess-hook
+	  'org-lparse-strip-experimental-blocks-maybe-hook)
+
 (defvar org-lparse-list-table-p nil
-  "Non-nil if `org-do-lparse' is within a list-table.
-See `org-lparse-list-table-enable'.")
+  "Non-nil if `org-do-lparse' is within a list-table.")
 
 (defvar org-lparse-dyn-current-environment nil)
-(defun org-lparse-begin-environment (style)
+(defun org-lparse-begin-environment (style &optional env-options-plist)
   (case style
     (list-table
-     (setq org-lparse-list-table-p org-lparse-list-table-enable))
+     (setq org-lparse-list-table-p t))
     (t
      (setq org-lparse-dyn-current-environment style)
-     (org-lparse-begin 'ENVIRONMENT  style))))
+     (org-lparse-begin 'ENVIRONMENT  style env-options-plist))))
 
-(defun org-lparse-end-environment (style)
+(defun org-lparse-end-environment (style &optional env-options-plist)
   (case style
     (list-table
      (setq org-lparse-list-table-p nil))
     (t
-     (org-lparse-end 'ENVIRONMENT style)
+     (org-lparse-end 'ENVIRONMENT style env-options-plist)
      (setq org-lparse-dyn-current-environment nil))))
 
 (defun org-lparse-current-environment-p (style)
@@ -2061,7 +2097,7 @@ When TITLE is nil, just close all open levels."
 
 ;; Notes on LIST-TABLES
 ;; ====================
-;; When `org-lparse-list-table-enable' is non-nil, the following list
+;; Lists withing "list-table" blocks (as shown below)
 ;;
 ;; #+begin_list-table
 ;; - Row 1

+ 43 - 35
contrib/lisp/org-odt.el

@@ -504,8 +504,41 @@ PUB-DIR is set, use this as the publishing directory."
    '("<text:p%s>" . "</text:p>") text
    (org-odt-get-extra-attrs-for-paragraph-style style)))
 
-(defun org-odt-begin-environment (style)
+(defvar org-lparse-opt-plist)		    ; bound during org-do-lparse
+(defun org-odt-format-author (&optional author)
+  (when (setq author (or author (plist-get org-lparse-opt-plist :author)))
+    (org-odt-format-tags '("<dc:creator>" . "</dc:creator>") author)))
+
+(defun org-odt-iso-date-from-org-timestamp (&optional org-ts)
+  (save-match-data
+    (let* ((time
+	    (and (stringp org-ts)
+		 (string-match org-ts-regexp0 org-ts)
+		 (apply 'encode-time
+			(org-fix-decoded-time
+			 (org-parse-time-string (match-string 0 org-ts) t)))))
+	   (date (format-time-string "%Y-%m-%dT%H:%M:%S%z" time)))
+      (format "%s:%s" (substring date 0 -2) (substring date -2)))))
+
+(defun org-odt-begin-annotation (&optional author date)
+  (org-lparse-insert-tag "<office:annotation>")
+  (when (setq author (org-odt-format-author author))
+    (insert author))
+  (insert (org-odt-format-tags
+	   '("<dc:date>" . "</dc:date>")
+	   (org-odt-iso-date-from-org-timestamp
+	    (or date (plist-get org-lparse-opt-plist :date)))))
+  (org-lparse-begin-paragraph))
+
+(defun org-odt-end-annotation ()
+  (org-lparse-insert-tag  "</office:annotation>"))
+
+(defun org-odt-begin-environment (style env-options-plist)
   (case style
+    (annotation
+     (org-lparse-stash-save-paragraph-state)
+     (org-odt-begin-annotation (plist-get env-options-plist 'author)
+			       (plist-get env-options-plist 'date)))
     ((blockquote verse center quote)
      (org-lparse-begin-paragraph style)
      (list))
@@ -514,8 +547,12 @@ PUB-DIR is set, use this as the publishing directory."
      (list))
     (t (error "Unknown environment %s" style))))
 
-(defun org-odt-end-environment (style)
+(defun org-odt-end-environment (style env-options-plist)
   (case style
+    (annotation
+     (org-lparse-end-paragraph)
+     (org-odt-end-annotation)
+     (org-lparse-stash-pop-paragraph-state))
     ((blockquote verse center quote)
      (org-lparse-end-paragraph)
      (list))
@@ -1446,7 +1483,7 @@ MAY-INLINE-P allows inlining it as an image."
 			     (or (org-find-text-property-in-string
 				  'org-latex-src-embed-type src) 'character)
 			   'paragraph)))
-	   (attr-plist (when attr (read  attr)))
+	   (attr-plist (org-lparse-get-block-params attr))
 	   (size (org-odt-image-size-from-file
 		  src (plist-get attr-plist :width)
 		  (plist-get attr-plist :height)
@@ -1840,37 +1877,9 @@ visually."
 	    xml-files)
 
       (delete-directory zipdir)))
-
   (message "Created %s" target)
   (set-buffer (find-file-noselect target t)))
 
-(defun org-odt-format-date (date)
-  (let ((warning-msg
-	 "OpenDocument files require that dates be in ISO-8601 format. Please review your DATE options for compatibility."))
-    ;; If the user is not careful with the date specification, an
-    ;; invalid meta.xml will be emitted.
-
-    ;; For now honor user's diktat and let him off with a warning
-    ;; message. This is OK as LibreOffice (and possibly other
-    ;; apps) doesn't deem this deviation as critical and continue
-    ;; to load the file.
-
-    ;; FIXME: Surely there a better way to handle this. Revisit this
-    ;; later.
-    (cond
-     ((and date (string-match "%" date))
-      ;; Honor user's diktat. See comments above
-      (org-lparse-warn warning-msg)
-      (format-time-string date))
-     (date
-      ;; Honor user's diktat. See comments above
-      (org-lparse-warn warning-msg)
-      date)
-     (t
-      ;; ISO 8601 format
-      (let ((stamp (format-time-string "%Y-%m-%dT%H:%M:%S%z")))
-	(format "%s:%s" (substring stamp 0 -2) (substring stamp -2)))))))
-
 (defconst org-odt-manifest-file-entry-tag
   "
 <manifest:file-entry manifest:media-type=\"%s\" manifest:full-path=\"%s\"%s/>")
@@ -1900,13 +1909,13 @@ visually."
     (write-region "\n</manifest:manifest>" nil manifest-file t)))
 
 (defun org-odt-update-meta-file (opt-plist)
-  (let ((date (org-odt-format-date (plist-get opt-plist :date)))
+  (let ((date (org-odt-iso-date-from-org-timestamp
+	       (plist-get opt-plist :date)))
 	(author (or (plist-get opt-plist :author) ""))
 	(email (plist-get opt-plist :email))
 	(keywords (plist-get opt-plist :keywords))
 	(description (plist-get opt-plist :description))
 	(title (plist-get opt-plist :title)))
-
     (write-region
      (concat
       "<?xml version=\"1.0\" encoding=\"UTF-8\"?>
@@ -1918,7 +1927,7 @@ visually."
          xmlns:ooo=\"http://openoffice.org/2004/office\"
          office:version=\"1.2\">
        <office:meta>" "\n"
-      (org-odt-format-tags '("<dc:creator>" . "</dc:creator>") author)
+      (org-odt-format-author)
       (org-odt-format-tags
        '("\n<meta:initial-creator>" . "</meta:initial-creator>") author)
       (org-odt-format-tags '("\n<dc:date>" . "</dc:date>") date)
@@ -2100,7 +2109,6 @@ using `org-open-file'."
     (t (error "Unknown property: %s"  what))))
 
 (defvar org-lparse-latex-fragment-fallback) ; set by org-do-lparse
-(defvar org-lparse-opt-plist)		    ; bound during org-do-lparse
 (defun org-export-odt-do-preprocess-latex-fragments ()
   "Convert LaTeX fragments to images."
   (let* ((latex-frag-opt (plist-get org-lparse-opt-plist :LaTeX-fragments))