Function: org-export-expand-include-keyword
org-export-expand-include-keyword is a byte-compiled function defined
in ox.el.gz.
Signature
(org-export-expand-include-keyword &optional INCLUDED DIR FOOTNOTES)
Documentation
Expand every include keyword in buffer.
Optional argument INCLUDED is a list of included file names along with their line restriction, when appropriate. It is used to avoid infinite recursion. Optional argument DIR is the current working directory. It is used to properly resolve relative paths. Optional argument FOOTNOTES is a hash-table used for storing and resolving footnotes. It is created automatically.
Source Code
;; Defined in /usr/src/emacs/lisp/org/ox.el.gz
(defun org-export-expand-include-keyword (&optional included dir footnotes)
"Expand every include keyword in buffer.
Optional argument INCLUDED is a list of included file names along
with their line restriction, when appropriate. It is used to
avoid infinite recursion. Optional argument DIR is the current
working directory. It is used to properly resolve relative
paths. Optional argument FOOTNOTES is a hash-table used for
storing and resolving footnotes. It is created automatically."
(let ((includer-file (buffer-file-name (buffer-base-buffer)))
(case-fold-search t)
(file-prefix (make-hash-table :test #'equal))
(current-prefix 0)
(footnotes (or footnotes (make-hash-table :test #'equal)))
(include-re "^[ \t]*#\\+INCLUDE:"))
;; If :minlevel is not set the text-property
;; `:org-include-induced-level' will be used to determine the
;; relative level when expanding INCLUDE.
;; Only affects included Org documents.
(goto-char (point-min))
(while (re-search-forward include-re nil t)
(put-text-property (line-beginning-position) (line-end-position)
:org-include-induced-level
(1+ (org-reduced-level (or (org-current-level) 0)))))
;; Expand INCLUDE keywords.
(goto-char (point-min))
(while (re-search-forward include-re nil 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-current-text-indentation))
location
(coding-system-for-read
(or (and (string-match ":coding +\\(\\S-+\\)>" value)
(prog1 (intern (match-string 1 value))
(setq value (replace-match "" nil nil value))))
coding-system-for-read))
(file
(and (string-match "^\\(\".+?\"\\|\\S-+\\)\\(?:\\s-+\\|$\\)"
value)
(prog1
(save-match-data
(let ((matched (match-string 1 value))
stripped)
(when (string-match "\\(::\\(.*?\\)\\)\"?\\'"
matched)
(setq location (match-string 2 matched))
(setq matched
(replace-match "" nil nil matched 1)))
(setq stripped (org-strip-quotes matched))
(if (org-url-p stripped)
stripped
(expand-file-name stripped 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)
((and (not (org-url-p file)) (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
(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
includer-file)))
(org-export-expand-include-keyword
(cons (list file lines) included)
(unless (org-url-p file)
(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))))))))))))