>From 6925403a72db7216b9deca56acc3f72f6d179f22 Mon Sep 17 00:00:00 2001 From: Rasmus Date: Sun, 21 Sep 2014 13:35:11 +0200 Subject: [PATCH] ox: Allow file-links with #+INCLUDE-keyword * org.el (org-edit-special): Handle file-links for INCLUDE. * ox.el (org-export--prepare-file-contents): Handle links and add option no-heading. * ox.el (org-export-expand-include-keyword): Resolve headline links and add option :only-contents. * orgguide.texi (Include files): Updated. * org.texi (Include files): Updated. --- doc/org.texi | 18 ++++++++++++++++ doc/orgguide.texi | 9 ++++++-- lisp/org.el | 8 ++++--- lisp/ox.el | 63 +++++++++++++++++++++++++++++++++++++++++++------------ 4 files changed, 80 insertions(+), 18 deletions(-) diff --git a/doc/org.texi b/doc/org.texi index 7d98d51..9414314 100644 --- a/doc/org.texi +++ b/doc/org.texi @@ -10008,6 +10008,24 @@ to use the obvious defaults. #+INCLUDE: "~/.emacs" :lines "10-" @r{Include lines from 10 to EOF} @end example +Finally, you may use a file-link, see @ref{External links}, to extract an +object as matched by @address@hidden that address@hidden is locally bound to non-nil. +Therefore, @code{org-link-search} only matches headlines and named +elements.}. If the keyword @code{:only-contents} is used, only the contents +of the element in included. For headlines, drawers and properties +immediately following the headline will not be included when using address@hidden:only-contents}. The @code{:lines} keyword is local to the +element in question. Some examples: + address@hidden +#+INCLUDE: "./paper.org::#theory" :only-contents + @r{Include the body of the heading with the custom id @code{theory}} +#+INCLUDE: "./paper.org::mytable" @r{Include tabel with name and caption.} +#+INCLUDE: "./paper.org::*conclusion" :lines 1-20 + @r{Include the first 20 lines of the headline named conclusion.} address@hidden example + @table @kbd @kindex C-c ' @item C-c ' diff --git a/doc/orgguide.texi b/doc/orgguide.texi index ca8e052..d3cee0c 100644 --- a/doc/orgguide.texi +++ b/doc/orgguide.texi @@ -2264,8 +2264,13 @@ include your @file{.emacs} file, you could use: 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. The markup is optional, if it is not given, the text will be -assumed to be in Org mode format and will be processed normally. @kbd{C-c '} -will visit the included file. +assumed to be in Org mode format and will be processed normally. File-links +will be interpret as well: address@hidden +#+INCLUDE: "./otherfile.org::#my_custom_id" :no-contents address@hidden smallexample address@hidden address@hidden '} will visit the included file. @node Embedded @LaTeX{}, , Include files, Markup @section Embedded @LaTeX{} diff --git a/lisp/org.el b/lisp/org.el index 4ffe1e8..86a1bf9 100755 --- a/lisp/org.el +++ b/lisp/org.el @@ -20520,9 +20520,11 @@ Otherwise, return a user error." session params)))))) (keyword (if (member (org-element-property :key element) '("INCLUDE" "SETUPFILE")) - (find-file-other-window - (org-remove-double-quotes - (car (org-split-string (org-element-property :value element))))) + (org-open-link-from-string + (format "[[%s]]" + (expand-file-name + (org-remove-double-quotes + (car (org-split-string (org-element-property :value element))))))) (user-error "No special environment to edit here"))) (table (if (eq (org-element-property :type element) 'table.el) diff --git a/lisp/ox.el b/lisp/ox.el index f01f951..f5b8fcc 100644 --- a/lisp/ox.el +++ b/lisp/ox.el @@ -1,5 +1,4 @@ ;;; ox.el --- Generic Export Engine for Org Mode - ;; Copyright (C) 2012-2014 Free Software Foundation, Inc. ;; Author: Nicolas Goaziou @@ -3321,13 +3320,23 @@ paths." ;; 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 (expand-file-name - (org-remove-double-quotes - (match-string 1 value)) - dir) - (setq value (replace-match "" nil nil value))))) + (let ((matched (save-match-data + (org-split-string (match-string 1 value) "::")))) + (setq location (car-safe (cdr-safe matched))) + (prog1 (expand-file-name + (org-remove-double-quotes + (car matched)) + dir) + (setq value (replace-match "" nil nil value)))))) + + (only-contents + (and (string-match + ":\\(only-?contents?[[:space:]]*\\(?:'t\\|true\\|yes\\)?\\)" value) + (prog1 t + (setq value (replace-match "" nil nil value))))) (lines (and (string-match ":lines +\"\\(\\(?:[0-9]+\\)?-\\(?:[0-9]+\\)?\\)\"" @@ -3370,18 +3379,18 @@ paths." (insert (let ((ind-str (make-string ind ? )) (arg-str (if (stringp src-args) - (format " %s" src-args) - "")) + (format " %s" src-args) + "")) (contents (org-escape-code-in-string - (org-export--prepare-file-contents file lines)))) + (org-export--prepare-file-contents file location only-contents 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 ? )) (contents - (org-export--prepare-file-contents file lines))) + (org-export--prepare-file-contents file location only-contents lines))) (format "%s#+BEGIN_%s\n%s%s#+END_%s\n" ind-str block contents ind-str block)))) (t @@ -3390,7 +3399,7 @@ paths." (let ((org-inhibit-startup t)) (org-mode)) (insert (org-export--prepare-file-contents - file lines ind minlevel + file location only-contents lines ind minlevel (or (gethash file file-prefix) (puthash file (incf current-prefix) file-prefix)))) (org-export-expand-include-keyword @@ -3398,9 +3407,17 @@ paths." (file-name-directory file)) (buffer-string))))))))))))) -(defun org-export--prepare-file-contents (file &optional lines ind minlevel id) +(defun org-export--prepare-file-contents (file &optional location only-contents lines ind minlevel id) "Prepare the contents of FILE for inclusion and return them as a string. +When optional argument LOCATION is a string the matching element +identified using `org-link-search' is returned. Note that +`org-link-search-must-match-exact-headline' is locally set to +non-nil. When ONLY-CONTENTS is non-nil only the contents of the +matched element in included. If LOCATION is a headline and +ONLY-CONTENTS is non-nil, drawers and property-drawers +immediately following the first headline are also removed. + When optional argument LINES is a string specifying a range of lines, include only those lines. @@ -3420,6 +3437,26 @@ This is useful to avoid conflicts when more than one Org file with footnotes is included in a document." (with-temp-buffer (insert-file-contents file) + (org-mode) + (when location + (condition-case err + ;; enforce consistency in search. + (let ((org-link-search-must-match-exact-headline t)) + (org-link-search location)) + ;; helpful error messages + (error (error (format "%s for %s::%s" + (error-message-string err) file location)))) + (narrow-to-region + (org-element-property + (if only-contents :contents-begin :begin) (org-element-at-point)) + (org-element-property (if only-contents :contents-end :end) (org-element-at-point))) + ;; get rid of drawers and properties + (when only-contents + (let ((element (org-element-at-point))) + (while (member (org-element-type element) '(drawer property-drawer)) + (delete-region (org-element-property :begin element) + (org-element-property :end element)) + (setq element (org-element-at-point)))))) (when lines (let* ((lines (split-string lines "-")) (lbeg (string-to-number (car lines))) @@ -3495,7 +3532,7 @@ with footnotes is included in a document." (org-element-normalize-string (buffer-string)))) (defun org-export-execute-babel-code () - "Execute every Babel code in the visible part of current buffer." + "ExecUte every Babel code in the visible part of current buffer." ;; Get a pristine copy of current buffer so Babel references can be ;; properly resolved. (let ((reference (org-export-copy-buffer))) -- 2.1.0