summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorNicolas Goaziou <mail@nicolasgoaziou.fr>2017-04-23 19:48:50 +0200
committerNicolas Goaziou <mail@nicolasgoaziou.fr>2017-04-23 19:48:50 +0200
commit5e1f7ff04b2582c79abc19b37baaeba4362ad1f0 (patch)
tree52dfa6f168beaaa88c0f7e2b80cfcfca104cb689
parent942b6267a09e167ad3a546e83205601aa5c0704e (diff)
downloadorg-mode-5e1f7ff04b2582c79abc19b37baaeba4362ad1f0.tar.gz
ox: Ignore INCLUDE keywords in commented headlines
* lisp/ox.el (org-export-expand-include-keyword): Ignore INCLUDE keywords in commented headlines. * testing/lisp/test-ox.el (test-org-export/expand-include): Add test.
-rw-r--r--etc/ORG-NEWS1
-rw-r--r--lisp/ox.el219
-rw-r--r--testing/lisp/test-ox.el23
3 files changed, 126 insertions, 117 deletions
diff --git a/etc/ORG-NEWS b/etc/ORG-NEWS
index 7da09fc..b16b73a 100644
--- a/etc/ORG-NEWS
+++ b/etc/ORG-NEWS
@@ -313,6 +313,7 @@ you use "/!" markup when filtering TODO keywords.
This variable is a ~defcustom~ and replaces the variable
~org-babel-capitalize-example-region-markers~, which is a ~defvar~ and
is now obselete.
+*** =INCLUDE= keywords in commented trees are now ignored.
* Version 9.0
diff --git a/lisp/ox.el b/lisp/ox.el
index f35963e..0c822e0 100644
--- a/lisp/ox.el
+++ b/lisp/ox.el
@@ -3281,116 +3281,119 @@ storing and resolving footnotes. It is created automatically."
;; Expand INCLUDE keywords.
(goto-char (point-min))
(while (re-search-forward include-re nil t)
- (let ((element (save-match-data (org-element-at-point))))
- (when (eq (org-element-type element) 'keyword)
- (beginning-of-line)
- ;; Extract arguments from keyword's value.
- (let* ((value (org-element-property :value element))
- (ind (org-get-indentation))
- location
- (file
- (and (string-match
- "^\\(\".+?\"\\|\\S-+\\)\\(?:\\s-+\\|$\\)" value)
- (prog1
- (save-match-data
- (let ((matched (match-string 1 value)))
- (when (string-match "\\(::\\(.*?\\)\\)\"?\\'"
- matched)
- (setq location (match-string 2 matched))
- (setq matched
- (replace-match "" nil nil matched 1)))
- (expand-file-name
- (org-unbracket-string "\"" "\"" matched)
- dir)))
- (setq value (replace-match "" nil nil value)))))
- (only-contents
- (and (string-match ":only-contents *\\([^: \r\t\n]\\S-*\\)?"
- value)
- (prog1 (org-not-nil (match-string 1 value))
- (setq value (replace-match "" nil nil value)))))
- (lines
- (and (string-match
- ":lines +\"\\(\\(?:[0-9]+\\)?-\\(?:[0-9]+\\)?\\)\""
- value)
- (prog1 (match-string 1 value)
- (setq value (replace-match "" nil nil value)))))
- (env (cond
- ((string-match "\\<example\\>" value) 'literal)
- ((string-match "\\<export\\(?: +\\(.*\\)\\)?" value)
- 'literal)
- ((string-match "\\<src\\(?: +\\(.*\\)\\)?" value)
- 'literal)))
- ;; Minimal level of included file defaults to the child
- ;; level of the current headline, if any, or one. It
- ;; only applies is the file is meant to be included as
- ;; an Org one.
- (minlevel
- (and (not env)
- (if (string-match ":minlevel +\\([0-9]+\\)" value)
- (prog1 (string-to-number (match-string 1 value))
- (setq value (replace-match "" nil nil value)))
- (get-text-property (point)
- :org-include-induced-level))))
- (args (and (eq env 'literal) (match-string 1 value)))
- (block (and (string-match "\\<\\(\\S-+\\)\\>" value)
- (match-string 1 value))))
- ;; Remove keyword.
- (delete-region (point) (line-beginning-position 2))
- (cond
- ((not file) nil)
- ((not (file-readable-p file))
- (error "Cannot include file %s" file))
- ;; Check if files has already been parsed. Look after
- ;; inclusion lines too, as different parts of the same file
- ;; can be included too.
- ((member (list file lines) included)
- (error "Recursive file inclusion: %s" file))
- (t
+ (unless (org-in-commented-heading-p)
+ (let ((element (save-match-data (org-element-at-point))))
+ (when (eq (org-element-type element) 'keyword)
+ (beginning-of-line)
+ ;; Extract arguments from keyword's value.
+ (let* ((value (org-element-property :value element))
+ (ind (org-get-indentation))
+ location
+ (file
+ (and (string-match
+ "^\\(\".+?\"\\|\\S-+\\)\\(?:\\s-+\\|$\\)" value)
+ (prog1
+ (save-match-data
+ (let ((matched (match-string 1 value)))
+ (when (string-match "\\(::\\(.*?\\)\\)\"?\\'"
+ matched)
+ (setq location (match-string 2 matched))
+ (setq matched
+ (replace-match "" nil nil matched 1)))
+ (expand-file-name
+ (org-unbracket-string "\"" "\"" matched)
+ dir)))
+ (setq value (replace-match "" nil nil value)))))
+ (only-contents
+ (and (string-match ":only-contents *\\([^: \r\t\n]\\S-*\\)?"
+ value)
+ (prog1 (org-not-nil (match-string 1 value))
+ (setq value (replace-match "" nil nil value)))))
+ (lines
+ (and (string-match
+ ":lines +\"\\(\\(?:[0-9]+\\)?-\\(?:[0-9]+\\)?\\)\""
+ value)
+ (prog1 (match-string 1 value)
+ (setq value (replace-match "" nil nil value)))))
+ (env (cond
+ ((string-match "\\<example\\>" value) 'literal)
+ ((string-match "\\<export\\(?: +\\(.*\\)\\)?" value)
+ 'literal)
+ ((string-match "\\<src\\(?: +\\(.*\\)\\)?" value)
+ 'literal)))
+ ;; Minimal level of included file defaults to the
+ ;; child level of the current headline, if any, or
+ ;; one. It only applies is the file is meant to be
+ ;; included as an Org one.
+ (minlevel
+ (and (not env)
+ (if (string-match ":minlevel +\\([0-9]+\\)" value)
+ (prog1 (string-to-number (match-string 1 value))
+ (setq value (replace-match "" nil nil value)))
+ (get-text-property (point)
+ :org-include-induced-level))))
+ (args (and (eq env 'literal) (match-string 1 value)))
+ (block (and (string-match "\\<\\(\\S-+\\)\\>" value)
+ (match-string 1 value))))
+ ;; Remove keyword.
+ (delete-region (point) (line-beginning-position 2))
(cond
- ((eq env 'literal)
- (insert
- (let ((ind-str (make-string ind ?\s))
- (arg-str (if (stringp args) (format " %s" args) ""))
- (contents
- (org-escape-code-in-string
- (org-export--prepare-file-contents file lines))))
- (format "%s#+BEGIN_%s%s\n%s%s#+END_%s\n"
- ind-str block arg-str contents ind-str block))))
- ((stringp block)
- (insert
- (let ((ind-str (make-string ind ?\s))
- (contents
- (org-export--prepare-file-contents file lines)))
- (format "%s#+BEGIN_%s\n%s%s#+END_%s\n"
- ind-str block contents ind-str block))))
+ ((not file) nil)
+ ((not (file-readable-p file))
+ (error "Cannot include file %s" file))
+ ;; Check if files has already been parsed. Look after
+ ;; inclusion lines too, as different parts of the same
+ ;; file can be included too.
+ ((member (list file lines) included)
+ (error "Recursive file inclusion: %s" file))
(t
- (insert
- (with-temp-buffer
- (let ((org-inhibit-startup t)
- (lines
- (if location
- (org-export--inclusion-absolute-lines
- file location only-contents lines)
- lines)))
- (org-mode)
- (insert
- (org-export--prepare-file-contents
- file lines ind minlevel
- (or (gethash file file-prefix)
- (puthash file (cl-incf current-prefix) file-prefix))
- footnotes)))
- (org-export-expand-include-keyword
- (cons (list file lines) included)
- (file-name-directory file)
- footnotes)
- (buffer-string)))))
- ;; Expand footnotes after all files have been included.
- ;; Footnotes are stored at end of buffer.
- (unless included
- (org-with-wide-buffer
- (goto-char (point-max))
- (maphash (lambda (k v) (insert (format "\n[fn:%s] %s\n" k v)))
- footnotes)))))))))))
+ (cond
+ ((eq env 'literal)
+ (insert
+ (let ((ind-str (make-string ind ?\s))
+ (arg-str (if (stringp args) (format " %s" args) ""))
+ (contents
+ (org-escape-code-in-string
+ (org-export--prepare-file-contents file lines))))
+ (format "%s#+BEGIN_%s%s\n%s%s#+END_%s\n"
+ ind-str block arg-str contents ind-str block))))
+ ((stringp block)
+ (insert
+ (let ((ind-str (make-string ind ?\s))
+ (contents
+ (org-export--prepare-file-contents file lines)))
+ (format "%s#+BEGIN_%s\n%s%s#+END_%s\n"
+ ind-str block contents ind-str block))))
+ (t
+ (insert
+ (with-temp-buffer
+ (let ((org-inhibit-startup t)
+ (lines
+ (if location
+ (org-export--inclusion-absolute-lines
+ file location only-contents lines)
+ lines)))
+ (org-mode)
+ (insert
+ (org-export--prepare-file-contents
+ file lines ind minlevel
+ (or
+ (gethash file file-prefix)
+ (puthash file (cl-incf current-prefix) file-prefix))
+ footnotes)))
+ (org-export-expand-include-keyword
+ (cons (list file lines) included)
+ (file-name-directory file)
+ footnotes)
+ (buffer-string)))))
+ ;; Expand footnotes after all files have been
+ ;; included. Footnotes are stored at end of buffer.
+ (unless included
+ (org-with-wide-buffer
+ (goto-char (point-max))
+ (maphash (lambda (k v)
+ (insert (format "\n[fn:%s] %s\n" k v)))
+ footnotes))))))))))))
(defun org-export--inclusion-absolute-lines (file location only-contents lines)
"Resolve absolute lines for an included file with file-link.
diff --git a/testing/lisp/test-ox.el b/testing/lisp/test-ox.el
index 4c5dee5..e35b762 100644
--- a/testing/lisp/test-ox.el
+++ b/testing/lisp/test-ox.el
@@ -1055,6 +1055,11 @@ Text"
(should-error
(org-test-with-temp-text "#+INCLUDE: dummy.org"
(org-export-expand-include-keyword)))
+ ;; Refuse to expand keywords in commented headings.
+ (should
+ (org-test-with-temp-text "* COMMENT H1\n#+INCLUDE: dummy.org"
+ (org-export-expand-include-keyword)
+ t))
;; Full insertion with recursive inclusion.
(should
(equal
@@ -1262,15 +1267,15 @@ Footnotes[fn:2], foot[fn:test] and [fn:inline:inline footnote]
;; Adjacent INCLUDE-keywords should have the same :minlevel if unspecified.
(should
(cl-every (lambda (level) (zerop (1- level)))
- (org-test-with-temp-text
- (concat
- (format "#+INCLUDE: \"%s/examples/include.org::#ah\"\n"
- org-test-dir)
- (format "#+INCLUDE: \"%s/examples/include.org::*Heading\""
- org-test-dir))
- (org-export-expand-include-keyword)
- (org-element-map (org-element-parse-buffer) 'headline
- (lambda (head) (org-element-property :level head))))))
+ (org-test-with-temp-text
+ (concat
+ (format "#+INCLUDE: \"%s/examples/include.org::#ah\"\n"
+ org-test-dir)
+ (format "#+INCLUDE: \"%s/examples/include.org::*Heading\""
+ org-test-dir))
+ (org-export-expand-include-keyword)
+ (org-element-map (org-element-parse-buffer) 'headline
+ (lambda (head) (org-element-property :level head))))))
;; INCLUDE does not insert induced :minlevel for src-blocks.
(should-not
(equal