ox: Add EXPORT_FILE_NAME keyword

* lisp/ox.el (org-export-output-file-name): Support EXPORT_FILE_NAME
  keyword.
* doc/org.texi (Export settings): Document new keyword.
* testing/lisp/test-ox.el (test-org-export/output-file-name): Add
  tests.
This commit is contained in:
Nicolas Goaziou 2016-12-20 17:10:46 +01:00
parent 2ac798af6c
commit 91dc1b34e3
4 changed files with 77 additions and 44 deletions

View File

@ -10465,6 +10465,12 @@ be executed during export even though the subtree is not exported.
The title to be shown. You can use several such keywords for long titles.
@end table
@item EXPORT_FILE_NAME
@cindex #+EXPORT_FILE_NAME
The name of the output file to be generated. By default, it is taken from
the file associated to the buffer, when possible, or asked to you otherwise.
In all cases, the extension is ignored, and a back-end specific one is added.
The @code{#+OPTIONS} keyword is a compact@footnote{If you want to configure
many options this way, you can use several @code{#+OPTIONS} lines.} form that
recognizes the following arguments:
@ -10636,9 +10642,9 @@ Toggle inclusion of tables (@code{org-export-with-tables}).
When exporting only a subtree, each of the previous keywords@footnote{With
the exception of @samp{SETUPFILE}.} can be overridden locally by special node
properties. These begin with @samp{EXPORT_}, followed by the name of the
keyword they supplant. For example, @samp{DATE} and @samp{OPTIONS} keywords
become, respectively, @samp{EXPORT_DATE} and @samp{EXPORT_OPTIONS}
properties.
keyword they supplant, unless the keyword already beging with @samp{EXPORT_}.
For example, @samp{DATE} and @samp{EXPORT_FILE_NAME} keywords become,
respectively, @samp{EXPORT_DATE} and @samp{EXPORT_FILE_NAME} properties.
@cindex #+BIND
@vindex org-export-allow-bind-keywords
@ -10647,13 +10653,6 @@ can become buffer-local during export by using the BIND keyword. Its syntax
is @samp{#+BIND: variable value}. This is particularly useful for in-buffer
settings that cannot be changed using specific keywords.
@cindex property, EXPORT_FILE_NAME
The name of the output file to be generated is taken from the file associated
to the buffer, when possible, or asked to you otherwise. For subtree export,
you can also set @code{EXPORT_FILE_NAME} property. In all cases, only the
base name of the file is retained, and a back-end specific extension is
added.
@node Table of contents
@section Table of contents
@cindex table of contents

View File

@ -128,6 +128,10 @@ as descriptions of links, a.k.a. image links. See its docstring for
details.
**** Add global macros through ~org-export-global-macros~
With this variable, one can define macros available for all documents.
**** New keyword ~#+EXPORT_FILE_NAME~
Simiralry to ~:EXPORT_FILE_NAME:~ property, this keyword allow to
specify the name of the output file upon exporting the document. This
has also an effect on publishing.
**** Horizontal rules are no longer ignored in LaTeX table math mode
*** ~org-list-to-generic~ includes a new property: ~:ifmt~

View File

@ -6184,29 +6184,37 @@ directory.
Return file name as a string."
(let* ((visited-file (buffer-file-name (buffer-base-buffer)))
(base-name
;; File name may come from EXPORT_FILE_NAME subtree
;; property.
(file-name-sans-extension
(or (and subtreep (org-entry-get nil "EXPORT_FILE_NAME" 'selective))
;; File name may be extracted from buffer's associated
;; file, if any.
(and visited-file (file-name-nondirectory visited-file))
;; Can't determine file name on our own: Ask user.
(read-file-name
"Output file: " pub-dir nil nil nil
(lambda (name)
(string= (file-name-extension name t) extension))))))
(concat
(file-name-sans-extension
(or
;; Check EXPORT_FILE_NAME subtree property.
(and subtreep (org-entry-get nil "EXPORT_FILE_NAME" 'selective))
;; Check #+EXPORT_FILE_NAME keyword.
(org-with-point-at (point-min)
(catch :found
(let ((case-fold-search t))
(while (re-search-forward
"^[ \t]*#\\+EXPORT_FILE_NAME:[ \t]+\\S-" nil t)
(let ((element (org-element-at-point)))
(when (eq 'keyword (org-element-type element))
(throw :found
(org-element-property :value element))))))))
;; Extract from buffer's associated file, if any.
(and visited-file (file-name-nondirectory visited-file))
;; Can't determine file name on our own: ask user.
(read-file-name
"Output file: " pub-dir nil nil nil
(lambda (n) (string= extension (file-name-extension n t))))))
extension))
(output-file
;; Build file name. Enforce EXTENSION over whatever user
;; may have come up with. PUB-DIR, if defined, always has
;; precedence over any provided path.
(cond
(pub-dir
(concat (file-name-as-directory pub-dir)
(file-name-nondirectory base-name)
extension))
((file-name-absolute-p base-name) (concat base-name extension))
(t (concat (file-name-as-directory ".") base-name extension)))))
(pub-dir (concat (file-name-as-directory pub-dir)
(file-name-nondirectory base-name)))
((file-name-absolute-p base-name) base-name)
(t base-name))))
;; If writing to OUTPUT-FILE would overwrite original file, append
;; EXTENSION another time to final name.
(if (and visited-file (file-equal-p visited-file output-file))

View File

@ -961,20 +961,34 @@ Text"
;; Export from a file: name is built from original file name.
(should
(org-test-with-temp-text-in-file "Test"
(equal (concat (file-name-as-directory ".")
(file-name-nondirectory
(file-name-sans-extension (buffer-file-name))))
(file-name-sans-extension (org-export-output-file-name ".ext")))))
(equal (file-name-base (buffer-file-name))
(file-name-base (org-export-output-file-name ".ext")))))
;; When #+EXPORT_FILE_NAME is defined, use it.
(should
(equal "test.ext"
(org-test-with-temp-text-in-file "#+EXPORT_FILE_NAME: test"
(org-export-output-file-name ".ext" t))))
;; When exporting to subtree, check EXPORT_FILE_NAME property first.
(should
(org-test-with-temp-text-in-file
"* Test\n :PROPERTIES:\n :EXPORT_FILE_NAME: test\n :END:"
(equal (org-export-output-file-name ".ext" t) "./test.ext")))
(equal "test.ext"
(org-test-with-temp-text-in-file
"* Test\n :PROPERTIES:\n :EXPORT_FILE_NAME: test\n :END:"
(org-export-output-file-name ".ext" t))))
(should
(equal "property.ext"
(org-test-with-temp-text
"#+EXPORT_FILE_NAME: keyword
* Test<point>
:PROPERTIES:
:EXPORT_FILE_NAME: property
:END:"
(org-export-output-file-name ".ext" t))))
;; From a buffer not associated to a file, too.
(should
(org-test-with-temp-text
"* Test\n :PROPERTIES:\n :EXPORT_FILE_NAME: test\n :END:"
(equal (org-export-output-file-name ".ext" t) "./test.ext")))
(equal "test.ext"
(org-test-with-temp-text
"* Test\n :PROPERTIES:\n :EXPORT_FILE_NAME: test\n :END:"
(org-export-output-file-name ".ext" t))))
;; When provided name is absolute, preserve it.
(should
(org-test-with-temp-text
@ -983,15 +997,23 @@ Text"
(file-name-absolute-p (org-export-output-file-name ".ext" t))))
;; When PUB-DIR argument is provided, use it.
(should
(org-test-with-temp-text-in-file "Test"
(equal (file-name-directory
(org-export-output-file-name ".ext" nil "dir/"))
"dir/")))
(equal "dir/"
(org-test-with-temp-text-in-file "Test"
(file-name-directory
(org-export-output-file-name ".ext" nil "dir/")))))
;; PUB-DIR has precedence over EXPORT_FILE_NAME keyword or property.
(should
(equal "pub-dir/"
(org-test-with-temp-text-in-file
"#+EXPORT_FILE_NAME: /dir/keyword\nTest"
(file-name-directory
(org-export-output-file-name ".ext" nil "pub-dir/")))))
;; When returned name would overwrite original file, add EXTENSION
;; another time.
(should
(org-test-at-id "75282ba2-f77a-4309-a970-e87c149fe125"
(equal (org-export-output-file-name ".org") "./normal.org.org"))))
(equal "normal.org.org"
(org-test-at-id "75282ba2-f77a-4309-a970-e87c149fe125"
(org-export-output-file-name ".org")))))
(ert-deftest test-org-export/expand-include ()
"Test file inclusion in an Org buffer."