|
@@ -3256,73 +3256,81 @@ working directory. It is used to properly resolve relative
|
|
|
paths."
|
|
|
(let ((case-fold-search t))
|
|
|
(goto-char (point-min))
|
|
|
- (while (re-search-forward "^[ \t]*#\\+INCLUDE: +\\(.*\\)[ \t]*$" nil t)
|
|
|
- (when (eq (org-element-type (save-match-data (org-element-at-point)))
|
|
|
- 'keyword)
|
|
|
- (beginning-of-line)
|
|
|
- ;; Extract arguments from keyword's value.
|
|
|
- (let* ((value (match-string 1))
|
|
|
- (ind (org-get-indentation))
|
|
|
- (file (and (string-match "^\"\\(\\S-+\\)\"" value)
|
|
|
- (prog1 (expand-file-name (match-string 1 value) dir)
|
|
|
- (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) 'example)
|
|
|
- ((string-match "\\<src\\(?: +\\(.*\\)\\)?" value)
|
|
|
- (match-string 1 value))))
|
|
|
- ;; 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)))
|
|
|
- (let ((cur (org-current-level)))
|
|
|
- (if cur (1+ (org-reduced-level cur)) 1))))))
|
|
|
- ;; Remove keyword.
|
|
|
- (delete-region (point) (progn (forward-line) (point)))
|
|
|
- (cond
|
|
|
- ((not file) (error "Invalid syntax in INCLUDE keyword"))
|
|
|
- ((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
|
|
|
+ (while (re-search-forward "^[ \t]*#\\+INCLUDE:" 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))
|
|
|
+ (file (let ((f (if (eq (aref value 0) ?\") (read value)
|
|
|
+ (and (string-match "^\\S-+" value)
|
|
|
+ (match-string 0 value)))))
|
|
|
+ (setq value
|
|
|
+ (progn
|
|
|
+ (string-match (format "^\"?%s\"?[ \t]*" f)
|
|
|
+ value)
|
|
|
+ (replace-match "" nil nil value)))
|
|
|
+ (expand-file-name f dir)))
|
|
|
+ (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) 'example)
|
|
|
+ ((string-match "\\<src\\(?: +\\(.*\\)\\)?" value)
|
|
|
+ (match-string 1 value))))
|
|
|
+ ;; 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)))
|
|
|
+ (let ((cur (org-current-level)))
|
|
|
+ (if cur (1+ (org-reduced-level cur)) 1))))))
|
|
|
+ ;; Remove keyword.
|
|
|
+ (delete-region (point) (progn (forward-line) (point)))
|
|
|
(cond
|
|
|
- ((eq env 'example)
|
|
|
- (insert
|
|
|
- (let ((ind-str (make-string ind ? ))
|
|
|
- (contents
|
|
|
- (org-escape-code-in-string
|
|
|
- (org-export--prepare-file-contents file lines))))
|
|
|
- (format "%s#+BEGIN_EXAMPLE\n%s%s#+END_EXAMPLE\n"
|
|
|
- ind-str contents ind-str))))
|
|
|
- ((stringp env)
|
|
|
- (insert
|
|
|
- (let ((ind-str (make-string ind ? ))
|
|
|
- (contents
|
|
|
- (org-escape-code-in-string
|
|
|
- (org-export--prepare-file-contents file lines))))
|
|
|
- (format "%s#+BEGIN_SRC %s\n%s%s#+END_SRC\n"
|
|
|
- ind-str env contents ind-str))))
|
|
|
+ ((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)) (org-mode))
|
|
|
- (insert
|
|
|
- (org-export--prepare-file-contents file lines ind minlevel))
|
|
|
- (org-export-expand-include-keyword
|
|
|
- (cons (list file lines) included)
|
|
|
- (file-name-directory file))
|
|
|
- (buffer-string))))))))))))
|
|
|
+ (cond
|
|
|
+ ((eq env 'example)
|
|
|
+ (insert
|
|
|
+ (let ((ind-str (make-string ind ? ))
|
|
|
+ (contents
|
|
|
+ (org-escape-code-in-string
|
|
|
+ (org-export--prepare-file-contents file lines))))
|
|
|
+ (format "%s#+BEGIN_EXAMPLE\n%s%s#+END_EXAMPLE\n"
|
|
|
+ ind-str contents ind-str))))
|
|
|
+ ((stringp env)
|
|
|
+ (insert
|
|
|
+ (let ((ind-str (make-string ind ? ))
|
|
|
+ (contents
|
|
|
+ (org-escape-code-in-string
|
|
|
+ (org-export--prepare-file-contents file lines))))
|
|
|
+ (format "%s#+BEGIN_SRC %s\n%s%s#+END_SRC\n"
|
|
|
+ ind-str env contents ind-str))))
|
|
|
+ (t
|
|
|
+ (insert
|
|
|
+ (with-temp-buffer
|
|
|
+ (let ((org-inhibit-startup t)) (org-mode))
|
|
|
+ (insert
|
|
|
+ (org-export--prepare-file-contents file lines ind minlevel))
|
|
|
+ (org-export-expand-include-keyword
|
|
|
+ (cons (list file lines) included)
|
|
|
+ (file-name-directory file))
|
|
|
+ (buffer-string)))))))))))))
|
|
|
|
|
|
(defun org-export--prepare-file-contents (file &optional lines ind minlevel)
|
|
|
"Prepare the contents of FILE for inclusion and return them as a string.
|