Browse Source

Merge branch 'master' of orgmode.org:org-mode

Bastien Guerry 13 years ago
parent
commit
f72bb5733d

+ 47 - 22
contrib/lisp/org-e-ascii.el

@@ -104,23 +104,23 @@
   :menu-entry
   :menu-entry
   (?t "Export to Plain Text"
   (?t "Export to Plain Text"
       ((?A "As ASCII buffer"
       ((?A "As ASCII buffer"
-	   (lambda (s v b)
-	     (org-e-ascii-export-as-ascii s v b '(:ascii-charset ascii))))
+	   (lambda (a s v b)
+	     (org-e-ascii-export-as-ascii a s v b '(:ascii-charset ascii))))
        (?a "As ASCII file"
        (?a "As ASCII file"
-	   (lambda (s v b)
-	     (org-e-ascii-export-to-ascii s v b '(:ascii-charset ascii))))
+	   (lambda (a s v b)
+	     (org-e-ascii-export-to-ascii a s v b '(:ascii-charset ascii))))
        (?L "As Latin1 buffer"
        (?L "As Latin1 buffer"
-	   (lambda (s v b)
-	     (org-e-ascii-export-as-ascii s v b '(:ascii-charset latin1))))
+	   (lambda (a s v b)
+	     (org-e-ascii-export-as-ascii a s v b '(:ascii-charset latin1))))
        (?l "As Latin1 file"
        (?l "As Latin1 file"
-	   (lambda (s v b)
-	     (org-e-ascii-export-to-ascii s v b '(:ascii-charset latin1))))
+	   (lambda (a s v b)
+	     (org-e-ascii-export-to-ascii a s v b '(:ascii-charset latin1))))
        (?U "As UTF-8 buffer"
        (?U "As UTF-8 buffer"
-	   (lambda (s v b)
-	     (org-e-ascii-export-as-ascii s v b '(:ascii-charset utf-8))))
+	   (lambda (a s v b)
+	     (org-e-ascii-export-as-ascii a s v b '(:ascii-charset utf-8))))
        (?u "As UTF-8 file"
        (?u "As UTF-8 file"
-	   (lambda (s v b)
-	     (org-e-ascii-export-to-ascii s v b '(:ascii-charset utf-8))))))
+	   (lambda (a s v b)
+	     (org-e-ascii-export-to-ascii a s v b '(:ascii-charset utf-8))))))
   :filters-alist ((:filter-headline . org-e-ascii-filter-headline-blank-lines)
   :filters-alist ((:filter-headline . org-e-ascii-filter-headline-blank-lines)
 		  (:filter-parse-tree . org-e-ascii-filter-paragraph-spacing)
 		  (:filter-parse-tree . org-e-ascii-filter-paragraph-spacing)
 		  (:filter-section . org-e-ascii-filter-headline-blank-lines))
 		  (:filter-section . org-e-ascii-filter-headline-blank-lines))
@@ -1780,7 +1780,7 @@ This function only applies to `e-ascii' back-end.  See
 
 
 ;;;###autoload
 ;;;###autoload
 (defun org-e-ascii-export-as-ascii
 (defun org-e-ascii-export-as-ascii
-  (&optional subtreep visible-only body-only ext-plist)
+  (&optional async subtreep visible-only body-only ext-plist)
   "Export current buffer to a text buffer.
   "Export current buffer to a text buffer.
 
 
 If narrowing is active in the current buffer, only export its
 If narrowing is active in the current buffer, only export its
@@ -1788,6 +1788,10 @@ narrowed part.
 
 
 If a region is active, export that region.
 If a region is active, export that region.
 
 
+A non-nil optional argument ASYNC means the process should happen
+asynchronously.  The resulting buffer should be accessible
+through the `org-export-stack' interface.
+
 When optional argument SUBTREEP is non-nil, export the sub-tree
 When optional argument SUBTREEP is non-nil, export the sub-tree
 at point, extracting information from the headline properties
 at point, extracting information from the headline properties
 first.
 first.
@@ -1806,16 +1810,27 @@ Export is done in a buffer named \"*Org E-ASCII Export*\", which
 will be displayed when `org-export-show-temporary-export-buffer'
 will be displayed when `org-export-show-temporary-export-buffer'
 is non-nil."
 is non-nil."
   (interactive)
   (interactive)
-  (let ((outbuf (org-export-to-buffer
-		 'e-ascii "*Org E-ASCII Export*"
-		 subtreep visible-only body-only ext-plist)))
-    (with-current-buffer outbuf (text-mode))
-    (when org-export-show-temporary-export-buffer
-      (switch-to-buffer-other-window outbuf))))
+  (if async
+      (org-export-async-start
+	  (lambda (output)
+	    (with-current-buffer (get-buffer-create "*Org E-ASCII Export*")
+	      (erase-buffer)
+	      (insert output)
+	      (goto-char (point-min))
+	      (text-mode)
+	      (org-export-add-to-stack (current-buffer) 'e-ascii)))
+	`(org-export-as 'e-ascii ,subtreep ,visible-only ,body-only
+			',ext-plist))
+    (let ((outbuf (org-export-to-buffer
+		   'e-ascii "*Org E-ASCII Export*"
+		   subtreep visible-only body-only ext-plist)))
+      (with-current-buffer outbuf (text-mode))
+      (when org-export-show-temporary-export-buffer
+	(switch-to-buffer-other-window outbuf)))))
 
 
 ;;;###autoload
 ;;;###autoload
 (defun org-e-ascii-export-to-ascii
 (defun org-e-ascii-export-to-ascii
-  (&optional subtreep visible-only body-only ext-plist)
+  (&optional async subtreep visible-only body-only ext-plist)
   "Export current buffer to a text file.
   "Export current buffer to a text file.
 
 
 If narrowing is active in the current buffer, only export its
 If narrowing is active in the current buffer, only export its
@@ -1823,6 +1838,10 @@ narrowed part.
 
 
 If a region is active, export that region.
 If a region is active, export that region.
 
 
+A non-nil optional argument ASYNC means the process should happen
+asynchronously.  The resulting file should be accessible through
+the `org-export-stack' interface.
+
 When optional argument SUBTREEP is non-nil, export the sub-tree
 When optional argument SUBTREEP is non-nil, export the sub-tree
 at point, extracting information from the headline properties
 at point, extracting information from the headline properties
 first.
 first.
@@ -1840,8 +1859,14 @@ file-local settings.
 Return output file's name."
 Return output file's name."
   (interactive)
   (interactive)
   (let ((outfile (org-export-output-file-name ".txt" subtreep)))
   (let ((outfile (org-export-output-file-name ".txt" subtreep)))
-    (org-export-to-file
-     'e-ascii outfile subtreep visible-only body-only ext-plist)))
+    (if async
+	(org-export-async-start
+	    (lambda (f) (org-export-add-to-stack f 'e-ascii))
+	  `(expand-file-name
+	    (org-export-to-file
+	     'e-ascii ,outfile ,subtreep ,visible-only ,body-only ',ext-plist)))
+      (org-export-to-file
+       'e-ascii outfile subtreep visible-only body-only ext-plist))))
 
 
 ;;;###autoload
 ;;;###autoload
 (defun org-e-ascii-publish-to-ascii (plist filename pub-dir)
 (defun org-e-ascii-publish-to-ascii (plist filename pub-dir)

+ 57 - 15
contrib/lisp/org-e-beamer.el

@@ -273,8 +273,9 @@ brackets.  Return overlay specification, as a string, or nil."
        (?b "As TEX file (Beamer)" org-e-beamer-export-to-latex)
        (?b "As TEX file (Beamer)" org-e-beamer-export-to-latex)
        (?P "As PDF file (Beamer)" org-e-beamer-export-to-pdf)
        (?P "As PDF file (Beamer)" org-e-beamer-export-to-pdf)
        (?O "As PDF file and open (Beamer)"
        (?O "As PDF file and open (Beamer)"
-	   (lambda (s v b)
-	     (org-open-file (org-e-beamer-export-to-pdf s v b))))))
+	   (lambda (a s v b)
+	     (if a (org-e-beamer-export-to-pdf t s v b)
+	       (org-open-file (org-e-beamer-export-to-pdf nil s v b)))))))
   :options-alist
   :options-alist
   ((:beamer-theme "BEAMER_THEME" nil org-e-beamer-theme)
   ((:beamer-theme "BEAMER_THEME" nil org-e-beamer-theme)
    (:beamer-color-theme "BEAMER_COLOR_THEME" nil nil t)
    (:beamer-color-theme "BEAMER_COLOR_THEME" nil nil t)
@@ -980,7 +981,7 @@ value."
 
 
 ;;;###autoload
 ;;;###autoload
 (defun org-e-beamer-export-as-latex
 (defun org-e-beamer-export-as-latex
-  (&optional subtreep visible-only body-only ext-plist)
+  (&optional async subtreep visible-only body-only ext-plist)
   "Export current buffer as a Beamer buffer.
   "Export current buffer as a Beamer buffer.
 
 
 If narrowing is active in the current buffer, only export its
 If narrowing is active in the current buffer, only export its
@@ -988,6 +989,10 @@ narrowed part.
 
 
 If a region is active, export that region.
 If a region is active, export that region.
 
 
+A non-nil optional argument ASYNC means the process should happen
+asynchronously.  The resulting buffer should be accessible
+through the `org-export-stack' interface.
+
 When optional argument SUBTREEP is non-nil, export the sub-tree
 When optional argument SUBTREEP is non-nil, export the sub-tree
 at point, extracting information from the headline properties
 at point, extracting information from the headline properties
 first.
 first.
@@ -1006,16 +1011,28 @@ Export is done in a buffer named \"*Org E-BEAMER Export*\", which
 will be displayed when `org-export-show-temporary-export-buffer'
 will be displayed when `org-export-show-temporary-export-buffer'
 is non-nil."
 is non-nil."
   (interactive)
   (interactive)
-  (let ((outbuf (org-export-to-buffer
-		 'e-beamer "*Org E-BEAMER Export*"
-		 subtreep visible-only body-only ext-plist)))
-    (with-current-buffer outbuf (LaTeX-mode))
-    (when org-export-show-temporary-export-buffer
-      (switch-to-buffer-other-window outbuf))))
+  (if async
+      (org-export-async-start
+	  (lambda (output)
+	    (with-current-buffer (get-buffer-create "*Org E-BEAMER Export*")
+	      (erase-buffer)
+	      (insert output)
+	      (goto-char (point-min))
+	      (LaTeX-mode)
+	      (when org-export-show-temporary-export-buffer
+		(org-export-add-to-stack (current-buffer) 'e-beamer))))
+	`(org-export-as 'e-beamer ,subtreep ,visible-only ,body-only
+			',ext-plist))
+    (let ((outbuf (org-export-to-buffer
+		   'e-beamer "*Org E-BEAMER Export*"
+		   subtreep visible-only body-only ext-plist)))
+      (with-current-buffer outbuf (LaTeX-mode))
+      (when org-export-show-temporary-export-buffer
+	(switch-to-buffer-other-window outbuf)))))
 
 
 ;;;###autoload
 ;;;###autoload
 (defun org-e-beamer-export-to-latex
 (defun org-e-beamer-export-to-latex
-  (&optional subtreep visible-only body-only ext-plist)
+  (&optional async subtreep visible-only body-only ext-plist)
   "Export current buffer as a Beamer presentation (tex).
   "Export current buffer as a Beamer presentation (tex).
 
 
 If narrowing is active in the current buffer, only export its
 If narrowing is active in the current buffer, only export its
@@ -1023,6 +1040,10 @@ narrowed part.
 
 
 If a region is active, export that region.
 If a region is active, export that region.
 
 
+A non-nil optional argument ASYNC means the process should happen
+asynchronously.  The resulting file should be accessible through
+the `org-export-stack' interface.
+
 When optional argument SUBTREEP is non-nil, export the sub-tree
 When optional argument SUBTREEP is non-nil, export the sub-tree
 at point, extracting information from the headline properties
 at point, extracting information from the headline properties
 first.
 first.
@@ -1040,12 +1061,19 @@ file-local settings.
 Return output file's name."
 Return output file's name."
   (interactive)
   (interactive)
   (let ((outfile (org-export-output-file-name ".tex" subtreep)))
   (let ((outfile (org-export-output-file-name ".tex" subtreep)))
-    (org-export-to-file
-     'e-beamer outfile subtreep visible-only body-only ext-plist)))
+    (if async
+	(org-export-async-start
+	    (lambda (f) (org-export-add-to-stack f 'e-beamer))
+	  `(expand-file-name
+	    (org-export-to-file
+	     'e-beamer ,outfile ,subtreep ,visible-only ,body-only
+	     ',ext-plist)))
+      (org-export-to-file
+       'e-beamer outfile subtreep visible-only body-only ext-plist))))
 
 
 ;;;###autoload
 ;;;###autoload
 (defun org-e-beamer-export-to-pdf
 (defun org-e-beamer-export-to-pdf
-  (&optional subtreep visible-only body-only ext-plist)
+  (&optional async subtreep visible-only body-only ext-plist)
   "Export current buffer as a Beamer presentation (PDF).
   "Export current buffer as a Beamer presentation (PDF).
 
 
 If narrowing is active in the current buffer, only export its
 If narrowing is active in the current buffer, only export its
@@ -1053,6 +1081,10 @@ narrowed part.
 
 
 If a region is active, export that region.
 If a region is active, export that region.
 
 
+A non-nil optional argument ASYNC means the process should happen
+asynchronously.  The resulting file should be accessible through
+the `org-export-stack' interface.
+
 When optional argument SUBTREEP is non-nil, export the sub-tree
 When optional argument SUBTREEP is non-nil, export the sub-tree
 at point, extracting information from the headline properties
 at point, extracting information from the headline properties
 first.
 first.
@@ -1069,8 +1101,18 @@ file-local settings.
 
 
 Return PDF file's name."
 Return PDF file's name."
   (interactive)
   (interactive)
-  (org-e-latex-compile
-   (org-e-beamer-export-to-latex subtreep visible-only body-only ext-plist)))
+  (if async
+      (let ((outfile (org-export-output-file-name ".tex" subtreep)))
+	(org-export-async-start
+	    (lambda (f) (org-export-add-to-stack f 'e-beamer))
+	  `(expand-file-name
+	    (org-e-latex-compile
+	     (org-export-to-file
+	      'e-beamer ,outfile ,subtreep ,visible-only ,body-only
+	      ',ext-plist)))))
+    (org-e-latex-compile
+     (org-e-beamer-export-to-latex
+      nil subtreep visible-only body-only ext-plist))))
 
 
 ;;;###autoload
 ;;;###autoload
 (defun org-e-beamer-select-environment ()
 (defun org-e-beamer-select-environment ()

+ 38 - 9
contrib/lisp/org-e-groff.el

@@ -100,7 +100,9 @@
       ((?g "As GROFF file" org-e-groff-export-to-groff)
       ((?g "As GROFF file" org-e-groff-export-to-groff)
        (?p "As PDF file" org-e-groff-export-to-pdf)
        (?p "As PDF file" org-e-groff-export-to-pdf)
        (?o "As PDF file and open"
        (?o "As PDF file and open"
-	   (lambda (s v b) (org-open-file (org-e-groff-export-to-pdf s v b))))))
+	   (lambda (a s v b)
+	     (if a (org-e-groff-export-to-pdf t s v b)
+	       (org-open-file (org-e-groff-export-to-pdf nil s v b)))))))
   :options-alist
   :options-alist
   ((:groff-class "GROFF_CLASS" nil org-e-groff-default-class t)
   ((:groff-class "GROFF_CLASS" nil org-e-groff-default-class t)
    (:groff-class-options "GROFF_CLASS_OPTIONS" nil nil t)
    (:groff-class-options "GROFF_CLASS_OPTIONS" nil nil t)
@@ -1886,7 +1888,7 @@ contextual information."
 ;;; Interactive functions
 ;;; Interactive functions
 
 
 (defun org-e-groff-export-to-groff
 (defun org-e-groff-export-to-groff
-  (&optional subtreep visible-only body-only ext-plist)
+  (&optional async subtreep visible-only body-only ext-plist)
   "Export current buffer to a Groff file.
   "Export current buffer to a Groff file.
 
 
 If narrowing is active in the current buffer, only export its
 If narrowing is active in the current buffer, only export its
@@ -1894,6 +1896,10 @@ narrowed part.
 
 
 If a region is active, export that region.
 If a region is active, export that region.
 
 
+A non-nil optional argument ASYNC means the process should happen
+asynchronously.  The resulting file should be accessible through
+the `org-export-stack' interface.
+
 When optional argument SUBTREEP is non-nil, export the sub-tree
 When optional argument SUBTREEP is non-nil, export the sub-tree
 at point, extracting information from the headline properties
 at point, extracting information from the headline properties
 first.
 first.
@@ -1907,14 +1913,23 @@ file-local settings.
 
 
 Return output file's name."
 Return output file's name."
   (interactive)
   (interactive)
-  (setq org-e-groff-registered-references nil)
-  (setq org-e-groff-special-content nil)
   (let ((outfile (org-export-output-file-name ".groff" subtreep)))
   (let ((outfile (org-export-output-file-name ".groff" subtreep)))
-    (org-export-to-file
-     'e-groff outfile subtreep visible-only body-only ext-plist)))
+    (if async
+	(org-export-async-start
+	    (lambda (f) (org-export-add-to-stack f 'e-groff))
+	  (let ((org-e-groff-registered-references nil)
+		(org-e-groff-special-content nil))
+	    `(expand-file-name
+	      (org-export-to-file
+	       'e-groff ,outfile ,subtreep ,visible-only ,body-only
+	       ',ext-plist))))
+      (let ((org-e-groff-registered-references nil)
+	    (org-e-groff-special-content nil))
+	(org-export-to-file
+	 'e-groff outfile subtreep visible-only body-only ext-plist)))))
 
 
 (defun org-e-groff-export-to-pdf
 (defun org-e-groff-export-to-pdf
-  (&optional subtreep visible-only body-only ext-plist)
+  (&optional async subtreep visible-only body-only ext-plist)
   "Export current buffer to Groff then process through to PDF.
   "Export current buffer to Groff then process through to PDF.
 
 
 If narrowing is active in the current buffer, only export its
 If narrowing is active in the current buffer, only export its
@@ -1922,6 +1937,10 @@ narrowed part.
 
 
 If a region is active, export that region.
 If a region is active, export that region.
 
 
+A non-nil optional argument ASYNC means the process should happen
+asynchronously.  The resulting file should be accessible through
+the `org-export-stack' interface.
+
 When optional argument SUBTREEP is non-nil, export the sub-tree
 When optional argument SUBTREEP is non-nil, export the sub-tree
 at point, extracting information from the headline properties
 at point, extracting information from the headline properties
 first.
 first.
@@ -1935,8 +1954,18 @@ file-local settings.
 
 
 Return PDF file's name."
 Return PDF file's name."
   (interactive)
   (interactive)
-  (org-e-groff-compile
-   (org-e-groff-export-to-groff subtreep visible-only body-only ext-plist)))
+  (if async
+      (let ((outfile (org-export-output-file-name ".groff" subtreep)))
+	(org-export-async-start
+	    (lambda (f) (org-export-add-to-stack f 'e-groff))
+	  `(expand-file-name
+	    (org-e-groff-compile
+	     (org-export-to-file
+	      'e-groff ,outfile ,subtreep ,visible-only ,body-only
+	      ',ext-plist)))))
+    (org-e-groff-compile
+     (org-e-groff-export-to-groff
+      nil subtreep visible-only body-only ext-plist))))
 
 
 (defun org-e-groff-compile (file)
 (defun org-e-groff-compile (file)
   "Compile a Groff file.
   "Compile a Groff file.

+ 41 - 13
contrib/lisp/org-e-html.el

@@ -108,7 +108,9 @@
       ((?H "To temporary buffer" org-e-html-export-as-html)
       ((?H "To temporary buffer" org-e-html-export-as-html)
        (?h "To file" org-e-html-export-to-html)
        (?h "To file" org-e-html-export-to-html)
        (?o "To file and open"
        (?o "To file and open"
-	   (lambda (s v b) (org-open-file (org-e-html-export-to-html s v b))))))
+	   (lambda (a s v b)
+	     (if a (org-e-html-export-to-html t s v b)
+	       (org-open-file (org-e-html-export-to-html nil s v b)))))))
   :options-alist
   :options-alist
   ;; FIXME: Prefix KEYWORD and OPTION with "HTML_".  Prefix
   ;; FIXME: Prefix KEYWORD and OPTION with "HTML_".  Prefix
   ;; corresponding properties with `:html-".  If such a renaming is
   ;; corresponding properties with `:html-".  If such a renaming is
@@ -2746,7 +2748,7 @@ contextual information."
 
 
 ;;;###autoload
 ;;;###autoload
 (defun org-e-html-export-as-html
 (defun org-e-html-export-as-html
-  (&optional subtreep visible-only body-only ext-plist)
+  (&optional async subtreep visible-only body-only ext-plist)
   "Export current buffer to an HTML buffer.
   "Export current buffer to an HTML buffer.
 
 
 If narrowing is active in the current buffer, only export its
 If narrowing is active in the current buffer, only export its
@@ -2754,6 +2756,10 @@ narrowed part.
 
 
 If a region is active, export that region.
 If a region is active, export that region.
 
 
+A non-nil optional argument ASYNC means the process should happen
+asynchronously.  The resulting buffer should be accessible
+through the `org-export-stack' interface.
+
 When optional argument SUBTREEP is non-nil, export the sub-tree
 When optional argument SUBTREEP is non-nil, export the sub-tree
 at point, extracting information from the headline properties
 at point, extracting information from the headline properties
 first.
 first.
@@ -2772,18 +2778,28 @@ Export is done in a buffer named \"*Org E-HTML Export*\", which
 will be displayed when `org-export-show-temporary-export-buffer'
 will be displayed when `org-export-show-temporary-export-buffer'
 is non-nil."
 is non-nil."
   (interactive)
   (interactive)
-  (let ((outbuf
-	 (org-export-to-buffer
-	  'e-html "*Org E-HTML Export*"
-	  subtreep visible-only body-only ext-plist)))
-    ;; Set major mode.
-    (with-current-buffer outbuf (nxml-mode))
-    (when org-export-show-temporary-export-buffer
-      (switch-to-buffer-other-window outbuf))))
+  (if async
+      (org-export-async-start
+	  (lambda (output)
+	    (with-current-buffer (get-buffer-create "*Org E-HTML Export*")
+	      (erase-buffer)
+	      (insert output)
+	      (goto-char (point-min))
+	      (nxml-mode)
+	      (when org-export-show-temporary-export-buffer
+		(org-export-add-to-stack (current-buffer) 'e-html))))
+	`(org-export-as 'e-html ,subtreep ,visible-only ,body-only ',ext-plist))
+    (let ((outbuf (org-export-to-buffer
+		   'e-html "*Org E-HTML Export*"
+		   subtreep visible-only body-only ext-plist)))
+      ;; Set major mode.
+      (with-current-buffer outbuf (nxml-mode))
+      (when org-export-show-temporary-export-buffer
+	(switch-to-buffer-other-window outbuf)))))
 
 
 ;;;###autoload
 ;;;###autoload
 (defun org-e-html-export-to-html
 (defun org-e-html-export-to-html
-  (&optional subtreep visible-only body-only ext-plist)
+  (&optional async subtreep visible-only body-only ext-plist)
   "Export current buffer to a HTML file.
   "Export current buffer to a HTML file.
 
 
 If narrowing is active in the current buffer, only export its
 If narrowing is active in the current buffer, only export its
@@ -2791,6 +2807,10 @@ narrowed part.
 
 
 If a region is active, export that region.
 If a region is active, export that region.
 
 
+A non-nil optional argument ASYNC means the process should happen
+asynchronously.  The resulting file should be accessible through
+the `org-export-stack' interface.
+
 When optional argument SUBTREEP is non-nil, export the sub-tree
 When optional argument SUBTREEP is non-nil, export the sub-tree
 at point, extracting information from the headline properties
 at point, extracting information from the headline properties
 first.
 first.
@@ -2810,8 +2830,16 @@ Return output file's name."
   (let* ((extension (concat "." org-e-html-extension))
   (let* ((extension (concat "." org-e-html-extension))
 	 (file (org-export-output-file-name extension subtreep))
 	 (file (org-export-output-file-name extension subtreep))
 	 (org-export-coding-system org-e-html-coding-system))
 	 (org-export-coding-system org-e-html-coding-system))
-    (org-export-to-file
-     'e-html file subtreep visible-only body-only ext-plist)))
+    (if async
+	(org-export-async-start
+	    (lambda (f) (org-export-add-to-stack f 'e-latex))
+	  (let ((org-export-coding-system org-e-html-coding-system))
+	    `(expand-file-name
+	      (org-export-to-file
+	       'e-html ,file ,subtreep ,visible-only ,body-only ',ext-plist))))
+      (let ((org-export-coding-system org-e-html-coding-system))
+	(org-export-to-file
+	 'e-html file subtreep visible-only body-only ext-plist)))))
 
 
 ;;;###autoload
 ;;;###autoload
 (defun org-e-html-publish-to-html (plist filename pub-dir)
 (defun org-e-html-publish-to-html (plist filename pub-dir)

+ 71 - 26
contrib/lisp/org-e-icalendar.el

@@ -274,12 +274,11 @@ re-read the iCalendar file.")
   ((:filter-headline . org-e-icalendar-clear-blank-lines))
   ((:filter-headline . org-e-icalendar-clear-blank-lines))
   :menu-entry
   :menu-entry
   (?c "Export to iCalendar"
   (?c "Export to iCalendar"
-      ((?f "Current file"
-	   (lambda (s v b) (org-e-icalendar-export-to-ics s v b)))
+      ((?f "Current file" org-e-icalendar-export-to-ics)
        (?a "All agenda files"
        (?a "All agenda files"
-	   (lambda (s v b) (org-e-icalendar-export-agenda-files)))
+	   (lambda (a s v b) (org-e-icalendar-export-agenda-files a)))
        (?c "Combine all agenda files"
        (?c "Combine all agenda files"
-	   (lambda (s v b) (org-e-icalendar-combine-agenda-files))))))
+	   (lambda (a s v b) (org-e-icalendar-combine-agenda-files a))))))
 
 
 
 
 
 
@@ -789,7 +788,8 @@ CALSCALE:GREGORIAN\n"
 ;;; Interactive Functions
 ;;; Interactive Functions
 
 
 ;;;###autoload
 ;;;###autoload
-(defun org-e-icalendar-export-to-ics (&optional subtreep visible-only body-only)
+(defun org-e-icalendar-export-to-ics
+  (&optional async subtreep visible-only body-only)
   "Export current buffer to an iCalendar file.
   "Export current buffer to an iCalendar file.
 
 
 If narrowing is active in the current buffer, only export its
 If narrowing is active in the current buffer, only export its
@@ -797,6 +797,10 @@ narrowed part.
 
 
 If a region is active, export that region.
 If a region is active, export that region.
 
 
+A non-nil optional argument ASYNC means the process should happen
+asynchronously.  The resulting file should be accessible through
+the `org-export-stack' interface.
+
 When optional argument SUBTREEP is non-nil, export the sub-tree
 When optional argument SUBTREEP is non-nil, export the sub-tree
 at point, extracting information from the headline properties
 at point, extracting information from the headline properties
 first.
 first.
@@ -814,35 +818,76 @@ Return ICS file name."
       (org-e-icalendar-create-uid file 'warn-user)))
       (org-e-icalendar-create-uid file 'warn-user)))
   ;; Export part.  Since this back-end is backed up by `e-ascii',
   ;; Export part.  Since this back-end is backed up by `e-ascii',
   ;; ensure links will not be collected at the end of sections.
   ;; ensure links will not be collected at the end of sections.
-  (let ((outfile (org-export-output-file-name ".ics" subtreep))
-	(org-e-ascii-links-to-notes nil))
-    (org-export-to-file 'e-icalendar outfile subtreep visible-only body-only
-			'(:ascii-charset utf-8))
-    (run-hook-with-args 'org-e-icalendar-after-save-hook outfile)
-    outfile))
+  (let ((outfile (org-export-output-file-name ".ics" subtreep)))
+    (if async
+	(org-export-async-start
+	    (lambda (f)
+	      (org-export-add-to-stack f 'e-icalendar)
+	      (run-hook-with-args 'org-e-icalendar-after-save-hook f))
+	  `(let ((org-e-ascii-links-to-notes nil))
+	     (expand-file-name
+	      (org-export-to-file
+	       'e-icalendar ,outfile ,subtreep ,visible-only ,body-only
+	       '(:ascii-charset utf-8)))))
+      (let ((org-e-ascii-links-to-notes nil))
+	(org-export-to-file 'e-icalendar outfile subtreep visible-only body-only
+			    '(:ascii-charset utf-8)))
+      (run-hook-with-args 'org-e-icalendar-after-save-hook outfile)
+      outfile)))
 
 
 ;;;###autoload
 ;;;###autoload
-(defun org-e-icalendar-export-agenda-files ()
-  "Export all agenda files to iCalendar files."
+(defun org-e-icalendar-export-agenda-files (&optional async)
+  "Export all agenda files to iCalendar files.
+When optional argument ASYNC is non-nil, export happens in an
+external process."
   (interactive)
   (interactive)
-  (let ((files (org-agenda-files t)))
-    (org-agenda-prepare-buffers files)
-    (unwind-protect
-	(mapc (lambda (file)
-		(catch 'nextfile
-		  (org-check-agenda-file file)
-		  (with-current-buffer (org-get-agenda-file-buffer file)
-		    (org-e-icalendar-export-to-ics))))
-	      files)
-      (org-release-buffers org-agenda-new-buffers))))
+  (if async
+      ;; Asynchronous export is not interactive, so we will not call
+      ;; `org-check-agenda-file'.  Instead we remove any non-existent
+      ;; agenda file from the list.
+      (let ((files (org-remove-if-not 'file-exists-p (org-agenda-files t))))
+	(org-export-async-start
+	    (lambda (results)
+	      (mapc (lambda (f) (org-export-add-to-stack f 'icalendar))
+		    results))
+	  `(let (output-files)
+	     (mapc (lambda (file)
+		     (with-current-buffer (org-get-agenda-file-buffer file)
+		       (push (expand-file-name (org-e-icalendar-export-to-ics))
+			     output-files)))
+		   ',files)
+	     output-files)))
+    (let ((files (org-agenda-files t)))
+      (org-agenda-prepare-buffers files)
+      (unwind-protect
+	  (mapc (lambda (file)
+		  (catch 'nextfile
+		    (org-check-agenda-file file)
+		    (with-current-buffer (org-get-agenda-file-buffer file)
+		      (org-e-icalendar-export-to-ics))))
+		files)
+	(org-release-buffers org-agenda-new-buffers)))))
 
 
 ;;;###autoload
 ;;;###autoload
-(defun org-e-icalendar-combine-agenda-files ()
+(defun org-e-icalendar-combine-agenda-files (&optional async)
   "Combine all agenda files into a single iCalendar file.
   "Combine all agenda files into a single iCalendar file.
-The file is stored under the name
+
+A non-nil optional argument ASYNC means the process should happen
+asynchronously.  The resulting file should be accessible through
+the `org-export-stack' interface.
+
+The file is stored under the name chosen in
 `org-e-icalendar-combined-agenda-file'."
 `org-e-icalendar-combined-agenda-file'."
   (interactive)
   (interactive)
-  (apply 'org-e-icalendar--combine-files nil (org-agenda-files t)))
+  (if async
+      (let ((files (org-remove-if-not 'file-exists-p (org-agenda-files t))))
+	(org-export-async-start
+	    (lambda (dummy)
+	      (org-export-add-to-stack
+	       (expand-file-name org-e-icalendar-combined-agenda-file)
+	       'e-icalendar))
+	  `(apply 'org-e-icalendar--combine-files nil ',files)))
+    (apply 'org-e-icalendar--combine-files nil (org-agenda-files t))))
 
 
 (defun org-e-icalendar-export-current-agenda ()
 (defun org-e-icalendar-export-current-agenda ()
   "Export current agenda view to an iCalendar file.
   "Export current agenda view to an iCalendar file.

+ 55 - 14
contrib/lisp/org-e-latex.el

@@ -156,7 +156,9 @@
        (?l "As TEX file" org-e-latex-export-to-latex)
        (?l "As TEX file" org-e-latex-export-to-latex)
        (?p "As PDF file" org-e-latex-export-to-pdf)
        (?p "As PDF file" org-e-latex-export-to-pdf)
        (?o "As PDF file and open"
        (?o "As PDF file and open"
-	   (lambda (s v b) (org-open-file (org-e-latex-export-to-pdf s v b))))))
+	   (lambda (a s v b)
+	     (if a (org-e-latex-export-to-pdf t s v b)
+	       (org-open-file (org-e-latex-export-to-pdf nil s v b)))))))
   :options-alist ((:date "DATE" nil org-e-latex-date-format t)
   :options-alist ((:date "DATE" nil org-e-latex-date-format t)
 		  (:latex-class "LATEX_CLASS" nil org-e-latex-default-class t)
 		  (:latex-class "LATEX_CLASS" nil org-e-latex-default-class t)
 		  (:latex-class-options "LATEX_CLASS_OPTIONS" nil nil t)
 		  (:latex-class-options "LATEX_CLASS_OPTIONS" nil nil t)
@@ -2639,7 +2641,7 @@ contextual information."
 
 
 ;;;###autoload
 ;;;###autoload
 (defun org-e-latex-export-as-latex
 (defun org-e-latex-export-as-latex
-  (&optional subtreep visible-only body-only ext-plist)
+  (&optional async subtreep visible-only body-only ext-plist)
   "Export current buffer as a LaTeX buffer.
   "Export current buffer as a LaTeX buffer.
 
 
 If narrowing is active in the current buffer, only export its
 If narrowing is active in the current buffer, only export its
@@ -2647,6 +2649,10 @@ narrowed part.
 
 
 If a region is active, export that region.
 If a region is active, export that region.
 
 
+A non-nil optional argument ASYNC means the process should happen
+asynchronously.  The resulting buffer should be accessible
+through the `org-export-stack' interface.
+
 When optional argument SUBTREEP is non-nil, export the sub-tree
 When optional argument SUBTREEP is non-nil, export the sub-tree
 at point, extracting information from the headline properties
 at point, extracting information from the headline properties
 first.
 first.
@@ -2665,16 +2671,27 @@ Export is done in a buffer named \"*Org E-LATEX Export*\", which
 will be displayed when `org-export-show-temporary-export-buffer'
 will be displayed when `org-export-show-temporary-export-buffer'
 is non-nil."
 is non-nil."
   (interactive)
   (interactive)
-  (let ((outbuf (org-export-to-buffer
-		 'e-latex "*Org E-LATEX Export*"
-		 subtreep visible-only body-only ext-plist)))
-    (with-current-buffer outbuf (LaTeX-mode))
-    (when org-export-show-temporary-export-buffer
-      (switch-to-buffer-other-window outbuf))))
+  (if async
+      (org-export-async-start
+	  (lambda (output)
+	    (with-current-buffer (get-buffer-create "*Org E-LATEX Export*")
+	      (erase-buffer)
+	      (insert output)
+	      (goto-char (point-min))
+	      (LaTeX-mode)
+	      (org-export-add-to-stack (current-buffer) 'e-latex)))
+	`(org-export-as 'e-latex ,subtreep ,visible-only ,body-only
+			',ext-plist))
+    (let ((outbuf
+	   (org-export-to-buffer 'e-latex "*Org E-LATEX Export*"
+				 subtreep visible-only body-only ext-plist)))
+      (with-current-buffer outbuf (LaTeX-mode))
+      (when org-export-show-temporary-export-buffer
+	(switch-to-buffer-other-window outbuf)))))
 
 
 ;;;###autoload
 ;;;###autoload
 (defun org-e-latex-export-to-latex
 (defun org-e-latex-export-to-latex
-  (&optional subtreep visible-only body-only ext-plist)
+  (&optional async subtreep visible-only body-only ext-plist)
   "Export current buffer to a LaTeX file.
   "Export current buffer to a LaTeX file.
 
 
 If narrowing is active in the current buffer, only export its
 If narrowing is active in the current buffer, only export its
@@ -2682,6 +2699,10 @@ narrowed part.
 
 
 If a region is active, export that region.
 If a region is active, export that region.
 
 
+A non-nil optional argument ASYNC means the process should happen
+asynchronously.  The resulting file should be accessible through
+the `org-export-stack' interface.
+
 When optional argument SUBTREEP is non-nil, export the sub-tree
 When optional argument SUBTREEP is non-nil, export the sub-tree
 at point, extracting information from the headline properties
 at point, extracting information from the headline properties
 first.
 first.
@@ -2699,12 +2720,18 @@ file-local settings.
 Return output file's name."
 Return output file's name."
   (interactive)
   (interactive)
   (let ((outfile (org-export-output-file-name ".tex" subtreep)))
   (let ((outfile (org-export-output-file-name ".tex" subtreep)))
-    (org-export-to-file
-     'e-latex outfile subtreep visible-only body-only ext-plist)))
+    (if async
+	(org-export-async-start
+	    (lambda (f) (org-export-add-to-stack f 'e-latex))
+	  `(expand-file-name
+	    (org-export-to-file
+	     'e-latex ,outfile ,subtreep ,visible-only ,body-only ',ext-plist)))
+      (org-export-to-file
+       'e-latex outfile subtreep visible-only body-only ext-plist))))
 
 
 ;;;###autoload
 ;;;###autoload
 (defun org-e-latex-export-to-pdf
 (defun org-e-latex-export-to-pdf
-  (&optional subtreep visible-only body-only ext-plist)
+  (&optional async subtreep visible-only body-only ext-plist)
   "Export current buffer to LaTeX then process through to PDF.
   "Export current buffer to LaTeX then process through to PDF.
 
 
 If narrowing is active in the current buffer, only export its
 If narrowing is active in the current buffer, only export its
@@ -2712,6 +2739,10 @@ narrowed part.
 
 
 If a region is active, export that region.
 If a region is active, export that region.
 
 
+A non-nil optional argument ASYNC means the process should happen
+asynchronously.  The resulting file should be accessible through
+the `org-export-stack' interface.
+
 When optional argument SUBTREEP is non-nil, export the sub-tree
 When optional argument SUBTREEP is non-nil, export the sub-tree
 at point, extracting information from the headline properties
 at point, extracting information from the headline properties
 first.
 first.
@@ -2728,8 +2759,18 @@ file-local settings.
 
 
 Return PDF file's name."
 Return PDF file's name."
   (interactive)
   (interactive)
-  (org-e-latex-compile
-   (org-e-latex-export-to-latex subtreep visible-only body-only ext-plist)))
+  (if async
+      (let ((outfile (org-export-output-file-name ".tex" subtreep)))
+	(org-export-async-start
+	    (lambda (f) (org-export-add-to-stack f 'e-latex))
+	  `(expand-file-name
+	    (org-e-latex-compile
+	     (org-export-to-file
+	      'e-latex ,outfile ,subtreep ,visible-only ,body-only
+	      ',ext-plist)))))
+    (org-e-latex-compile
+     (org-e-latex-export-to-latex
+      nil subtreep visible-only body-only ext-plist))))
 
 
 (defun org-e-latex-compile (texfile)
 (defun org-e-latex-compile (texfile)
   "Compile a TeX file.
   "Compile a TeX file.

+ 32 - 7
contrib/lisp/org-e-man.el

@@ -108,7 +108,9 @@
       ((?m "As MAN file" org-e-man-export-to-man)
       ((?m "As MAN file" org-e-man-export-to-man)
        (?p "As PDF file" org-e-man-export-to-pdf)
        (?p "As PDF file" org-e-man-export-to-pdf)
        (?o "As PDF file and open"
        (?o "As PDF file and open"
-	   (lambda (s v b) (org-open-file (org-e-man-export-to-pdf s v b))))))
+	   (lambda (a s v b)
+	     (if a (org-e-man-export-to-pdf t s v b)
+	       (org-open-file (org-e-man-export-to-pdf nil s v b)))))))
   :options-alist
   :options-alist
   ((:man-class "MAN_CLASS" nil nil t)
   ((:man-class "MAN_CLASS" nil nil t)
    (:man-class-options "MAN_CLASS_OPTIONS" nil nil t)
    (:man-class-options "MAN_CLASS_OPTIONS" nil nil t)
@@ -1146,7 +1148,7 @@ contextual information."
 ;;; Interactive functions
 ;;; Interactive functions
 
 
 (defun org-e-man-export-to-man
 (defun org-e-man-export-to-man
-  (&optional subtreep visible-only body-only ext-plist)
+  (&optional async subtreep visible-only body-only ext-plist)
   "Export current buffer to a Man file.
   "Export current buffer to a Man file.
 
 
 If narrowing is active in the current buffer, only export its
 If narrowing is active in the current buffer, only export its
@@ -1154,6 +1156,10 @@ narrowed part.
 
 
 If a region is active, export that region.
 If a region is active, export that region.
 
 
+A non-nil optional argument ASYNC means the process should happen
+asynchronously.  The resulting file should be accessible through
+the `org-export-stack' interface.
+
 When optional argument SUBTREEP is non-nil, export the sub-tree
 When optional argument SUBTREEP is non-nil, export the sub-tree
 at point, extracting information from the headline properties
 at point, extracting information from the headline properties
 first.
 first.
@@ -1171,11 +1177,17 @@ file-local settings.
 Return output file's name."
 Return output file's name."
   (interactive)
   (interactive)
   (let ((outfile (org-export-output-file-name ".man" subtreep)))
   (let ((outfile (org-export-output-file-name ".man" subtreep)))
-    (org-export-to-file
-     'e-man outfile subtreep visible-only body-only ext-plist)))
+    (if async
+	(org-export-async-start
+	    (lambda (f) (org-export-add-to-stack f 'e-man))
+	  `(expand-file-name
+	    (org-export-to-file
+	     'e-man ,outfile ,subtreep ,visible-only ,body-only ',ext-plist)))
+      (org-export-to-file
+       'e-man outfile subtreep visible-only body-only ext-plist))))
 
 
 (defun org-e-man-export-to-pdf
 (defun org-e-man-export-to-pdf
-  (&optional subtreep visible-only body-only ext-plist)
+  (&optional async subtreep visible-only body-only ext-plist)
   "Export current buffer to Groff then process through to PDF.
   "Export current buffer to Groff then process through to PDF.
 
 
 If narrowing is active in the current buffer, only export its
 If narrowing is active in the current buffer, only export its
@@ -1183,6 +1195,10 @@ narrowed part.
 
 
 If a region is active, export that region.
 If a region is active, export that region.
 
 
+A non-nil optional argument ASYNC means the process should happen
+asynchronously.  The resulting file should be accessible through
+the `org-export-stack' interface.
+
 When optional argument SUBTREEP is non-nil, export the sub-tree
 When optional argument SUBTREEP is non-nil, export the sub-tree
 at point, extracting information from the headline properties
 at point, extracting information from the headline properties
 first.
 first.
@@ -1199,8 +1215,17 @@ file-local settings.
 
 
 Return PDF file's name."
 Return PDF file's name."
   (interactive)
   (interactive)
-  (org-e-man-compile
-   (org-e-man-export-to-man subtreep visible-only body-only ext-plist)))
+  (if async
+      (let ((outfile (org-export-output-file-name ".man" subtreep)))
+	(org-export-async-start
+	    (lambda (f) (org-export-add-to-stack f 'e-man))
+	  `(expand-file-name
+	    (org-e-man-compile
+	     (org-export-to-file
+	      'e-man ,outfile ,subtreep ,visible-only ,body-only
+	      ',ext-plist)))))
+    (org-e-man-compile
+     (org-e-man-export-to-man nil subtreep visible-only body-only ext-plist))))
 
 
 (defun org-e-man-compile (file)
 (defun org-e-man-compile (file)
   "Compile a Groff file.
   "Compile a Groff file.

+ 48 - 23
contrib/lisp/org-e-odt.el

@@ -91,8 +91,9 @@
   (?o "Export to ODT"
   (?o "Export to ODT"
       ((?o "As ODT file" org-e-odt-export-to-odt)
       ((?o "As ODT file" org-e-odt-export-to-odt)
        (?O "As ODT file and open"
        (?O "As ODT file and open"
-	   (lambda (s v b)
-	     (org-open-file (org-e-odt-export-to-odt s v b) 'system)))))
+	   (lambda (a s v b)
+	     (if a (org-e-odt-export-to-odt t s v)
+	       (org-open-file (org-e-odt-export-to-odt nil s v) 'system))))))
   :options-alist
   :options-alist
   ((:odt-styles-file "ODT_STYLES_FILE" nil nil t)
   ((:odt-styles-file "ODT_STYLES_FILE" nil nil t)
    (:LaTeX-fragments nil "LaTeX" org-export-with-LaTeX-fragments)))
    (:LaTeX-fragments nil "LaTeX" org-export-with-LaTeX-fragments)))
@@ -3828,8 +3829,7 @@ formula file."
 ;;;; Export to OpenDocument Text
 ;;;; Export to OpenDocument Text
 
 
 ;;;###autoload
 ;;;###autoload
-(defun org-e-odt-export-to-odt
-  (&optional subtreep visible-only body-only ext-plist)
+(defun org-e-odt-export-to-odt (&optional async subtreep visible-only ext-plist)
   "Export current buffer to a HTML file.
   "Export current buffer to a HTML file.
 
 
 If narrowing is active in the current buffer, only export its
 If narrowing is active in the current buffer, only export its
@@ -3837,6 +3837,10 @@ narrowed part.
 
 
 If a region is active, export that region.
 If a region is active, export that region.
 
 
+A non-nil optional argument ASYNC means the process should happen
+asynchronously.  The resulting file should be accessible through
+the `org-export-stack' interface.
+
 When optional argument SUBTREEP is non-nil, export the sub-tree
 When optional argument SUBTREEP is non-nil, export the sub-tree
 at point, extracting information from the headline properties
 at point, extracting information from the headline properties
 first.
 first.
@@ -3844,31 +3848,52 @@ first.
 When optional argument VISIBLE-ONLY is non-nil, don't export
 When optional argument VISIBLE-ONLY is non-nil, don't export
 contents of hidden elements.
 contents of hidden elements.
 
 
-When optional argument BODY-ONLY is non-nil, only write code
-between \"\\begin{document}\" and \"\\end{document}\".
-
 EXT-PLIST, when provided, is a property list with external
 EXT-PLIST, when provided, is a property list with external
 parameters overriding Org default settings, but still inferior to
 parameters overriding Org default settings, but still inferior to
 file-local settings.
 file-local settings.
 
 
 Return output file's name."
 Return output file's name."
   (interactive)
   (interactive)
-  (org-e-odt--export-wrap
-   (org-export-output-file-name ".odt" subtreep)
-   (let* ((org-e-odt-embedded-images-count 0)
-	  (org-e-odt-embedded-formulas-count 0)
-	  (org-e-odt-automatic-styles nil)
-	  (org-e-odt-object-counters nil)
-	  ;; Let `htmlfontify' know that we are interested in collecting
-	  ;; styles.
-	  (hfy-user-sheet-assoc nil))
-     ;; Initialize content.xml and kick-off the export process.
-     (let ((out-buf (progn
-		      (require 'nxml-mode)
-		      (let ((nxml-auto-insert-xml-declaration-flag nil))
-			(find-file-noselect
-			 (concat org-e-odt-zip-dir "content.xml") t)))))
-       (org-export-to-buffer 'e-odt out-buf subtreep visible-only body-only)))))
+  (let ((outfile (org-export-output-file-name ".odt" subtreep)))
+    (if async
+	(org-export-async-start (lambda (f) (org-export-add-to-stack f 'e-odt))
+	  `(expand-file-name
+	    (org-e-odt--export-wrap
+	     ,outfile
+	     (let* ((org-e-odt-embedded-images-count 0)
+		    (org-e-odt-embedded-formulas-count 0)
+		    (org-e-odt-automatic-styles nil)
+		    (org-e-odt-object-counters nil)
+		    ;; Let `htmlfontify' know that we are interested in
+		    ;; collecting styles.
+		    (hfy-user-sheet-assoc nil))
+	       ;; Initialize content.xml and kick-off the export
+	       ;; process.
+	       (let ((out-buf
+		      (progn
+			(require 'nxml-mode)
+			(let ((nxml-auto-insert-xml-declaration-flag nil))
+			  (find-file-noselect
+			   (concat org-e-odt-zip-dir "content.xml") t)))))
+		 (org-export-to-buffer
+		  'e-odt out-buf ,subtreep ,visible-only nil ',ext-plist))))))
+      (org-e-odt--export-wrap
+       outfile
+       (let* ((org-e-odt-embedded-images-count 0)
+	      (org-e-odt-embedded-formulas-count 0)
+	      (org-e-odt-automatic-styles nil)
+	      (org-e-odt-object-counters nil)
+	      ;; Let `htmlfontify' know that we are interested in collecting
+	      ;; styles.
+	      (hfy-user-sheet-assoc nil))
+	 ;; Initialize content.xml and kick-off the export process.
+	 (let ((out-buf (progn
+			  (require 'nxml-mode)
+			  (let ((nxml-auto-insert-xml-declaration-flag nil))
+			    (find-file-noselect
+			     (concat org-e-odt-zip-dir "content.xml") t)))))
+	   (org-export-to-buffer
+	    'e-odt out-buf subtreep visible-only nil ext-plist)))))))
 
 
 
 
 ;;;; Convert between OpenDocument and other formats
 ;;;; Convert between OpenDocument and other formats

+ 55 - 35
contrib/lisp/org-e-publish.el

@@ -42,13 +42,9 @@
 (require 'format-spec)
 (require 'format-spec)
 (require 'org-export)
 (require 'org-export)
 
 
-(declare-function org-e-latex-compile "org-e-latex" (texfile))
-
 
 
 
 
 ;;; Variables
 ;;; Variables
-(defvar org-e-publish-initial-buffer nil
-  "The buffer `org-e-publish' has been called from.")
 
 
 (defvar org-e-publish-temp-files nil
 (defvar org-e-publish-temp-files nil
   "Temporary list of files to be published.")
   "Temporary list of files to be published.")
@@ -817,8 +813,15 @@ It returns time in `current-time' format."
 (defalias 'org-e-publish-project 'org-e-publish)
 (defalias 'org-e-publish-project 'org-e-publish)
 
 
 ;;;###autoload
 ;;;###autoload
-(defun org-e-publish (project &optional force)
-  "Publish PROJECT."
+(defun org-e-publish (project &optional force async)
+  "Publish PROJECT.
+
+PROJECT is either a project name, as a string, or a project
+alist (see `org-e-publish-project-alist' variable).
+
+When optional argument FORCE is non-nil, force publishing all
+files in PROJECT.  With a non-nil optional argument ASYNC,
+publishing will be done asynchronously, in another process."
   (interactive
   (interactive
    (list
    (list
     (assoc (org-icompleting-read
     (assoc (org-icompleting-read
@@ -826,52 +829,69 @@ It returns time in `current-time' format."
 	    org-e-publish-project-alist nil t)
 	    org-e-publish-project-alist nil t)
 	   org-e-publish-project-alist)
 	   org-e-publish-project-alist)
     current-prefix-arg))
     current-prefix-arg))
-  (setq org-e-publish-initial-buffer (current-buffer))
-  (save-window-excursion
-    (let* ((org-e-publish-use-timestamps-flag
-	    (if force nil org-e-publish-use-timestamps-flag)))
-      (org-e-publish-projects
-       (if (stringp project)
-	   ;; If this function is called in batch mode, project is
-	   ;; still a string here.
-	   (list (assoc project org-e-publish-project-alist))
-	 (list project))))))
+  (let ((project-alist  (if (not (stringp project)) (list project)
+			  ;; If this function is called in batch mode,
+			  ;; project is still a string here.
+			  (list (assoc project org-e-publish-project-alist)))))
+    (if async
+	(org-export-async-start 'ignore
+	  `(let ((org-e-publish-use-timestamps-flag
+		  (if ',force nil ,org-e-publish-use-timestamps-flag)))
+	     (org-e-publish-projects ',project-alist)))
+      (save-window-excursion
+	(let* ((org-e-publish-use-timestamps-flag
+		(if force nil org-e-publish-use-timestamps-flag)))
+	  (org-e-publish-projects project-alist))))))
 
 
 ;;;###autoload
 ;;;###autoload
-(defun org-e-publish-all (&optional force)
+(defun org-e-publish-all (&optional force async)
   "Publish all projects.
   "Publish all projects.
-With prefix argument, remove all files in the timestamp
-directory and force publishing all files."
+With prefix argument FORCE, remove all files in the timestamp
+directory and force publishing all projects.  With a non-nil
+optional argument ASYNC, publishing will be done asynchronously,
+in another process."
   (interactive "P")
   (interactive "P")
-  (when force (org-e-publish-remove-all-timestamps))
-  (save-window-excursion
-    (let ((org-e-publish-use-timestamps-flag
-	   (if force nil org-e-publish-use-timestamps-flag)))
-      (org-e-publish-projects org-e-publish-project-alist))))
+  (if async
+      (org-export-async-start 'ignore
+	`(when ',force (org-e-publish-remove-all-timestamps))
+	`(let ((org-e-publish-use-timestamps-flag
+		(if ',force nil ,org-e-publish-use-timestamps-flag)))
+	   (org-e-publish-projects ',org-e-publish-project-alist)))
+    (when force (org-e-publish-remove-all-timestamps))
+    (save-window-excursion
+      (let ((org-e-publish-use-timestamps-flag
+	     (if force nil org-e-publish-use-timestamps-flag)))
+	(org-e-publish-projects org-e-publish-project-alist)))))
 
 
 
 
 ;;;###autoload
 ;;;###autoload
-(defun org-e-publish-current-file (&optional force)
+(defun org-e-publish-current-file (&optional force async)
   "Publish the current file.
   "Publish the current file.
-With prefix argument, force publish the file."
+With prefix argument FORCE, force publish the file.  When
+optional argument ASYNC is non-nil, publishing will be done
+asynchronously, in another process."
   (interactive "P")
   (interactive "P")
-  (save-window-excursion
-    (let ((org-e-publish-use-timestamps-flag
-	   (if force nil org-e-publish-use-timestamps-flag)))
-      (org-e-publish-file (buffer-file-name (buffer-base-buffer))))))
+  (let ((file (buffer-file-name (buffer-base-buffer))))
+    (if async
+	(org-export-async-start 'ignore
+	  `(let ((org-e-publish-use-timestamps-flag
+		  (if ',force nil ,org-e-publish-use-timestamps-flag)))
+	     (org-e-publish-file ,file)))
+      (save-window-excursion
+	(let ((org-e-publish-use-timestamps-flag
+	       (if force nil org-e-publish-use-timestamps-flag)))
+	  (org-e-publish-file file))))))
 
 
 ;;;###autoload
 ;;;###autoload
-(defun org-e-publish-current-project (&optional force)
+(defun org-e-publish-current-project (&optional force async)
   "Publish the project associated with the current file.
   "Publish the project associated with the current file.
 With a prefix argument, force publishing of all files in
 With a prefix argument, force publishing of all files in
 the project."
 the project."
   (interactive "P")
   (interactive "P")
   (save-window-excursion
   (save-window-excursion
     (let ((project (org-e-publish-get-project-from-filename
     (let ((project (org-e-publish-get-project-from-filename
-		    (buffer-file-name (buffer-base-buffer)) 'up))
-	  (org-e-publish-use-timestamps-flag
-	   (if force nil org-e-publish-use-timestamps-flag)))
-      (if project (org-e-publish project)
+		    (buffer-file-name (buffer-base-buffer)) 'up)))
+      (if project (org-e-publish project force async)
 	(error "File %s is not part of any known project"
 	(error "File %s is not part of any known project"
 	       (buffer-file-name (buffer-base-buffer)))))))
 	       (buffer-file-name (buffer-base-buffer)))))))
 
 

+ 31 - 6
contrib/lisp/org-e-texinfo.el

@@ -1657,7 +1657,7 @@ contextual information."
 ;;; Interactive functions
 ;;; Interactive functions
 
 
 (defun org-e-texinfo-export-to-texinfo
 (defun org-e-texinfo-export-to-texinfo
-  (&optional subtreep visible-only body-only ext-plist)
+  (&optional async subtreep visible-only body-only ext-plist)
   "Export current buffer to a Texinfo file.
   "Export current buffer to a Texinfo file.
 
 
 If narrowing is active in the current buffer, only export its
 If narrowing is active in the current buffer, only export its
@@ -1665,6 +1665,10 @@ narrowed part.
 
 
 If a region is active, export that region.
 If a region is active, export that region.
 
 
+A non-nil optional argument ASYNC means the process should happen
+asynchronously.  The resulting file should be accessible through
+the `org-export-stack' interface.
+
 When optional argument SUBTREEP is non-nil, export the sub-tree
 When optional argument SUBTREEP is non-nil, export the sub-tree
 at point, extracting information from the headline properties
 at point, extracting information from the headline properties
 first.
 first.
@@ -1682,11 +1686,18 @@ file-local settings.
 Return output file's name."
 Return output file's name."
   (interactive)
   (interactive)
   (let ((outfile (org-export-output-file-name ".texi" subtreep)))
   (let ((outfile (org-export-output-file-name ".texi" subtreep)))
-    (org-export-to-file
-     'e-texinfo outfile subtreep visible-only body-only ext-plist)))
+    (if async
+	(org-export-async-start
+	    (lambda (f) (org-export-add-to-stack f 'e-texinfo))
+	  `(expand-file-name
+	    (org-export-to-file
+	     'e-texinfo ,outfile ,subtreep ,visible-only ,body-only
+	     ',ext-plist)))
+      (org-export-to-file
+       'e-texinfo outfile subtreep visible-only body-only ext-plist))))
 
 
 (defun org-e-texinfo-export-to-info
 (defun org-e-texinfo-export-to-info
-  (&optional subtreep visible-only body-only ext-plist)
+  (&optional async subtreep visible-only body-only ext-plist)
   "Export current buffer to Texinfo then process through to INFO.
   "Export current buffer to Texinfo then process through to INFO.
 
 
 If narrowing is active in the current buffer, only export its
 If narrowing is active in the current buffer, only export its
@@ -1694,6 +1705,10 @@ narrowed part.
 
 
 If a region is active, export that region.
 If a region is active, export that region.
 
 
+A non-nil optional argument ASYNC means the process should happen
+asynchronously.  The resulting file should be accessible through
+the `org-export-stack' interface.
+
 When optional argument SUBTREEP is non-nil, export the sub-tree
 When optional argument SUBTREEP is non-nil, export the sub-tree
 at point, extracting information from the headline properties
 at point, extracting information from the headline properties
 first.
 first.
@@ -1713,8 +1728,18 @@ directory.
 
 
 Return INFO file's name."
 Return INFO file's name."
   (interactive)
   (interactive)
-  (org-e-texinfo-compile
-   (org-e-texinfo-export-to-texinfo subtreep visible-only body-only ext-plist)))
+  (if async
+      (let ((outfile (org-export-output-file-name ".texi" subtreep)))
+	(org-export-async-start
+	    (lambda (f) (org-export-add-to-stack f 'e-texinfo))
+	  `(expand-file-name
+	    (org-e-texinfo-compile
+	     (org-export-to-file
+	      'e-texinfo ,outfile ,subtreep ,visible-only ,body-only
+	      ',ext-plist)))))
+    (org-e-texinfo-compile
+     (org-e-texinfo-export-to-texinfo
+      nil subtreep visible-only body-only ext-plist))))
 
 
 (defun org-e-texinfo-compile (file)
 (defun org-e-texinfo-compile (file)
   "Compile a texinfo file.
   "Compile a texinfo file.

+ 451 - 79
contrib/lisp/org-export.el

@@ -65,8 +65,14 @@
 ;; customizable should belong to the `org-export-BACKEND' group.
 ;; customizable should belong to the `org-export-BACKEND' group.
 ;;
 ;;
 ;; Tools for common tasks across back-ends are implemented in the
 ;; Tools for common tasks across back-ends are implemented in the
-;; penultimate part of this file.  A dispatcher for standard back-ends
-;; is provided in the last one.
+;; following part of then file.
+;;
+;; Then, a wrapper macro for asynchronous export,
+;; `org-export-async-start', along with tools to display results. are
+;; given in the penultimate part.
+;;
+;; Eventually, a dispatcher (`org-export-dispatch') for standard
+;; back-ends is provided in the last one.
 
 
 ;;; Code:
 ;;; Code:
 
 
@@ -74,11 +80,12 @@
 (require 'org-element)
 (require 'org-element)
 (require 'ob-exp)
 (require 'ob-exp)
 
 
-(declare-function org-e-publish "org-e-publish" (project &optional force))
-(declare-function org-e-publish-all "org-e-publish" (&optional force))
-(declare-function org-e-publish-current-file "org-e-publish" (&optional force))
+(declare-function org-e-publish "org-e-publish" (project &optional force async))
+(declare-function org-e-publish-all "org-e-publish" (&optional force async))
+(declare-function
+ org-e-publish-current-file "org-e-publish" (&optional force async))
 (declare-function org-e-publish-current-project "org-e-publish"
 (declare-function org-e-publish-current-project "org-e-publish"
-		  (&optional force))
+		  (&optional force async))
 
 
 (defvar org-e-publish-project-alist)
 (defvar org-e-publish-project-alist)
 (defvar org-table-number-fraction)
 (defvar org-table-number-fraction)
@@ -251,6 +258,25 @@ whose extension is either \"png\", \"jpeg\", \"jpg\", \"gif\",
 See `org-export-inline-image-p' for more information about
 See `org-export-inline-image-p' for more information about
 rules.")
 rules.")
 
 
+(defvar org-export-async-debug nil
+  "Non-nil means asynchronous export process should leave data behind.
+
+This data is found in the appropriate \"*Org Export Process*\"
+buffer, and in files prefixed with \"org-export-process\" and
+located in `temporary-file-directory'.
+
+When non-nil, it will also set `debug-on-error' to a non-nil
+value in the external process.")
+
+(defvar org-export-stack-contents nil
+  "Record asynchronously generated export results and processes.
+This is an alist: its CAR is the source of the
+result (destination file or buffer for a finished process,
+original buffer for a running one) and its CDR is a list
+containing the back-end used, as a symbol, and either a process
+or the time at which it finished.  It is used to build the menu
+from `org-export-stack'.")
+
 (defvar org-export-registered-backends nil
 (defvar org-export-registered-backends nil
   "List of backends currently available in the exporter.
   "List of backends currently available in the exporter.
 
 
@@ -703,6 +729,21 @@ these cases."
   :group 'org-export-general
   :group 'org-export-general
   :type 'boolean)
   :type 'boolean)
 
 
+(defcustom org-export-in-background nil
+  "Non-nil means export and publishing commands will run in background.
+Results from an asynchronous export are never displayed.  You can
+retrieve them with \\[org-export-stack]."
+  :group 'org-export-general
+  :type 'boolean)
+
+(defcustom org-export-async-init-file user-init-file
+  "File used to initialize external export process.
+Value must be an absolute file name.  It defaults to user's
+initialization file.  Though, a specific configuration makes the
+process faster and the export more portable."
+  :group 'org-export-general
+  :type '(file :must-match t))
+
 (defcustom org-export-dispatch-use-expert-ui nil
 (defcustom org-export-dispatch-use-expert-ui nil
   "Non-nil means using a non-intrusive `org-export-dispatch'.
   "Non-nil means using a non-intrusive `org-export-dispatch'.
 In that case, no help buffer is displayed.  Though, an indicator
 In that case, no help buffer is displayed.  Though, an indicator
@@ -811,9 +852,10 @@ keywords are understood:
 
 
       ACTION-OR-MENU is either a function or an alist.
       ACTION-OR-MENU is either a function or an alist.
 
 
-      If it is an action, it will be called with three arguments:
-      SUBTREEP, VISIBLE-ONLY and BODY-ONLY.  See `org-export-as'
-      for further explanations.
+      If it is an action, it will be called with four
+      arguments (booleans): ASYNC, SUBTREEP, VISIBLE-ONLY and
+      BODY-ONLY.  See `org-export-as' for further explanations on
+      some of them.
 
 
       If it is an alist, associations should follow the
       If it is an alist, associations should follow the
       pattern:
       pattern:
@@ -1910,15 +1952,13 @@ Return transcoded string."
 	      (cond
 	      (cond
 	       ;; Ignored element/object.
 	       ;; Ignored element/object.
 	       ((memq data (plist-get info :ignore-list)) nil)
 	       ((memq data (plist-get info :ignore-list)) nil)
-	       ;; Plain text.  All residual text properties from parse
-	       ;; tree (i.e. `:parent' property) are removed.
+	       ;; Plain text.
 	       ((eq type 'plain-text)
 	       ((eq type 'plain-text)
-		(org-no-properties
-		 (org-export-filter-apply-functions
-		  (plist-get info :filter-plain-text)
-		  (let ((transcoder (org-export-transcoder data info)))
-		    (if transcoder (funcall transcoder data info) data))
-		  info)))
+		(org-export-filter-apply-functions
+		 (plist-get info :filter-plain-text)
+		 (let ((transcoder (org-export-transcoder data info)))
+		   (if transcoder (funcall transcoder data info) data))
+		 info))
 	       ;; Uninterpreted element/object: change it back to Org
 	       ;; Uninterpreted element/object: change it back to Org
 	       ;; syntax and export again resulting raw string.
 	       ;; syntax and export again resulting raw string.
 	       ((not (org-export--interpret-p data info))
 	       ((not (org-export--interpret-p data info))
@@ -2533,7 +2573,7 @@ Return the updated communication channel."
 ;; but a copy of it (with the same buffer-local variables and
 ;; but a copy of it (with the same buffer-local variables and
 ;; visibility), where macros and include keywords are expanded and
 ;; visibility), where macros and include keywords are expanded and
 ;; Babel blocks are executed, if appropriate.
 ;; Babel blocks are executed, if appropriate.
-;; `org-export-with-current-buffer-copy' macro prepares that copy.
+;; `org-export-with-buffer-copy' macro prepares that copy.
 ;;
 ;;
 ;; File inclusion is taken care of by
 ;; File inclusion is taken care of by
 ;; `org-export-expand-include-keyword' and
 ;; `org-export-expand-include-keyword' and
@@ -2588,7 +2628,7 @@ Return code as a string."
       ;; Initialize communication channel with original buffer
       ;; Initialize communication channel with original buffer
       ;; attributes, unavailable in its copy.
       ;; attributes, unavailable in its copy.
       (let ((info (org-export--get-buffer-attributes)) tree)
       (let ((info (org-export--get-buffer-attributes)) tree)
-	(org-export-with-current-buffer-copy
+	(org-export-with-buffer-copy
 	 ;; Run first hook with current back-end as argument.
 	 ;; Run first hook with current back-end as argument.
 	 (run-hook-with-args 'org-export-before-processing-hook backend)
 	 (run-hook-with-args 'org-export-before-processing-hook backend)
 	 ;; Update communication channel and get parse tree.  Buffer
 	 ;; Update communication channel and get parse tree.  Buffer
@@ -2645,11 +2685,14 @@ Return code as a string."
 		      (or (org-export-data tree info) "")))
 		      (or (org-export-data tree info) "")))
 	       (template (cdr (assq 'template
 	       (template (cdr (assq 'template
 				    (plist-get info :translate-alist))))
 				    (plist-get info :translate-alist))))
-	       (output (org-export-filter-apply-functions
-			(plist-get info :filter-final-output)
-			(if (or (not (functionp template)) body-only) body
-			  (funcall template body info))
-			info)))
+	       ;; Remove all text properties since they cannot be
+	       ;; retrieved from an external process.
+	       (output (org-no-properties
+			(org-export-filter-apply-functions
+			 (plist-get info :filter-final-output)
+			 (if (or (not (functionp template)) body-only) body
+			   (funcall template body info))
+			 info))))
 	  ;; Maybe add final OUTPUT to kill ring, then return it.
 	  ;; Maybe add final OUTPUT to kill ring, then return it.
 	  (when (and org-export-copy-to-kill-ring (org-string-nw-p output))
 	  (when (and org-export-copy-to-kill-ring (org-string-nw-p output))
 	    (org-kill-new output))
 	    (org-kill-new output))
@@ -2752,32 +2795,94 @@ determined."
      ((file-name-absolute-p base-name) (concat base-name extension))
      ((file-name-absolute-p base-name) (concat base-name extension))
      (t (concat (file-name-as-directory ".") base-name extension)))))
      (t (concat (file-name-as-directory ".") base-name extension)))))
 
 
-(defmacro org-export-with-current-buffer-copy (&rest body)
+(defun org-export-copy-buffer ()
+  "Return a copy of the current buffer.
+The copy preserves Org buffer-local variables, visibility and
+narrowing."
+  (let ((copy-buffer-fun (org-export--generate-copy-script (current-buffer)))
+	(new-buf (generate-new-buffer (buffer-name))))
+    (with-current-buffer new-buf
+      (funcall copy-buffer-fun)
+      (set-buffer-modified-p nil))
+    new-buf))
+
+(defmacro org-export-with-buffer-copy (&rest body)
   "Apply BODY in a copy of the current buffer.
   "Apply BODY in a copy of the current buffer.
-
-The copy preserves local variables and visibility of the original
-buffer.
-
-Point is at buffer's beginning when BODY is applied."
-  (declare (debug (body)))
-  (org-with-gensyms (original-buffer offset buffer-string overlays region)
-    `(let* ((,original-buffer (current-buffer))
-	    (,region (list (point-min) (point-max)))
-	    (,buffer-string (org-with-wide-buffer (buffer-string)))
-	    (,overlays (mapcar 'copy-overlay (apply 'overlays-in ,region))))
-       (with-temp-buffer
-	 (let ((buffer-invisibility-spec nil))
-	   (org-clone-local-variables
-	    ,original-buffer
-	    "^\\(org-\\|orgtbl-\\|major-mode$\\|outline-\\(regexp\\|level\\)$\\)")
-	   (insert ,buffer-string)
-	   (apply 'narrow-to-region ,region)
-	   (mapc (lambda (ov)
-		   (move-overlay
-		    ov (overlay-start ov) (overlay-end ov) (current-buffer)))
-		 ,overlays)
-	   (goto-char (point-min))
-	   (progn ,@body))))))
+The copy preserves local variables, visibility and contents of
+the original buffer.  Point is at the beginning of the buffer
+when BODY is applied."
+  (declare (debug t))
+  (org-with-gensyms (buf-copy)
+    `(let ((,buf-copy (org-export-copy-buffer)))
+       (unwind-protect
+	   (with-current-buffer ,buf-copy
+	     (goto-char (point-min))
+	     (progn ,@body))
+	 (and (buffer-live-p ,buf-copy)
+	      ;; Kill copy without confirmation.
+	      (progn (with-current-buffer ,buf-copy
+		       (restore-buffer-modified-p nil))
+		     (kill-buffer ,buf-copy)))))))
+
+(defun org-export--generate-copy-script (buffer)
+  "Generate a function duplicating BUFFER.
+
+The copy will preserve local variables, visibility, contents and
+narrowing of the original buffer.  If a region was active in
+BUFFER, contents will be narrowed to that region instead.
+
+The resulting function can be eval'ed at a later time, from
+another buffer, effectively cloning the original buffer there."
+  (with-current-buffer buffer
+    `(lambda ()
+       (let ((inhibit-modification-hooks t))
+	 ;; Buffer local variables.
+	 ,@(let (local-vars)
+	     (mapc
+	      (lambda (entry)
+		(when (consp entry)
+		  (let ((var (car entry))
+			(val (cdr entry)))
+		    (and (not (eq var 'org-font-lock-keywords))
+			 (or (memq var
+				   '(major-mode default-directory
+						buffer-file-name outline-level
+						outline-regexp
+						buffer-invisibility-spec))
+			     (string-match "^\\(org-\\|orgtbl-\\)"
+					   (symbol-name var)))
+			 ;; Skip unreadable values, as they cannot be
+			 ;; sent to external process.
+			 (or (not val) (ignore-errors (read (format "%S" val))))
+			 (push `(set (make-local-variable (quote ,var))
+				     (quote ,val))
+			       local-vars)))))
+	      (buffer-local-variables (buffer-base-buffer)))
+	     local-vars)
+	 ;; Whole buffer contents.
+	 (insert
+	  ,(org-with-wide-buffer
+	    (buffer-substring-no-properties
+	     (point-min) (point-max))))
+	 ;; Narrowing.
+	 ,(if (org-region-active-p)
+	      `(narrow-to-region ,(region-beginning) ,(region-end))
+	    `(narrow-to-region ,(point-min) ,(point-max)))
+	 ;; Current position of point.
+	 (goto-char ,(point))
+	 ;; Overlays with invisible property.
+	 ,@(let (ov-set)
+	     (mapc
+	      (lambda (ov)
+		(let ((invis-prop (overlay-get ov 'invisible)))
+		  (when invis-prop
+		    (push `(overlay-put
+			    (make-overlay ,(overlay-start ov)
+					  ,(overlay-end ov))
+			    'invisible (quote ,invis-prop))
+			  ov-set))))
+	      (overlays-in (point-min) (point-max)))
+	     ov-set)))))
 
 
 (defun org-export-expand-include-keyword (&optional included dir)
 (defun org-export-expand-include-keyword (&optional included dir)
   "Expand every include keyword in buffer.
   "Expand every include keyword in buffer.
@@ -2935,7 +3040,7 @@ This function will return an error if the current buffer is
 visiting a file."
 visiting a file."
   ;; Get a pristine copy of current buffer so Babel references can be
   ;; Get a pristine copy of current buffer so Babel references can be
   ;; properly resolved.
   ;; properly resolved.
-  (let* (clone-buffer-hook (reference (clone-buffer)))
+  (let ((reference (org-export-copy-buffer)))
     (unwind-protect (let ((org-current-export-file reference))
     (unwind-protect (let ((org-current-export-file reference))
 		      (org-export-blocks-preprocess))
 		      (org-export-blocks-preprocess))
       (kill-buffer reference))))
       (kill-buffer reference))))
@@ -4854,6 +4959,253 @@ to `:default' encoding. If it fails, return S."
 	s)))
 	s)))
 
 
 
 
+
+;;; Asynchronous Export
+;;
+;; `org-export-async-start' is the entry point for asynchronous
+;; export.  It recreates current buffer (including visibility,
+;; narrowing and visited file) in an external Emacs process, and
+;; evaluates a command there.  It then applies a function on the
+;; returned results in the current process.
+;;
+;; Asynchronously generated results are never displayed directly.
+;; Instead, they are stored in `org-export-stack-contents'.  They can
+;; then be retrieved by calling `org-export-stack'.
+;;
+;; Export Stack is viewed through a dedicated major mode
+;;`org-export-stack-mode' and tools: `org-export--stack-refresh',
+;;`org-export--stack-delete', `org-export--stack-view' and
+;;`org-export--stack-clear'.
+;;
+;; For back-ends, `org-export-add-to-stack' add a new source to stack.
+;; It should used whenever `org-export-async-start' is called.
+
+(defmacro org-export-async-start  (fun &rest body)
+  "Call function FUN on the results returned by BODY evaluation.
+
+BODY evaluation happens in an asynchronous process, from a buffer
+which is an exact copy of the current one.
+
+Use `org-export-add-to-stack' in FUN in order to register results
+in the stack.  Examples for, respectively a temporary buffer and
+a file are:
+
+  \(org-export-async-start
+      \(lambda (output)
+        \(with-current-buffer (get-buffer-create \"*Org BACKEND Export*\")
+        \(erase-buffer)
+        \(insert output)
+        \(goto-char (point-min))
+        \(org-export-add-to-stack (current-buffer) 'backend)))
+    `(org-export-as 'backend ,subtreep ,visible-only ,body-only ',ext-plist))
+
+and
+
+  \(org-export-async-start
+      \(lambda (f) (org-export-add-to-stack f 'backend))
+    `(expand-file-name
+      \(org-export-to-file
+       'backend ,outfile ,subtreep ,visible-only ,body-only ',ext-plist)))"
+  (declare (indent 1) (debug t))
+  (org-with-gensyms (process temp-file copy-fun proc-buffer handler)
+    ;; Write the full sexp evaluating BODY in a copy of the current
+    ;; buffer to a temporary file, as it may be too long for program
+    ;; args in `start-process'.
+    `(with-temp-message "Initializing asynchronous export process"
+       (let ((,copy-fun (org-export--generate-copy-script (current-buffer)))
+	     (,temp-file (make-temp-file "org-export-process")))
+	 (with-temp-file ,temp-file
+	   (insert
+	    (format
+	     "%S"
+	     `(with-temp-buffer
+		,(when org-export-async-debug '(setq debug-on-error t))
+		;; Initialize `org-mode' in the external process.
+		(org-mode)
+		;; Re-create current buffer there.
+		(funcall ,,copy-fun)
+		(restore-buffer-modified-p nil)
+		;; Sexp to evaluate in the buffer.
+		(print (progn ,,@body))))))
+	 ;; Start external process.
+	 (let* ((process-connection-type nil)
+		(,proc-buffer (generate-new-buffer-name "*Org Export Process*"))
+		(,process
+		 (start-process
+		  "org-export-process" ,proc-buffer
+		  (expand-file-name invocation-name invocation-directory)
+		  "-Q" "--batch"
+		  "-l" org-export-async-init-file
+		  "-l" ,temp-file)))
+	   ;; Register running process in stack.
+	   (org-export-add-to-stack (get-buffer ,proc-buffer) nil ,process)
+	   ;; Set-up sentinel in order to catch results.
+	   (set-process-sentinel
+	    ,process
+	    (let ((handler #',fun))
+	      `(lambda (p status)
+		 (let ((proc-buffer (process-buffer p)))
+		   (when (eq (process-status p) 'exit)
+		     (unwind-protect
+			 (if (zerop (process-exit-status p))
+			     (unwind-protect
+				 (let ((results
+					(with-current-buffer proc-buffer
+					  (goto-char (point-max))
+					  (backward-sexp)
+					  (read (current-buffer)))))
+				   (funcall ,handler results))
+			       (unless org-export-async-debug
+				 (and (get-buffer proc-buffer)
+				      (kill-buffer proc-buffer))))
+			   (org-export-add-to-stack proc-buffer nil p)
+			   (ding)
+			   (message "Process '%s' exited abnormally" p))
+		       (unless org-export-async-debug
+			 (delete-file ,,temp-file)))))))))))))
+
+(defun org-export-add-to-stack (source backend &optional process)
+  "Add a new result to export stack if not present already.
+
+SOURCE is a buffer or a file name containing export results.
+BACKEND is a symbol representing export back-end used to generate
+it.
+
+Entries already pointing to SOURCE and unavailable entries are
+removed beforehand.  Return the new stack."
+  (setq org-export-stack-contents
+	(cons (list source backend (or process (current-time)))
+	      (org-export--stack-remove source))))
+
+(defun org-export-stack ()
+  "Menu for asynchronous export results and running processes."
+  (interactive)
+  (let ((buffer (get-buffer-create "*Org Export Stack*")))
+    (set-buffer buffer)
+    (when (zerop (buffer-size)) (org-export-stack-mode))
+    (org-export--stack-refresh)
+    (pop-to-buffer buffer))
+  (message "Type \"q\" to quit, \"?\" for help"))
+
+(defun org-export--stack-source-at-point ()
+  "Return source from export results at point in stack."
+  (let ((source (car (nth (1- (org-current-line)) org-export-stack-contents))))
+    (if (not source) (error "Source unavailable, please refresh buffer")
+      (let ((source-name (if (stringp source) source (buffer-name source))))
+	(if (save-excursion
+	      (beginning-of-line)
+	      (looking-at (concat ".* +" (regexp-quote source-name) "$")))
+	    source
+	  ;; SOURCE is not consistent with current line.  The stack
+	  ;; view is outdated.
+	  (error "Source unavailable; type `g' to update buffer"))))))
+
+(defun org-export--stack-clear ()
+  "Remove all entries from export stack."
+  (interactive)
+  (setq org-export-stack-contents nil))
+
+(defun org-export--stack-refresh (&rest dummy)
+  "Refresh the asynchronous export stack.
+DUMMY is ignored.  Unavailable sources are removed from the list.
+Return the new stack."
+  (let ((inhibit-read-only t))
+    (org-preserve-lc
+     (erase-buffer)
+     (insert (concat
+	      (let ((counter 0))
+		(mapconcat
+		 (lambda (entry)
+		   (let ((proc-p (processp (nth 2 entry))))
+		     (concat
+		      ;; Back-end.
+		      (format " %-12s  " (or (nth 1 entry) ""))
+		      ;; Age.
+		      (let ((data (nth 2 entry)))
+			(if proc-p (format " %6s  " (process-status data))
+			  ;; Compute age of the results.
+			  (org-format-seconds
+			   "%4h:%.2m  "
+			   (float-time (time-since data)))))
+		      ;; Source.
+		      (format " %s"
+			      (let ((source (car entry)))
+				(if (stringp source) source
+				  (buffer-name source)))))))
+		 ;; Clear stack from exited processes, dead buffers or
+		 ;; non-existent files.
+		 (setq org-export-stack-contents
+		       (org-remove-if-not
+			(lambda (el)
+			  (if (processp (nth 2 el))
+			      (buffer-live-p (process-buffer (nth 2 el)))
+			    (let ((source (car el)))
+			      (if (bufferp source) (buffer-live-p source)
+				(file-exists-p source)))))
+			org-export-stack-contents)) "\n")))))))
+
+(defun org-export--stack-remove (&optional source)
+  "Remove export results at point from stack.
+If optional argument SOURCE is non-nil, remove it instead."
+  (interactive)
+  (let ((source (or source (org-export--stack-source-at-point))))
+    (setq org-export-stack-contents
+	  (org-remove-if (lambda (el) (equal (car el) source))
+			 org-export-stack-contents))))
+
+(defun org-export--stack-view ()
+  "View export results at point in stack."
+  (interactive)
+  (let ((source (org-export--stack-source-at-point)))
+    (cond ((processp source)
+	   (org-switch-to-buffer-other-window (process-buffer source)))
+	  ((bufferp source) (org-switch-to-buffer-other-window source))
+	  (t (org-open-file source)))))
+
+(defconst org-export-stack-mode-map
+  (let ((km (make-sparse-keymap)))
+    (define-key km " " 'next-line)
+    (define-key km "n" 'next-line)
+    (define-key km "\C-n" 'next-line)
+    (define-key km [down] 'next-line)
+    (define-key km "p" 'previous-line)
+    (define-key km "\C-p" 'previous-line)
+    (define-key km "\C-?" 'previous-line)
+    (define-key km [up] 'previous-line)
+    (define-key km "C" 'org-export--stack-clear)
+    (define-key km "v" 'org-export--stack-view)
+    (define-key km (kbd "RET") 'org-export--stack-view)
+    (define-key km "d" 'org-export--stack-remove)
+    km)
+  "Keymap for Org Export Stack.")
+
+(define-derived-mode org-export-stack-mode special-mode "Org-Stack"
+  "Mode for displaying asynchronous export stack.
+
+Type \\[org-export-stack] to visualize the asynchronous export
+stack.
+
+In an Org Export Stack buffer, use \\[org-export--stack-view] to view export output
+on current line, \\[org-export--stack-remove] to remove it from the stack and \\[org-export--stack-clear] to clear 
+stack completely.
+
+Removal entries in an Org Export Stack buffer doesn't affect
+files or buffers, only view in the stack.
+
+\\{org-export-stack-mode-map}"
+  (abbrev-mode 0)
+  (auto-fill-mode 0)
+  (setq buffer-read-only t
+	buffer-undo-list t
+	truncate-lines t
+	header-line-format
+	'(:eval
+	  (format "  %-12s | %6s | %s" "Back-End" "Age" "Source")))
+  (add-hook 'post-command-hook 'org-export--stack-refresh nil t)
+  (set (make-local-variable 'revert-buffer-function)
+       'org-export--stack-refresh))
+
+
 
 
 ;;; The Dispatcher
 ;;; The Dispatcher
 ;;
 ;;
@@ -4874,38 +5226,49 @@ to switch to one or the other.
 
 
 When called with C-u prefix ARG, repeat the last export action,
 When called with C-u prefix ARG, repeat the last export action,
 with the same set of options used back then, on the current
 with the same set of options used back then, on the current
-buffer."
+buffer.
+
+When called with a double universal argument, display the
+asynchronous export stack directly."
   (interactive "P")
   (interactive "P")
-  (let* ((input (or (and arg org-export-dispatch-last-action)
-		    (save-window-excursion
-		      (unwind-protect
-			  ;; Store this export command.
-			  (setq org-export-dispatch-last-action
-				(org-export-dispatch-ui
-				 (list org-export-initial-scope)
-				 nil
-				 org-export-dispatch-use-expert-ui))
-			(and (get-buffer "*Org Export Dispatcher*")
-			     (kill-buffer "*Org Export Dispatcher*"))))))
+  (let* ((input
+	  (cond ((equal arg '(16)) '(stack))
+		((and arg org-export-dispatch-last-action))
+		(t (save-window-excursion
+		     (unwind-protect
+			 ;; Store this export command.
+			 (setq org-export-dispatch-last-action
+			       (org-export-dispatch-ui
+				(list org-export-initial-scope
+				      (and org-export-in-background 'async))
+				nil
+				org-export-dispatch-use-expert-ui))
+		       (and (get-buffer "*Org Export Dispatcher*")
+			    (kill-buffer "*Org Export Dispatcher*")))))))
 	 (action (car input))
 	 (action (car input))
 	 (optns (cdr input)))
 	 (optns (cdr input)))
     (case action
     (case action
       ;; First handle special hard-coded actions.
       ;; First handle special hard-coded actions.
-      (publish-current-file (org-e-publish-current-file (memq 'force optns)))
+      (stack (org-export-stack))
+      (publish-current-file
+       (org-e-publish-current-file (memq 'force optns) (memq 'async optns)))
       (publish-current-project
       (publish-current-project
-       (org-e-publish-current-project (memq 'force optns)))
+       (org-e-publish-current-project (memq 'force optns) (memq 'async optns)))
       (publish-choose-project
       (publish-choose-project
        (org-e-publish (assoc (org-icompleting-read
        (org-e-publish (assoc (org-icompleting-read
 			      "Publish project: "
 			      "Publish project: "
 			      org-e-publish-project-alist nil t)
 			      org-e-publish-project-alist nil t)
 			     org-e-publish-project-alist)
 			     org-e-publish-project-alist)
-		      (memq 'force optns)))
-      (publish-all (org-e-publish-all (memq 'force optns)))
-      (otherwise
-       (funcall action
-		(memq 'subtree optns)
-		(memq 'visible optns)
-		(memq 'body optns))))))
+		      (memq 'force optns)
+		      (memq 'async optns)))
+      (publish-all (org-e-publish-all (memq 'force optns) (memq 'async optns)))
+      (otherwise (funcall action
+			  ;; Return a symbol instead of a list to ease
+			  ;; asynchronous export macro use.
+			  (and (memq 'async optns) t)
+			  (and (memq 'subtree optns) t)
+			  (and (memq 'visible optns) t)
+			  (and (memq 'body optns) t))))))
 
 
 (defun org-export-dispatch-ui (options first-key expertp)
 (defun org-export-dispatch-ui (options first-key expertp)
   "Handle interface for `org-export-dispatch'.
   "Handle interface for `org-export-dispatch'.
@@ -4916,6 +5279,7 @@ export.  It can contain any of the following symbols:
 `subtree' restricts export to current subtree
 `subtree' restricts export to current subtree
 `visible' restricts export to visible part of buffer.
 `visible' restricts export to visible part of buffer.
 `force'   force publishing files.
 `force'   force publishing files.
+`async'   use asynchronous export process
 
 
 FIRST-KEY is the key pressed to select the first level menu.  It
 FIRST-KEY is the key pressed to select the first level menu.  It
 is nil when this menu hasn't been selected yet.
 is nil when this menu hasn't been selected yet.
@@ -4951,10 +5315,10 @@ back to standard interface."
 			       ((numberp key-b) t)))))
 			       ((numberp key-b) t)))))
 		    (lambda (a b) (< (car a) (car b)))))
 		    (lambda (a b) (< (car a) (car b)))))
 	 ;; Compute a list of allowed keys based on the first key
 	 ;; Compute a list of allowed keys based on the first key
-	 ;; pressed, if any.  Some keys (?1, ?2, ?3, ?4 and ?q) are
-	 ;; always available.
+	 ;; pressed, if any.  Some keys (?1, ?2, ?3, ?4, ?5 and ?q)
+	 ;; are always available.
 	 (allowed-keys
 	 (allowed-keys
-	  (nconc (list ?1 ?2 ?3 ?4)
+	  (nconc (list ?1 ?2 ?3 ?4 ?5)
 		 (if (not first-key) (org-uniquify (mapcar 'car backends))
 		 (if (not first-key) (org-uniquify (mapcar 'car backends))
 		   (let (sub-menu)
 		   (let (sub-menu)
 		     (dolist (backend backends (sort (mapcar 'car sub-menu) '<))
 		     (dolist (backend backends (sort (mapcar 'car sub-menu) '<))
@@ -4962,6 +5326,7 @@ back to standard interface."
 			 (setq sub-menu (append (nth 2 backend) sub-menu))))))
 			 (setq sub-menu (append (nth 2 backend) sub-menu))))))
 		 (cond ((eq first-key ?P) (list ?f ?p ?x ?a))
 		 (cond ((eq first-key ?P) (list ?f ?p ?x ?a))
 		       ((not first-key) (list ?P)))
 		       ((not first-key) (list ?P)))
+		 (list ?&)
 		 (when expertp (list ??))
 		 (when expertp (list ??))
 		 (list ?q)))
 		 (list ?q)))
 	 ;; Build the help menu for standard UI.
 	 ;; Build the help menu for standard UI.
@@ -4971,7 +5336,8 @@ back to standard interface."
 	     ;; Options are hard-coded.
 	     ;; Options are hard-coded.
 	     (format "Options
 	     (format "Options
     [%s] Body only:    %s       [%s] Visible only:     %s
     [%s] Body only:    %s       [%s] Visible only:     %s
-    [%s] Export scope: %s   [%s] Force publishing: %s\n"
+    [%s] Export scope: %s   [%s] Force publishing: %s
+    [%s] Asynchronous export: %s\n"
 		     (funcall fontify-key "1" t)
 		     (funcall fontify-key "1" t)
 		     (if (memq 'body options) "On " "Off")
 		     (if (memq 'body options) "On " "Off")
 		     (funcall fontify-key "2" t)
 		     (funcall fontify-key "2" t)
@@ -4979,7 +5345,9 @@ back to standard interface."
 		     (funcall fontify-key "3" t)
 		     (funcall fontify-key "3" t)
 		     (if (memq 'subtree options) "Subtree" "Buffer ")
 		     (if (memq 'subtree options) "Subtree" "Buffer ")
 		     (funcall fontify-key "4" t)
 		     (funcall fontify-key "4" t)
-		     (if (memq 'force options) "On " "Off"))
+		     (if (memq 'force options) "On " "Off")
+		     (funcall fontify-key "5" t)
+		     (if (memq 'async options) "On " "Off"))
 	     ;; Display registered back-end entries.  When a key
 	     ;; Display registered back-end entries.  When a key
 	     ;; appears for the second time, do not create another
 	     ;; appears for the second time, do not create another
 	     ;; entry, but append its sub-menu to existing menu.
 	     ;; entry, but append its sub-menu to existing menu.
@@ -5020,6 +5388,7 @@ back to standard interface."
 		     (funcall fontify-key "p" ?P)
 		     (funcall fontify-key "p" ?P)
 		     (funcall fontify-key "x" ?P)
 		     (funcall fontify-key "x" ?P)
 		     (funcall fontify-key "a" ?P))
 		     (funcall fontify-key "a" ?P))
+	     (format "\[%s] Export stack\n" (funcall fontify-key "&" t))
 	     (format "\[%s] %s"
 	     (format "\[%s] %s"
 		     (funcall fontify-key "q" t)
 		     (funcall fontify-key "q" t)
 		     (if first-key "Main menu" "Exit")))))
 		     (if first-key "Main menu" "Exit")))))
@@ -5028,11 +5397,12 @@ back to standard interface."
 	 (expert-prompt
 	 (expert-prompt
 	  (when expertp
 	  (when expertp
 	    (format
 	    (format
-	     "Export command (Options: %s%s%s%s) [%s]: "
+	     "Export command (Options: %s%s%s%s%s) [%s]: "
 	     (if (memq 'body options) (funcall fontify-key "b" t) "-")
 	     (if (memq 'body options) (funcall fontify-key "b" t) "-")
 	     (if (memq 'visible options) (funcall fontify-key "v" t) "-")
 	     (if (memq 'visible options) (funcall fontify-key "v" t) "-")
 	     (if (memq 'subtree options) (funcall fontify-key "s" t) "-")
 	     (if (memq 'subtree options) (funcall fontify-key "s" t) "-")
 	     (if (memq 'force options) (funcall fontify-key "f" t) "-")
 	     (if (memq 'force options) (funcall fontify-key "f" t) "-")
+	     (if (memq 'async options) (funcall fontify-key "a" t) "-")
 	     (concat allowed-keys)))))
 	     (concat allowed-keys)))))
     ;; With expert UI, just read key with a fancy prompt.  In standard
     ;; With expert UI, just read key with a fancy prompt.  In standard
     ;; UI, display an intrusive help buffer.
     ;; UI, display an intrusive help buffer.
@@ -5085,11 +5455,13 @@ options as CDR."
      ;; Help key: Switch back to standard interface if
      ;; Help key: Switch back to standard interface if
      ;; expert UI was active.
      ;; expert UI was active.
      ((eq key ??) (org-export-dispatch-ui options first-key nil))
      ((eq key ??) (org-export-dispatch-ui options first-key nil))
+     ;; Switch to asynchronous export stack.
+     ((eq key ?&) '(stack))
      ;; Toggle export options.
      ;; Toggle export options.
-     ((memq key '(?1 ?2 ?3 ?4))
+     ((memq key '(?1 ?2 ?3 ?4 ?5))
       (org-export-dispatch-ui
       (org-export-dispatch-ui
        (let ((option (case key (?1 'body) (?2 'visible) (?3 'subtree)
        (let ((option (case key (?1 'body) (?2 'visible) (?3 'subtree)
-			   (?4 'force))))
+			   (?4 'force) (?5 'async))))
 	 (if (memq option options) (remq option options)
 	 (if (memq option options) (remq option options)
 	   (cons option options)))
 	   (cons option options)))
        first-key expertp))
        first-key expertp))

+ 36 - 11
contrib/lisp/org-md.el

@@ -59,10 +59,12 @@ This variable can be set to either `atx' or `setext'."
   :menu-entry
   :menu-entry
   (?m "Export to Markdown"
   (?m "Export to Markdown"
       ((?M "To temporary buffer"
       ((?M "To temporary buffer"
-	   (lambda (s v b) (org-md-export-as-markdown s v)))
-       (?m "To file" (lambda (s v b) (org-md-export-to-markdown s v)))
+	   (lambda (a s v b) (org-md-export-as-markdown a s v)))
+       (?m "To file" (lambda (a s v b) (org-md-export-to-markdown a s v)))
        (?o "To file and open"
        (?o "To file and open"
-	   (lambda (s v b) (org-open-file (org-md-export-to-markdown s v))))))
+	   (lambda (a s v b)
+	     (if a (org-md-export-to-markdown t s v)
+	       (org-open-file (org-md-export-to-markdown nil s v)))))))
   :translate-alist ((bold . org-md-bold)
   :translate-alist ((bold . org-md-bold)
 		    (code . org-md-verbatim)
 		    (code . org-md-verbatim)
 		    (example-block . org-md-example-block)
 		    (example-block . org-md-example-block)
@@ -411,7 +413,7 @@ as a communication channel."
 ;;; Interactive function
 ;;; Interactive function
 
 
 ;;;###autoload
 ;;;###autoload
-(defun org-md-export-as-markdown (&optional subtreep visible-only)
+(defun org-md-export-as-markdown (&optional async subtreep visible-only)
   "Export current buffer to a text buffer.
   "Export current buffer to a text buffer.
 
 
 If narrowing is active in the current buffer, only export its
 If narrowing is active in the current buffer, only export its
@@ -419,6 +421,10 @@ narrowed part.
 
 
 If a region is active, export that region.
 If a region is active, export that region.
 
 
+A non-nil optional argument ASYNC means the process should happen
+asynchronously.  The resulting buffer should be accessible
+through the `org-export-stack' interface.
+
 When optional argument SUBTREEP is non-nil, export the sub-tree
 When optional argument SUBTREEP is non-nil, export the sub-tree
 at point, extracting information from the headline properties
 at point, extracting information from the headline properties
 first.
 first.
@@ -430,15 +436,25 @@ Export is done in a buffer named \"*Org MD Export*\", which will
 be displayed when `org-export-show-temporary-export-buffer' is
 be displayed when `org-export-show-temporary-export-buffer' is
 non-nil."
 non-nil."
   (interactive)
   (interactive)
-  (let ((outbuf (org-export-to-buffer
-		 'md "*Org MD Export*" subtreep visible-only)))
-    (with-current-buffer outbuf (text-mode))
-    (when org-export-show-temporary-export-buffer
-      (switch-to-buffer-other-window outbuf))))
+  (if async
+      (org-export-async-start
+	  (lambda (output)
+	    (with-current-buffer (get-buffer-create "*Org MD Export*")
+	      (erase-buffer)
+	      (insert output)
+	      (goto-char (point-min))
+	      (text-mode)
+	      (org-export-add-to-stack (current-buffer) 'md)))
+	`(org-export-as 'md ,subtreep ,visible-only))
+    (let ((outbuf (org-export-to-buffer
+		   'md "*Org MD Export*" subtreep visible-only)))
+      (with-current-buffer outbuf (text-mode))
+      (when org-export-show-temporary-export-buffer
+	(switch-to-buffer-other-window outbuf)))))
 
 
 
 
 ;;;###autoload
 ;;;###autoload
-(defun org-md-export-to-markdown (&optional subtreep visible-only)
+(defun org-md-export-to-markdown (&optional async subtreep visible-only)
   "Export current buffer to a Markdown file.
   "Export current buffer to a Markdown file.
 
 
 If narrowing is active in the current buffer, only export its
 If narrowing is active in the current buffer, only export its
@@ -446,6 +462,10 @@ narrowed part.
 
 
 If a region is active, export that region.
 If a region is active, export that region.
 
 
+A non-nil optional argument ASYNC means the process should happen
+asynchronously.  The resulting file should be accessible through
+the `org-export-stack' interface.
+
 When optional argument SUBTREEP is non-nil, export the sub-tree
 When optional argument SUBTREEP is non-nil, export the sub-tree
 at point, extracting information from the headline properties
 at point, extracting information from the headline properties
 first.
 first.
@@ -456,7 +476,12 @@ contents of hidden elements.
 Return output file's name."
 Return output file's name."
   (interactive)
   (interactive)
   (let ((outfile (org-export-output-file-name ".md" subtreep)))
   (let ((outfile (org-export-output-file-name ".md" subtreep)))
-    (org-export-to-file 'md outfile subtreep visible-only)))
+    (if async
+	(org-export-async-start
+	    (lambda (f) (org-export-add-to-stack f 'md))
+	  `(expand-file-name
+	    (org-export-to-file 'md ,outfile ,subtreep ,visible-only)))
+      (org-export-to-file 'md outfile subtreep visible-only))))
 
 
 
 
 (provide 'org-md)
 (provide 'org-md)