From mboxrd@z Thu Jan 1 00:00:00 1970 From: Nicolas Goaziou Subject: Re: Post() evaluates but fails in export Date: Fri, 14 Mar 2014 16:01:10 +0100 Message-ID: <87wqfwzux5.fsf@gmail.com> References: <87txd1fy0m.fsf@syk.fi> <87ob23jfbz.fsf@syk.fi> Mime-Version: 1.0 Content-Type: multipart/mixed; boundary="=-=-=" Return-path: Received: from eggs.gnu.org ([2001:4830:134:3::10]:54045) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1WOTbO-0004kE-Fi for emacs-orgmode@gnu.org; Fri, 14 Mar 2014 11:00:56 -0400 Received: from Debian-exim by eggs.gnu.org with spam-scanned (Exim 4.71) (envelope-from ) id 1WOTbI-0006Lq-QS for emacs-orgmode@gnu.org; Fri, 14 Mar 2014 11:00:50 -0400 Received: from mail-wi0-x235.google.com ([2a00:1450:400c:c05::235]:48164) by eggs.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1WOTbI-0006Ll-AB for emacs-orgmode@gnu.org; Fri, 14 Mar 2014 11:00:44 -0400 Received: by mail-wi0-f181.google.com with SMTP id bs8so2726224wib.8 for ; Fri, 14 Mar 2014 08:00:43 -0700 (PDT) In-Reply-To: <87ob23jfbz.fsf@syk.fi> (Jarmo Hurri's message of "Wed, 19 Feb 2014 17:24:16 +0200") List-Id: "General discussions about Org-mode." List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: emacs-orgmode-bounces+geo-emacs-orgmode=m.gmane.org@gnu.org Sender: emacs-orgmode-bounces+geo-emacs-orgmode=m.gmane.org@gnu.org To: Jarmo Hurri Cc: emacs-orgmode@gnu.org --=-=-= Content-Type: text/plain Hello, Jarmo Hurri writes: > The following code evaluates just fine with C-c C-c, but fails during > export. This is with the newest org-mode just pulled and built. How do I > fix the issue? > > # ----------------------------------------------------------------------- > Here is a function I want to define (use below), but which I do not > want to export (neither code nor results). > #+name: foo > #+begin_src emacs-lisp :exports none :var bar="baz" > (concat "bar" bar) > #+end_src > > #+RESULTS: foo > : barbaz > > Here is a function that uses foo() defined above. This evaluates just > fine with C-c C-c, but fails in export. It fails both in ASCII export > (C-c C-e t a) and LaTeX export (C-c C-e l p). The error is > > org-babel-ref-resolve: Reference 'foo' not found in this buffer > > #+name: nofun > #+BEGIN_SRC emacs-lisp :exports results :post foo("nofun") > #+END_SRC > > #+RESULTS: nofun > : barnofun > # ----------------------------------------------------------------------- The attached patch should fix the issue. Could you confirm it? Regards, -- Nicolas Goaziou --=-=-= Content-Type: text/x-diff Content-Disposition: inline; filename=0001-ob-ref-Properly-resolve-references-in-post-arguments.patch >From 081bbb80b58d5e22c300ec22159570898ac5c0d3 Mon Sep 17 00:00:00 2001 From: Nicolas Goaziou Date: Fri, 14 Mar 2014 15:27:32 +0100 Subject: [PATCH] ob-ref: Properly resolve references in ":post" arguments * lisp/ob-core.el (org-babel-exp-reference-buffer): New variable, as a replacement for `org-current-export-file'. (org-babel-check-confirm-evaluate): Use new variable. * lisp/ob-exp.el (org-babel-exp-in-export-file): Use new variable. (org-babel-exp-get-export-buffer): Remove function. (org-babel-exp-process-buffer): Change signature. * lisp/ob-ref.el (org-babel-ref-resolve): Use new variable during export in order to properly resolve references. * lisp/ox.el (org-export-execute-babel-code): Use new variable. * contrib/lisp/org-wikinodes.el (org-wikinodes-process-links-for-export): Remove a cond branch as it is always false (`org-current-export-file' couldn't be a string). * testing/lisp/test-ob-lob.el (test-ob-lob/export-lob-lines): Update test. * testing/lisp/test-ob.el (test-ob/eval-header-argument): Update test. * testing/lisp/test-ob-exp.el (ob-export/reference-in-post-header): New test. During export, Babel executes sequentially all blocks in the buffer being exported. This can lead to modifications preventing some references from being resolved. As a workaround, Babel stores a pristine copy of the buffer in a variable so it can always find needed references. Before this patch, the variable storing this copy was `org-current-export-file' and was dynamically bound in "ox.el". It was used to resolve noweb references (`org-babel-expand-noweb-references') but not regular references (`org-babel-ref-resolve'). Now, the variable is `org-babel-exp-reference-buffer' and it is bound from `org-babel-exp-process-buffer'. It is used to resolve all references. In particular, this allows to use references in :post header. Thanks to Jarmo Hurri for reporting it. --- contrib/lisp/org-wikinodes.el | 7 -- lisp/ob-core.el | 8 +- lisp/ob-exp.el | 37 ++++----- lisp/ob-ref.el | 185 +++++++++++++++++++++--------------------- lisp/ox.el | 4 +- testing/lisp/test-ob-exp.el | 17 +++- testing/lisp/test-ob-lob.el | 3 +- testing/lisp/test-ob.el | 2 +- 8 files changed, 134 insertions(+), 129 deletions(-) diff --git a/contrib/lisp/org-wikinodes.el b/contrib/lisp/org-wikinodes.el index 7d136c2..7f3e2e3 100644 --- a/contrib/lisp/org-wikinodes.el +++ b/contrib/lisp/org-wikinodes.el @@ -268,7 +268,6 @@ If there is no such wiki target, return nil." (car org-export-target-aliases)))) (push (caar target-alist) (cdr a))))) -(defvar org-current-export-file) (defun org-wikinodes-process-links-for-export () "Process Wiki links in the export preprocess buffer. @@ -294,12 +293,6 @@ with working links." ((eq org-wikinodes-scope 'file) ;; No match in file, and other files are not allowed (insert (format "%s" link))) - ((setq file - (and (org-string-nw-p org-current-export-file) - (org-wikinodes-which-file - link (file-name-directory org-current-export-file)))) - ;; Match in another file in the current directory - (insert (format "[[file:%s::%s][%s]]" file link link))) (t ;; No match for this link (insert (format "%s" link))))))))) diff --git a/lisp/ob-core.el b/lisp/ob-core.el index 8c55a18..0adfc33 100644 --- a/lisp/ob-core.el +++ b/lisp/ob-core.el @@ -285,7 +285,11 @@ Returns a list (setf (nth 2 info) (org-babel-process-params (nth 2 info)))) (when info (append info (list name indent head))))) -(defvar org-current-export-file) ; dynamically bound +(defvar org-babel-exp-reference-buffer nil + "Buffer containing original contents of the exported buffer. +This is used by Babel to resolve references in source blocks. +Its value is dynamically bound during export.") + (defmacro org-babel-check-confirm-evaluate (info &rest body) "Evaluate BODY with special execution confirmation variables set. @@ -305,7 +309,7 @@ name of the code block." (when (assoc :noeval ,headers) "no"))) (,eval-no (or (equal ,eval "no") (equal ,eval "never"))) - (,export (org-bound-and-true-p org-current-export-file)) + (,export org-babel-exp-reference-buffer) (,eval-no-export (and ,export (or (equal ,eval "no-export") (equal ,eval "never-export")))) (noeval (or ,eval-no ,eval-no-export)) diff --git a/lisp/ob-exp.el b/lisp/ob-exp.el index 09ae827..388bdf5 100644 --- a/lisp/ob-exp.el +++ b/lisp/ob-exp.el @@ -27,7 +27,6 @@ (eval-when-compile (require 'cl)) -(defvar org-current-export-file) (defvar org-babel-lob-one-liner-regexp) (defvar org-babel-ref-split-regexp) (defvar org-list-forbidden-blocks) @@ -61,27 +60,18 @@ be executed." (const :tag "Always" t))) (put 'org-export-babel-evaluate 'safe-local-variable (lambda (x) (eq x nil))) -(defun org-babel-exp-get-export-buffer () - "Return the current export buffer if possible." - (cond - ((bufferp org-current-export-file) org-current-export-file) - (org-current-export-file (get-file-buffer org-current-export-file)) - ('otherwise - (error "Requested export buffer when `org-current-export-file' is nil")))) - (defvar org-link-search-inhibit-query) - (defmacro org-babel-exp-in-export-file (lang &rest body) (declare (indent 1)) `(let* ((lang-headers (intern (concat "org-babel-default-header-args:" ,lang))) (heading (nth 4 (ignore-errors (org-heading-components)))) (export-buffer (current-buffer)) - (original-buffer (org-babel-exp-get-export-buffer)) results) - (when original-buffer - ;; resolve parameters in the original file so that - ;; headline and file-wide parameters are included, attempt - ;; to go to the same heading in the original file - (set-buffer original-buffer) + results) + (when org-babel-exp-reference-buffer + ;; Resolve parameters in the original file so that headline and + ;; file-wide parameters are included, attempt to go to the same + ;; heading in the original file + (set-buffer org-babel-exp-reference-buffer) (save-restriction (when heading (condition-case nil @@ -152,12 +142,17 @@ this template." :type 'string) (defvar org-babel-default-lob-header-args) -(defun org-babel-exp-process-buffer () - "Execute all Babel blocks in current buffer." +(defun org-babel-exp-process-buffer (reference-buffer) + "Execute all Babel blocks in current buffer. +REFERENCE-BUFFER is the buffer containing a pristine copy of the +buffer being processed. It is used to properly resolve +references in source blocks, as modifications in current buffer +may make them unreachable." (interactive) (save-window-excursion (save-excursion (let ((case-fold-search t) + (org-babel-exp-reference-buffer reference-buffer) (regexp (concat org-babel-inline-src-block-regexp "\\|" org-babel-lob-one-liner-regexp "\\|" "^[ \t]*#\\+BEGIN_SRC"))) @@ -185,7 +180,7 @@ this template." (if (and (cdr (assoc :noweb params)) (string= "yes" (cdr (assoc :noweb params)))) (org-babel-expand-noweb-references - info (org-babel-exp-get-export-buffer)) + info org-babel-exp-reference-buffer) (nth 1 info))) (goto-char begin) (let ((replacement (org-babel-exp-do-export info 'inline))) @@ -340,7 +335,7 @@ replaced with its value." (org-babel-noweb-wrap) "" (nth 1 info)) (if (org-babel-noweb-p (nth 2 info) :export) (org-babel-expand-noweb-references - info (org-babel-exp-get-export-buffer)) + info org-babel-exp-reference-buffer) (nth 1 info)))) (org-fill-template org-babel-exp-code-template @@ -369,7 +364,7 @@ inhibit insertion of results into the buffer." (let ((lang (nth 0 info)) (body (if (org-babel-noweb-p (nth 2 info) :eval) (org-babel-expand-noweb-references - info (org-babel-exp-get-export-buffer)) + info org-babel-exp-reference-buffer) (nth 1 info))) (info (copy-sequence info)) (org-babel-current-src-block-location (point-marker))) diff --git a/lisp/ob-ref.el b/lisp/ob-ref.el index f50ca72..6172895 100644 --- a/lisp/ob-ref.el +++ b/lisp/ob-ref.el @@ -129,98 +129,99 @@ the variable." (defun org-babel-ref-resolve (ref) "Resolve the reference REF and return its value." (save-window-excursion - (save-excursion - (let ((case-fold-search t) - type args new-refere new-header-args new-referent result - lob-info split-file split-ref index index-row index-col id) - ;; if ref is indexed grab the indices -- beware nested indices - (when (and (string-match "\\[\\([^\\[]+\\)\\]$" ref) - (let ((str (substring ref 0 (match-beginning 0)))) - (= (org-count ?( str) (org-count ?) str)))) - (setq index (match-string 1 ref)) - (setq ref (substring ref 0 (match-beginning 0)))) - ;; assign any arguments to pass to source block - (when (string-match - "^\\(.+?\\)\\(\\[\\(.*\\)\\]\\|\\(\\)\\)\(\\(.*\\)\)$" ref) - (setq new-refere (match-string 1 ref)) - (setq new-header-args (match-string 3 ref)) - (setq new-referent (match-string 5 ref)) - (when (> (length new-refere) 0) - (when (> (length new-referent) 0) - (setq args (mapcar (lambda (ref) (cons :var ref)) - (org-babel-ref-split-args new-referent)))) - (when (> (length new-header-args) 0) - (setq args (append (org-babel-parse-header-arguments - new-header-args) args))) - (setq ref new-refere))) - (when (string-match "^\\(.+\\):\\(.+\\)$" ref) - (setq split-file (match-string 1 ref)) - (setq split-ref (match-string 2 ref)) - (find-file split-file) (setq ref split-ref)) - (save-restriction - (widen) - (goto-char (point-min)) - (if (let ((src-rx (org-babel-named-src-block-regexp-for-name ref)) - (res-rx (org-babel-named-data-regexp-for-name ref))) - ;; goto ref in the current buffer - (or - ;; check for code blocks - (re-search-forward src-rx nil t) - ;; check for named data - (re-search-forward res-rx nil t) - ;; check for local or global headlines by id - (setq id (org-babel-ref-goto-headline-id ref)) - ;; check the Library of Babel - (setq lob-info (cdr (assoc (intern ref) - org-babel-library-of-babel))))) - (unless (or lob-info id) (goto-char (match-beginning 0))) - ;; ;; TODO: allow searching for names in other buffers - ;; (setq id-loc (org-id-find ref 'marker) - ;; buffer (marker-buffer id-loc) - ;; loc (marker-position id-loc)) - ;; (move-marker id-loc nil) - (error "Reference '%s' not found in this buffer" ref)) - (cond - (lob-info (setq type 'lob)) - (id (setq type 'id)) - ((and (looking-at org-babel-src-name-regexp) - (save-excursion - (forward-line 1) - (or (looking-at org-babel-src-block-regexp) - (looking-at org-babel-multi-line-header-regexp)))) - (setq type 'source-block)) - ((and (looking-at org-babel-src-name-regexp) - (save-excursion - (forward-line 1) - (looking-at org-babel-lob-one-liner-regexp))) - (setq type 'call-line)) - (t (while (not (setq type (org-babel-ref-at-ref-p))) - (forward-line 1) - (beginning-of-line) - (if (or (= (point) (point-min)) (= (point) (point-max))) - (error "Reference not found"))))) - (let ((params (append args '((:results . "silent"))))) - (setq result - (case type - (results-line (org-babel-read-result)) - (table (org-babel-read-table)) - (list (org-babel-read-list)) - (file (org-babel-read-link)) - (source-block (org-babel-execute-src-block - nil nil (if org-babel-update-intermediate - nil params))) - (call-line (save-excursion - (forward-line 1) - (org-babel-lob-execute - (org-babel-lob-get-info)))) - (lob (org-babel-execute-src-block - nil lob-info params)) - (id (org-babel-ref-headline-body))))) - (if (symbolp result) - (format "%S" result) - (if (and index (listp result)) - (org-babel-ref-index-list index result) - result))))))) + (with-current-buffer (or org-babel-exp-reference-buffer (current-buffer)) + (save-excursion + (let ((case-fold-search t) + type args new-refere new-header-args new-referent result + lob-info split-file split-ref index index-row index-col id) + ;; if ref is indexed grab the indices -- beware nested indices + (when (and (string-match "\\[\\([^\\[]+\\)\\]$" ref) + (let ((str (substring ref 0 (match-beginning 0)))) + (= (org-count ?( str) (org-count ?) str)))) + (setq index (match-string 1 ref)) + (setq ref (substring ref 0 (match-beginning 0)))) + ;; assign any arguments to pass to source block + (when (string-match + "^\\(.+?\\)\\(\\[\\(.*\\)\\]\\|\\(\\)\\)\(\\(.*\\)\)$" ref) + (setq new-refere (match-string 1 ref)) + (setq new-header-args (match-string 3 ref)) + (setq new-referent (match-string 5 ref)) + (when (> (length new-refere) 0) + (when (> (length new-referent) 0) + (setq args (mapcar (lambda (ref) (cons :var ref)) + (org-babel-ref-split-args new-referent)))) + (when (> (length new-header-args) 0) + (setq args (append (org-babel-parse-header-arguments + new-header-args) args))) + (setq ref new-refere))) + (when (string-match "^\\(.+\\):\\(.+\\)$" ref) + (setq split-file (match-string 1 ref)) + (setq split-ref (match-string 2 ref)) + (find-file split-file) (setq ref split-ref)) + (save-restriction + (widen) + (goto-char (point-min)) + (if (let ((src-rx (org-babel-named-src-block-regexp-for-name ref)) + (res-rx (org-babel-named-data-regexp-for-name ref))) + ;; goto ref in the current buffer + (or + ;; check for code blocks + (re-search-forward src-rx nil t) + ;; check for named data + (re-search-forward res-rx nil t) + ;; check for local or global headlines by id + (setq id (org-babel-ref-goto-headline-id ref)) + ;; check the Library of Babel + (setq lob-info (cdr (assoc (intern ref) + org-babel-library-of-babel))))) + (unless (or lob-info id) (goto-char (match-beginning 0))) + ;; ;; TODO: allow searching for names in other buffers + ;; (setq id-loc (org-id-find ref 'marker) + ;; buffer (marker-buffer id-loc) + ;; loc (marker-position id-loc)) + ;; (move-marker id-loc nil) + (error "Reference '%s' not found in this buffer" ref)) + (cond + (lob-info (setq type 'lob)) + (id (setq type 'id)) + ((and (looking-at org-babel-src-name-regexp) + (save-excursion + (forward-line 1) + (or (looking-at org-babel-src-block-regexp) + (looking-at org-babel-multi-line-header-regexp)))) + (setq type 'source-block)) + ((and (looking-at org-babel-src-name-regexp) + (save-excursion + (forward-line 1) + (looking-at org-babel-lob-one-liner-regexp))) + (setq type 'call-line)) + (t (while (not (setq type (org-babel-ref-at-ref-p))) + (forward-line 1) + (beginning-of-line) + (if (or (= (point) (point-min)) (= (point) (point-max))) + (error "Reference not found"))))) + (let ((params (append args '((:results . "silent"))))) + (setq result + (case type + (results-line (org-babel-read-result)) + (table (org-babel-read-table)) + (list (org-babel-read-list)) + (file (org-babel-read-link)) + (source-block (org-babel-execute-src-block + nil nil (if org-babel-update-intermediate + nil params))) + (call-line (save-excursion + (forward-line 1) + (org-babel-lob-execute + (org-babel-lob-get-info)))) + (lob (org-babel-execute-src-block + nil lob-info params)) + (id (org-babel-ref-headline-body))))) + (if (symbolp result) + (format "%S" result) + (if (and index (listp result)) + (org-babel-ref-index-list index result) + result)))))))) (defun org-babel-ref-index-list (index lis) "Return the subset of LIS indexed by INDEX. diff --git a/lisp/ox.el b/lisp/ox.el index c437038..9f77af4 100644 --- a/lisp/ox.el +++ b/lisp/ox.el @@ -318,6 +318,7 @@ there is no export process in progress. It can be used to teach Babel blocks how to act differently according to the back-end used.") + ;;; User-configurable Variables ;; @@ -3434,8 +3435,7 @@ file should have." ;; Get a pristine copy of current buffer so Babel references can be ;; properly resolved. (let ((reference (org-export-copy-buffer))) - (unwind-protect (let ((org-current-export-file reference)) - (org-babel-exp-process-buffer)) + (unwind-protect (org-babel-exp-process-buffer reference) (kill-buffer reference)))) (defun org-export--copy-to-kill-ring-p () diff --git a/testing/lisp/test-ob-exp.el b/testing/lisp/test-ob-exp.el index 8345da7..67f40bf 100644 --- a/testing/lisp/test-ob-exp.el +++ b/testing/lisp/test-ob-exp.el @@ -32,8 +32,7 @@ Current buffer is a copy of the original buffer." (with-temp-buffer (org-mode) (insert string) - (let ((org-current-export-file buf)) - (org-babel-exp-process-buffer)) + (org-babel-exp-process-buffer buf) (goto-char (point-min)) (progn ,@body)))) @@ -356,6 +355,20 @@ Here is one at the end of a line. =2= (org-export-execute-babel-code) (buffer-string)))))) +(ert-deftest ob-export/reference-in-post-header () + "Test references in :post header during export." + (should + (org-test-with-temp-text " +#+NAME: foo +#+BEGIN_SRC emacs-lisp :exports none :var bar=\"baz\" + (concat \"bar\" bar) +#+END_SRC + +#+NAME: nofun +#+BEGIN_SRC emacs-lisp :exports results :post foo(\"nofun\") +#+END_SRC" + (org-export-execute-babel-code) t))) + (provide 'test-ob-exp) ;;; test-ob-exp.el ends here diff --git a/testing/lisp/test-ob-lob.el b/testing/lisp/test-ob-lob.el index b0d079a..b85022b 100644 --- a/testing/lisp/test-ob-lob.el +++ b/testing/lisp/test-ob-lob.el @@ -83,8 +83,7 @@ (with-temp-buffer (org-mode) (insert string) - (let ((org-current-export-file buf)) - (org-babel-exp-process-buffer)) + (org-babel-exp-process-buffer buf) (message (buffer-string)) (goto-char (point-min)) (should (re-search-forward "^: 0" nil t)) diff --git a/testing/lisp/test-ob.el b/testing/lisp/test-ob.el index d7ef41a..c0ca493 100644 --- a/testing/lisp/test-ob.el +++ b/testing/lisp/test-ob.el @@ -645,7 +645,7 @@ on two lines (check-eval "no" nil) (check-eval "never-export" t) (check-eval "no-export" t) - (let ((org-current-export-file "something")) + (let ((org-babel-exp-reference-buffer (current-buffer))) (check-eval "never" nil) (check-eval "no" nil) (check-eval "never-export" nil) -- 1.9.0 --=-=-=--