]> code.delx.au - gnu-emacs/blobdiff - lisp/org/org-docbook.el
Merge changes from emacs-23 branch
[gnu-emacs] / lisp / org / org-docbook.el
index e883d71b6f46e4a99cd5f3da67d996b445dc4fc4..f964a93fa1ca6e187fa507a2b2f50388f4dac61b 100644 (file)
@@ -4,7 +4,7 @@
 ;;
 ;; Emacs Lisp Archive Entry
 ;; Filename: org-docbook.el
-;; Version: 7.4
+;; Version: 7.7
 ;; Author: Baoqiu Cui <cbaoqiu AT yahoo DOT com>
 ;; Maintainer: Baoqiu Cui <cbaoqiu AT yahoo DOT com>
 ;; Keywords: org, wp, docbook
@@ -148,6 +148,11 @@ avoid same set of footnote IDs being used multiple times."
   :group 'org-export-docbook
   :type 'string)
 
+(defcustom org-export-docbook-footnote-separator "<superscript>, </superscript>"
+  "Text used to separate footnotes."
+  :group 'org-export-docbook
+  :type 'string)
+
 (defcustom org-export-docbook-emphasis-alist
   `(("*" "<emphasis role=\"bold\">" "</emphasis>")
     ("/" "<emphasis>" "</emphasis>")
@@ -320,7 +325,7 @@ could call this function in the following way:
 When called interactively, the output buffer is selected, and shown
 in a window.  A non-interactive call will only return the buffer."
   (interactive "r\nP")
-  (when (interactive-p)
+  (when (org-called-interactively-p 'any)
     (setq buffer "*Org DocBook Export*"))
   (let ((transient-mark-mode t)
        (zmacs-regions t)
@@ -332,7 +337,7 @@ in a window.  A non-interactive call will only return the buffer."
               nil nil
               buffer body-only))
     (if (fboundp 'deactivate-mark) (deactivate-mark))
-    (if (and (interactive-p) (bufferp rtn))
+    (if (and (org-called-interactively-p 'any) (bufferp rtn))
        (switch-to-buffer-other-window rtn)
       rtn)))
 
@@ -499,9 +504,6 @@ publishing directory."
         (inquote     nil)
         (infixed     nil)
         (inverse     nil)
-        (in-local-list nil)
-        (local-list-type nil)
-        (local-list-indent nil)
         (llt org-plain-list-ordered-item-terminator)
         (email (plist-get opt-plist :email))
         (language (plist-get opt-plist :language))
@@ -522,16 +524,19 @@ publishing directory."
          (buffer-substring
           (if region-p (region-beginning) (point-min))
           (if region-p (region-end) (point-max))))
+        (org-export-footnotes-seen nil)
+        (org-export-footnotes-data (org-footnote-all-labels 'with-defs))
         (lines
          (org-split-string
           (org-export-preprocess-string
            region
            :emph-multiline t
-           :for-docbook t
+           :for-backend 'docbook
            :skip-before-1st-heading
            (plist-get opt-plist :skip-before-1st-heading)
            :drawers (plist-get opt-plist :drawers)
            :todo-keywords (plist-get opt-plist :todo-keywords)
+           :tasks (plist-get opt-plist :tasks)
            :tags (plist-get opt-plist :tags)
            :priority (plist-get opt-plist :priority)
            :footnotes (plist-get opt-plist :footnotes)
@@ -646,7 +651,7 @@ publishing directory."
        (catch 'nextline
 
          ;; End of quote section?
-         (when (and inquote (string-match "^\\*+ " line))
+         (when (and inquote (string-match org-outline-regexp-bol line))
            (insert "]]></programlisting>\n")
            (org-export-docbook-open-para)
            (setq inquote nil))
@@ -671,22 +676,6 @@ publishing directory."
              (org-export-docbook-open-para))
            (throw 'nextline nil))
 
-         ;; List ender: close every open list.
-         (when (equal "ORG-LIST-END" line)
-           (while local-list-type
-             (let ((listtype (car local-list-type)))
-               (org-export-docbook-close-li listtype)
-               (insert (cond
-                        ((equal listtype "o") "</orderedlist>\n")
-                        ((equal listtype "u") "</itemizedlist>\n")
-                        ((equal listtype "d") "</variablelist>\n"))))
-             (pop local-list-type))
-           ;; We did close a list, normal text follows: need <para>
-           (org-export-docbook-open-para)
-           (setq local-list-indent nil
-                 in-local-list nil)
-           (throw 'nextline nil))
-
          ;; Protected HTML
          (when (get-text-property 0 'org-protected line)
            (let (par (ind (get-text-property 0 'original-indentation line)))
@@ -947,7 +936,10 @@ publishing directory."
          (when org-export-with-footnotes
            (setq start 0)
            (while (string-match "\\([^* \t].*?\\)\\[\\([0-9]+\\)\\]" line start)
-             (if (get-text-property (match-beginning 2) 'org-protected line)
+             ;; Discard protected matches not clearly identified as
+             ;; footnote markers.
+             (if (or (get-text-property (match-beginning 2) 'org-protected line)
+                     (not (get-text-property (match-beginning 2) 'org-footnote line)))
                  (setq start (match-end 2))
                (let* ((num (match-string 2 line))
                       (footnote-def (assoc num footnote-list)))
@@ -958,14 +950,22 @@ publishing directory."
                                          org-export-docbook-footnote-id-prefix num)
                                  t t line))
                    (setq line (replace-match
-                               (format "%s<footnote xml:id=\"%s%s\"><para>%s</para></footnote>"
-                                       (match-string 1 line)
-                                       org-export-docbook-footnote-id-prefix
-                                       num
-                                       (if footnote-def
-                                           (save-match-data
-                                             (org-docbook-expand (cdr footnote-def)))
-                                         (format "FOOTNOTE DEFINITION NOT FOUND: %s" num)))
+                               (concat
+                                (format "%s<footnote xml:id=\"%s%s\"><para>%s</para></footnote>"
+                                        (match-string 1 line)
+                                        org-export-docbook-footnote-id-prefix
+                                        num
+                                        (if footnote-def
+                                            (save-match-data
+                                              (org-docbook-expand (cdr footnote-def)))
+                                          (format "FOOTNOTE DEFINITION NOT FOUND: %s" num)))
+                                ;; If another footnote is following the
+                                ;; current one, add a separator.
+                                (if (save-match-data
+                                      (string-match "\\`\\[[0-9]+\\]"
+                                                    (substring line (match-end 0))))
+                                    org-export-docbook-footnote-separator
+                                  ""))
                                t t line))
                    (push (cons num 1) footref-seen))))))
 
@@ -1008,93 +1008,15 @@ publishing directory."
                       (org-format-table-html table-buffer table-orig-buffer
                                              'no-css)))))
 
+          ;; Normal lines
           (t
-           ;; Normal lines
-           (when (string-match
-                  (cond
-                   ((eq llt t) "^\\([ \t]*\\)\\(\\([-+*] \\)\\|\\([0-9]+[.)]\\) \\)?\\( *[^ \t\n\r]\\|[ \t]*$\\)")
-                   ((= llt ?.) "^\\([ \t]*\\)\\(\\([-+*] \\)\\|\\([0-9]+\\.\\) \\)?\\( *[^ \t\n\r]\\|[ \t]*$\\)")
-                   ((= llt ?\)) "^\\([ \t]*\\)\\(\\([-+*] \\)\\|\\([0-9]+)\\) \\)?\\( *[^ \t\n\r]\\|[ \t]*$\\)")
-                   (t (error "Invalid value of `org-plain-list-ordered-item-terminator'")))
-                  line)
-             (setq ind (or (get-text-property 0 'original-indentation line)
-                           (org-get-string-indentation line))
-                   item-type (if (match-beginning 4) "o" "u")
-                   starter (if (match-beginning 2)
-                               (substring (match-string 2 line) 0 -1))
-                   line (substring line (match-beginning 5))
-                   item-tag nil
-                   item-number nil)
-             (if (string-match "\\[@\\(?:start:\\)?\\([0-9]+\\)\\][ \t]?" line)
-                 (setq item-number (match-string 1 line)
-                       line (replace-match "" t t line)))
-             (if (and starter (string-match "\\(.*?\\) ::[ \t]*" line))
-                 (setq item-type "d"
-                       item-tag (match-string 1 line)
-                       line (substring line (match-end 0))))
-             (cond
-              ((and starter
-                    (or (not in-local-list)
-                        (> ind (car local-list-indent))))
-               ;; Start new (level of) list
-               (org-export-docbook-close-para-maybe)
-               (insert (cond
-                        ((equal item-type "u") "<itemizedlist>\n<listitem>\n")
-                        ((and (equal item-type "o") item-number)
-                         ;; Check for a specific start number.  If it
-                         ;; is specified, we use the ``override''
-                         ;; attribute of element <listitem> to pass the
-                         ;; info to DocBook.  We could also use the
-                         ;; ``startingnumber'' attribute of element
-                         ;; <orderedlist>, but the former works on both
-                         ;; DocBook 5.0 and prior versions.
-                         (format "<orderedlist>\n<listitem override=\"%s\">\n" item-number))
-                        ((equal item-type "o") "<orderedlist>\n<listitem>\n")
-                        ((equal item-type "d")
-                         (format "<variablelist>\n<varlistentry><term>%s</term><listitem>\n" item-tag))))
-               ;; For DocBook, we need to open a para right after tag
-               ;; <listitem>.
-               (org-export-docbook-open-para)
-               (push item-type local-list-type)
-               (push ind local-list-indent)
-               (setq in-local-list t))
-               ;; Continue current list
-              (starter
-               ;; terminate any previous sublist but first ensure
-               ;; list is not ill-formed
-               (let ((min-ind (apply 'min local-list-indent)))
-                 (when (< ind min-ind) (setq ind min-ind)))
-               (while (< ind (car local-list-indent))
-                 (let ((listtype (car local-list-type)))
-                   (org-export-docbook-close-li listtype)
-                   (insert (cond
-                            ((equal listtype "o") "</orderedlist>\n")
-                            ((equal listtype "u") "</itemizedlist>\n")
-                            ((equal listtype "d") "</variablelist>\n"))))
-                 (pop local-list-type) (pop local-list-indent)
-                 (setq in-local-list local-list-indent))
-               ;; insert new item
-               (let ((listtype (car local-list-type)))
-                 (org-export-docbook-close-li listtype)
-                 (insert (cond
-                          ((and (equal listtype "o") item-number)
-                           (format "<listitem override=\"%s\">" item-number))
-                          ((equal listtype "o") "<listitem>")
-                          ((equal listtype "u") "<listitem>")
-                          ((equal listtype "d") (format
-                                                 "<varlistentry><term>%s</term><listitem>"
-                                                 (or item-tag
-                                                     "???"))))))
-               ;; For DocBook, we need to open a para right after tag
-               ;; <listitem>.
-               (org-export-docbook-open-para)))
-             ;; Checkboxes.
-             (if (string-match "^[ \t]*\\(\\[[X -]\\]\\)" line)
-                 (setq line
-                       (replace-match (concat checkbox-start
-                                              (match-string 1 line)
-                                              checkbox-end)
-                                      t t line))))
+           ;; This line either is list item or end a list.
+           (when (when (get-text-property 0 'list-item line)
+                     (setq line (org-export-docbook-list-line
+                         line
+                         (get-text-property 0 'list-item line)
+                         (get-text-property 0 'list-struct line)
+                         (get-text-property 0 'list-prevs line)))))
 
            ;; Empty lines start a new paragraph.  If hand-formatted lists
            ;; are not fully interpreted, lines starting with "-", "+", "*"
@@ -1138,20 +1060,12 @@ publishing directory."
        (if (eq major-mode (default-value 'major-mode))
            (nxml-mode)))
 
-      ;; Remove empty paragraphs and lists.  Replace them with a
-      ;; newline.
+      ;; Remove empty paragraphs. Replace them with a newline.
       (goto-char (point-min))
       (while (re-search-forward
              "[ \r\n\t]*\\(<para>\\)[ \r\n\t]*</para>[ \r\n\t]*" nil t)
        (when (not (get-text-property (match-beginning 1) 'org-protected))
          (replace-match "\n")
-         ;; Avoid empty <listitem></listitem> caused by inline tasks.
-         ;; We should add an empty para to make everything valid.
-         (when (and (looking-at "</listitem>")
-                    (save-excursion
-                      (backward-char (length "<listitem>\n"))
-                      (looking-at "<listitem>")))
-           (insert "<para></para>"))
          (backward-char 1)))
       ;; Fill empty sections with <para></para>.  This is to make sure
       ;; that the DocBook document generated is valid and well-formed.
@@ -1193,10 +1107,6 @@ publishing directory."
       (insert "</listitem></varlistentry>\n")
     (insert "</listitem>\n")))
 
-(defvar in-local-list)
-(defvar local-list-indent)
-(defvar local-list-type)
-
 (defun org-export-docbook-level-start (level title)
   "Insert a new level in DocBook export.
 When TITLE is nil, just close all open levels."
@@ -1367,7 +1277,7 @@ TABLE is a string containing the HTML code generated by
                                     (match-string 1 table)
                                     (match-string 4 table)
                                     "</table>")
-                            nil nil table)
+                            nil t table)
            table))
     ;; Change <table> into <informaltable> if caption does not exist.
     (if (string-match
@@ -1377,7 +1287,7 @@ TABLE is a string containing the HTML code generated by
                               (match-string 1 table-with-label)
                               (match-string 3 table-with-label)
                               "</informaltable>")
-                      nil nil table-with-label)
+                      nil t table-with-label)
       table-with-label)))
 
 ;; Note: This function is very similar to
@@ -1438,6 +1348,102 @@ that need to be preserved in later phase of DocBook exporting."
            line (substring line (match-end 0))))
     (concat replaced line)))
 
+(defun org-export-docbook-list-line (line pos struct prevs)
+  "Insert list syntax in export buffer. Return LINE, maybe modified.
+
+POS is the item position or line position the line had before
+modifications to buffer. STRUCT is the list structure. PREVS is
+the alist of previous items."
+  (let* ((get-type
+         (function
+          ;; Translate type of list containing POS to "ordered",
+          ;; "variable" or "itemized".
+          (lambda (pos struct prevs)
+            (let ((type (org-list-get-list-type pos struct prevs)))
+              (cond
+               ((eq 'ordered type) "ordered")
+               ((eq 'descriptive type) "variable")
+               (t "itemized"))))))
+        (get-closings
+         (function
+          ;; Return list of all items and sublists ending at POS, in
+          ;; reverse order.
+          (lambda (pos)
+            (let (out)
+              (catch 'exit
+                (mapc (lambda (e)
+                        (let ((end (nth 6 e))
+                              (item (car e)))
+                          (cond
+                           ((= end pos) (push item out))
+                           ((>= item pos) (throw 'exit nil)))))
+                      struct))
+              out)))))
+    ;; First close any previous item, or list, ending at POS.
+    (mapc (lambda (e)
+           (let* ((lastp (= (org-list-get-last-item e struct prevs) e))
+                  (first-item (org-list-get-list-begin e struct prevs))
+                  (type (funcall get-type first-item struct prevs)))
+             ;; Ending for every item
+             (org-export-docbook-close-para-maybe)
+             (insert (if (equal type "variable")
+                         "</listitem></varlistentry>\n"
+                       "</listitem>\n"))
+             ;; We're ending last item of the list: end list.
+             (when lastp
+               (insert (format "</%slist>\n" type))
+               (org-export-docbook-open-para))))
+         (funcall get-closings pos))
+    (cond
+     ;; At an item: insert appropriate tags in export buffer.
+     ((assq pos struct)
+      (string-match (concat "[ \t]*\\(\\S-+[ \t]*\\)"
+                           "\\(?:\\[@\\(?:start:\\)?\\([0-9]+\\|[a-zA-Z]\\)\\][ \t]*\\)?"
+                           "\\(?:\\(\\[[ X-]\\]\\)[ \t]+\\)?"
+                           "\\(?:\\(.*\\)[ \t]+::\\(?:[ \t]+\\|$\\)\\)?"
+                           "\\(.*\\)")
+                   line)
+      (let* ((checkbox (match-string 3 line))
+            (desc-tag (or (match-string 4 line) "???"))
+            (body (match-string 5 line))
+            (list-beg (org-list-get-list-begin pos struct prevs))
+            (firstp (= list-beg pos))
+            ;; Always refer to first item to determine list type, in
+            ;; case list is ill-formed.
+            (type (funcall get-type list-beg struct prevs))
+            ;; Special variables for ordered lists.
+            (counter (let ((count-tmp (org-list-get-counter pos struct)))
+                       (cond
+                        ((not count-tmp) nil)
+                        ((string-match "[A-Za-z]" count-tmp)
+                         (- (string-to-char (upcase count-tmp)) 64))
+                        ((string-match "[0-9]+" count-tmp)
+                         count-tmp)))))
+       ;; When FIRSTP, a new list or sub-list is starting.
+       (when firstp
+         (org-export-docbook-close-para-maybe)
+         (insert (format "<%slist>\n" type)))
+       (insert (cond
+                ((equal type "variable")
+                 (format "<varlistentry><term>%s</term><listitem>" desc-tag))
+                ((and (equal type "ordered") counter)
+                 (format "<listitem override=\"%s\">" counter))
+                (t "<listitem>")))
+       ;; For DocBook, we need to open a para right after tag
+       ;; <listitem>.
+       (org-export-docbook-open-para)
+       ;; If line had a checkbox, some additional modification is required.
+       (when checkbox (setq body (concat checkbox " " body)))
+       ;; Return modified line
+       body))
+     ;; At a list ender:  normal text follows: need <para>.
+     ((equal "ORG-LIST-END-MARKER" line)
+      (org-export-docbook-open-para)
+      (throw 'nextline nil))
+     ;; Not at an item: return line unchanged (side-effects only).
+     (t line))))
+
 (provide 'org-docbook)
 
+
 ;;; org-docbook.el ends here