emacs-orgmode
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

Re: [O] Post() evaluates but fails in export


From: Nicolas Goaziou
Subject: Re: [O] Post() evaluates but fails in export
Date: Fri, 14 Mar 2014 16:01:10 +0100

Hello,

Jarmo Hurri <address@hidden> 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
>From 081bbb80b58d5e22c300ec22159570898ac5c0d3 Mon Sep 17 00:00:00 2001
From: Nicolas Goaziou <address@hidden>
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


reply via email to

[Prev in Thread] Current Thread [Next in Thread]