Browse Source

ox: implement additional #+INCLUDE markup

* lisp/ox.el (org-export-expand-include-keyword): Change parsing so
  that arbitrary blocks around the included content can be used.
  Content is not code-escaped unless it is a literal block, this
  applies to "src" and "example".
* doc/org.texi (Include files): Document the additional markup.
* testing/lisp/test-ox.el (test-org-export/expand-include): Add test
  for an #+INCLUDE with "html" and "center" markup.
* testing/examples/include.html: New file, used for testing
  "#+INCLUDE html".
Achim Gratz 5 years ago
parent
commit
4ed554196b
4 changed files with 81 additions and 44 deletions
  1. 25 18
      doc/org.texi
  2. 18 11
      lisp/ox.el
  3. 1 0
      testing/examples/include.html
  4. 37 15
      testing/lisp/test-ox.el

+ 25 - 18
doc/org.texi

@@ -9963,30 +9963,37 @@ include your @file{.emacs} file, you could use:
 @end example
 
 @noindent
-The optional second and third parameter are the markup (i.e., @samp{example}
-or @samp{src}), and, if the markup is @samp{src}, the language for formatting
-the contents.
-
-If no markup is given, the text will be assumed to be in Org mode format and
-will be processed normally.  However, footnote labels (@pxref{Footnotes}) in
-the file will be made local to that file.
-
-Contents of the included file will belong to the same structure (headline,
-item) containing the @code{INCLUDE} keyword.  In particular, headlines within
-the file will become children of the current section.  That behavior can be
-changed by providing an additional keyword parameter, @code{:minlevel}.  In
-that case, all headlines in the included file will be shifted so the one with
-the lowest level reaches that specified level.  For example, to make a file
-become a sibling of the current top-level headline, use
+The first parameter names the the file to include.  The optional second and
+third parameter specify the markup (i.e., @samp{example} or @samp{src}), and,
+if the markup is @samp{src}, the language for formatting the contents.
+
+If markup is requested, the included content will be placed within an
+appropriate block@footnote{While you can request paragraphs (@samp{verse},
+@samp{quote}, @samp{center}), but this places severe restrictions on the type
+of content that is permissible}.  No changes to the included content are made
+and it is the responsibility of the user to ensure that the result is valid
+Org syntax.  For markup @samp{example} and @samp{src}, which is requesting a
+literal example, the content will be code-escaped before inclusion.
+
+If no markup is requested, the text will be assumed to be in Org mode format
+and will be processed normally.  However, footnote labels (@pxref{Footnotes})
+in the file will be made local to that file.  Contents of the included file
+will belong to the same structure (headline, item) containing the
+@code{INCLUDE} keyword.  In particular, headlines within the file will become
+children of the current section.  That behavior can be changed by providing
+an additional keyword parameter, @code{:minlevel}.  In that case, all
+headlines in the included file will be shifted so the one with the lowest
+level reaches that specified level.  For example, to make a file become a
+sibling of the current top-level headline, use
 
 @example
 #+INCLUDE: "~/my-book/chapter2.org" :minlevel 1
 @end example
 
 You can also include a portion of a file by specifying a lines range using
-the @code{:lines} parameter.  The line at the upper end of the range will not
-be included.  The start and/or the end of the range may be omitted to use the
-obvious defaults.
+the @code{:lines} keyword parameter.  The line at the upper end of the range
+will not be included.  The start and/or the end of the range may be omitted
+to use the obvious defaults.
 
 @example
 #+INCLUDE: "~/.emacs" :lines "5-10"   @r{Include lines 5 to 10, 10 excluded}

+ 18 - 11
lisp/ox.el

@@ -3313,9 +3313,10 @@ paths."
 			value)
 		       (prog1 (match-string 1 value)
 			 (setq value (replace-match "" nil nil value)))))
-		 (env (cond ((string-match "\\<example\\>" value) 'example)
+		 (env (cond ((string-match "\\<example\\>" value)
+			     'literal)
 			    ((string-match "\\<src\\(?: +\\(.*\\)\\)?" value)
-			     (match-string 1 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
@@ -3326,7 +3327,11 @@ paths."
 			   (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))))))
+			   (if cur (1+ (org-reduced-level cur)) 1)))))
+		 (src-args (and (eq env 'literal)
+				(match-string 1 value)))
+		 (block (and (string-match "\\<\\(\\S-+\\)\\>" value)
+			     (match-string 1 value))))
 	    ;; Remove keyword.
 	    (delete-region (point) (progn (forward-line) (point)))
 	    (cond
@@ -3340,22 +3345,24 @@ paths."
 	      (error "Recursive file inclusion: %s" file))
 	     (t
 	      (cond
-	       ((eq env 'example)
+	       ((eq env 'literal)
 		(insert
 		 (let ((ind-str (make-string ind ? ))
+		       (arg-str (if (stringp src-args)
+				  (format " %s" src-args)
+				""))
 		       (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)
+		   (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 ? ))
 		       (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))))
+			 (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

+ 1 - 0
testing/examples/include.html

@@ -0,0 +1 @@
+<p>HTML!</p>

+ 37 - 15
testing/lisp/test-ox.el

@@ -835,22 +835,44 @@ body\n")))
       (org-export-expand-include-keyword)
       (buffer-string))))
   ;; Inclusion within an example block.
-  (org-test-with-temp-text
-      (format "#+INCLUDE: \"%s/examples/include.org\" :lines \"1-2\" example"
-	      org-test-dir)
-    (org-export-expand-include-keyword)
-    (should
-     (equal
-      (buffer-string)
-      "#+BEGIN_EXAMPLE\nSmall Org file with an include keyword.\n#+END_EXAMPLE\n")))
+  (should
+   (equal
+    "#+BEGIN_EXAMPLE\nSmall Org file with an include keyword.\n#+END_EXAMPLE\n"
+    (org-test-with-temp-text
+     (format "#+INCLUDE: \"%s/examples/include.org\" :lines \"1-2\" EXAMPLE"
+	     org-test-dir)
+     (org-export-expand-include-keyword)
+     (buffer-string))))
   ;; Inclusion within a src-block.
-  (org-test-with-temp-text
-      (format
-       "#+INCLUDE: \"%s/examples/include.org\" :lines \"4-5\" src emacs-lisp"
-       org-test-dir)
-    (org-export-expand-include-keyword)
-    (should (equal (buffer-string)
-		   "#+BEGIN_SRC emacs-lisp\n(+ 2 1)\n#+END_SRC\n")))
+  (should
+   (equal
+    "#+BEGIN_SRC emacs-lisp\n(+ 2 1)\n#+END_SRC\n"
+    (org-test-with-temp-text
+     (format
+      "#+INCLUDE: \"%s/examples/include.org\" :lines \"4-5\" SRC emacs-lisp"
+      org-test-dir)
+     (org-export-expand-include-keyword)
+     (buffer-string))))
+  ;; Inclusion within an html export-block.
+  (should
+   (equal
+    "#+BEGIN_HTML\n<p>HTML!</p>\n#+END_HTML\n"
+    (org-test-with-temp-text
+     (format
+      "#+INCLUDE: \"%s/examples/include.html\" HTML"
+      org-test-dir)
+     (org-export-expand-include-keyword)
+     (buffer-string))))
+  ;; Inclusion within an center paragraph
+  (should
+   (equal
+    "#+BEGIN_CENTER\nSuccess!\n#+END_CENTER\n"
+    (org-test-with-temp-text
+     (format
+      "#+INCLUDE: \"%s/examples/include2.org\" CENTER"
+      org-test-dir)
+     (org-export-expand-include-keyword)
+     (buffer-string))))
   ;; Footnotes labels are local to each included file.
   (should
    (= 6