emacs-orgmode
[Top][All Lists]
Advanced

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

Re: [O] [bug, patch, ox] INCLUDE and footnotes


From: Rasmus
Subject: Re: [O] [bug, patch, ox] INCLUDE and footnotes
Date: Mon, 22 Dec 2014 23:11:37 +0100
User-agent: Gnus/5.13 (Gnus v5.13) Emacs/25.0.50 (gnu/linux)

Hi,

I fixed the nitpicks, but no major changes.

Nicolas Goaziou <address@hidden> writes:

> Pleonasm.
>
> Note that the regexp can match even if not at a footnote reference [...]:

Fair enough.

> In a thousand years, scholars might debate over the secret meaning
> behind these symbols.

Let's hope so!  In the meantime i will let the user shoot herself in the
foot at specify wrong labels.

>>> This marker is not necessary since you're not going to add contents
>>> before (point-min) anyway. A plain number is enough.
>>
>> I might if I include *Bar here:
>>
>> * Foo
>> [1] foo
>>
>> * Bar
>> Baz[1]
>
> I'm not sure to understand. Would you mind elaborating?

If I have #+INCLUDE: "example-above.org::*Bar" then point-min of the
include area will be pushed forward by four since the definition of [1] is
changed to fn:1-1 or something like that.  So min-marker should be a
marker.  Or I'm misunderstanding something.

> The more I look at it, the more I'm seduced by
>
>       (unless included
>       (org-with-wide-buffer
>        (goto-char (point-max))
>        (maphash (lambda (ref def) (insert (format "\n[%s] %s\n" ref def)))
>                 footnotes)))))))))))
>
> I'm really nitpicking, tho.

Since it's soon Christmas, so I could perhaps accommodate.

>>      ;; Append ID to all footnote references and definitions, so they
>>      ;; become file specific and cannot collide with footnotes in other
>>      ;; included files.
>> +    ;; Further, collect relevant footnotes outside of LINES.
>
> You can include it in the previous paragraph, or insert a blank comment
> line, as it wouldn't survive a M-q.

Let's M-q it then.

>> +            (goto-char (1+ (org-element-property :begin reference)))
>> +            (when label
>
> Shouldn't these two lines be inverted?

Sure that's prettier.

Cheers,
Rasmus

-- 
ツ
>From 2382ee420c97a801560dff3e9bea343bca83dc13 Mon Sep 17 00:00:00 2001
From: rasmus <address@hidden>
Date: Tue, 9 Dec 2014 12:40:52 +0100
Subject: [PATCH 1/2] ox.el: Fix footnote-bug in #+INCLUDE-keyword

* ox.el (org-export--prepare-file-contents): Preserve footnotes
when using the LINES argument.  New optional argument FOOTNOTES.
 (org-export-expand-include-keyword): New optional argument
 FOOTNOTES.
* test-ox.el (test-org-export/expand-include): Add test for INCLUDE
  with :lines and footnotes.
---
 lisp/ox.el              | 94 +++++++++++++++++++++++++++++++++++--------------
 testing/lisp/test-ox.el | 32 +++++++++++++++--
 2 files changed, 97 insertions(+), 29 deletions(-)

diff --git a/lisp/ox.el b/lisp/ox.el
index 9d9e794..60f06cc 100644
--- a/lisp/ox.el
+++ b/lisp/ox.el
@@ -3052,17 +3052,20 @@ locally for the subtree through node properties."
                   (car key)
                   (if (org-string-nw-p val) (format " %s" val) ""))))))))
 
-(defun org-export-expand-include-keyword (&optional included dir)
+(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."
+paths.  Optional argument FOOTNOTES is a hash-table used for
+storing and resolving footnotes.  It is created automatically."
   (let ((case-fold-search t)
        (file-prefix (make-hash-table :test #'equal))
-       (current-prefix 0))
+       (current-prefix 0)
+       (footnotes (or footnotes (make-hash-table :test #'equal))))
     (goto-char (point-min))
+    ;; Expand INCLUDE keywords.
     (while (re-search-forward "^[ \t]*#\\+INCLUDE:" nil t)
       (let ((element (save-match-data (org-element-at-point))))
        (when (eq (org-element-type element) 'keyword)
@@ -3155,15 +3158,23 @@ paths."
                               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 (incf current-prefix) file-prefix)))))
+                     (insert (org-export--prepare-file-contents
+                             file lines ind minlevel
+                             (or (gethash file file-prefix)
+                                 (puthash file (incf current-prefix) 
file-prefix))
+                             footnotes)))
                   (org-export-expand-include-keyword
                    (cons (list file lines) included)
-                   (file-name-directory file))
-                  (buffer-string)))))))))))))
+                   (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 (ref def) (insert (format "\n[%s] %s\n" ref 
def)))
+                         footnotes)))))))))))
 
 (defun org-export--inclusion-absolute-lines (file location only-contents lines)
   "Resolve absolute lines for an included file with file-link.
@@ -3227,8 +3238,8 @@ Return a string of lines to be included in the format 
expected by
                       (while (< (point) end) (incf counter) (forward-line))
                       counter))))))))
 
-(defun org-export--prepare-file-contents (file &optional lines ind minlevel id)
-  "Prepare the contents of FILE for inclusion and return them as a string.
+(defun org-export--prepare-file-contents (file &optional lines ind minlevel id 
footnotes)
+  "Prepare contents of FILE for inclusion and return it as a string.
 
 When optional argument LINES is a string specifying a range of
 lines, include only those lines.
@@ -3242,11 +3253,14 @@ headline encountered.
 Optional argument MINLEVEL, when non-nil, is an integer
 specifying the level that any top-level headline in the included
 file should have.
-
 Optional argument ID is an integer that will be inserted before
 each footnote definition and reference if FILE is an Org file.
 This is useful to avoid conflicts when more than one Org file
-with footnotes is included in a document."
+with footnotes is included in a document.
+
+Optional argument FOOTNOTES is a hash-table to store footnotes in
+the included document.
+"
   (with-temp-buffer
     (insert-file-contents file)
     (when lines
@@ -3307,20 +3321,46 @@ with footnotes is included in a document."
                             (insert (make-string offset ?*)))))))))))
     ;; Append ID to all footnote references and definitions, so they
     ;; become file specific and cannot collide with footnotes in other
-    ;; included files.
+    ;; included files.  Further, collect relevant footnotes outside of
+    ;; LINES.
     (when id
-      (goto-char (point-min))
-      (while (re-search-forward org-footnote-re nil t)
-       (let ((reference (org-element-context)))
-         (when (memq (org-element-type reference)
-                     '(footnote-reference footnote-definition))
-           (goto-char (org-element-property :begin reference))
-           (forward-char)
-           (let ((label (org-element-property :label reference)))
-             (cond ((not label))
-                   ((org-string-match-p "\\`[0-9]+\\'" label)
-                    (insert (format "fn:%d-" id)))
-                   (t (forward-char 3) (insert (format "%d-" id)))))))))
+      (let ((marker-min (point-min-marker))
+           (marker-max (point-max-marker)))
+       (goto-char (point-min))
+       (while (re-search-forward org-footnote-re nil t)
+         (let ((reference (org-element-context)))
+           (when (eq (org-element-type reference) 'footnote-reference)
+             (let* ((label (org-element-property :label reference))
+                    (digit-label (and label (org-string-match-p "\\`[0-9]+\\'" 
label))))
+               ;; Update the footnote-reference at point and collect
+               ;; the new label, which is only used for footnotes
+               ;; outsides LINES.
+               (when label
+                 ;; If label is akin to [1] convert it to [fn:ID-1].
+                 ;; Otherwise add "ID-" after "fn:".
+                 (goto-char (1+ (org-element-property :begin reference)))
+                 (if digit-label (insert (format "fn:%d-" id))
+                   (forward-char 3)
+                   (insert (format "%d-" id)))
+                 (unless (eq (org-element-property :type reference) 'inline)
+                   (org-with-wide-buffer
+                    (let* ((definition (org-footnote-get-definition label))
+                           (beginning (line-beginning-position)))
+                      (goto-char (1+ beginning))
+                      ;; Update label cf. above.  Necessary when
+                      ;; including whole files.
+                      (if digit-label (insert (format "fn:%d-" id))
+                        (forward-char 3)
+                        (insert (format "%d-" id)))
+                      ;; Store footnotes outside of LINES.
+                      (when (or (< beginning marker-min) (> beginning 
marker-max))
+                        (puthash
+                         (buffer-substring (goto-char (1+ beginning))
+                                           (1- (search-forward "]")))
+                         (org-element-normalize-string (nth 3 definition))
+                         footnotes))))))))))
+       (set-marker marker-min nil)
+       (set-marker marker-max nil)))
     (org-element-normalize-string (buffer-string))))
 
 (defun org-export-execute-babel-code ()
diff --git a/testing/lisp/test-ox.el b/testing/lisp/test-ox.el
index 9a0e787..37e2e23 100644
--- a/testing/lisp/test-ox.el
+++ b/testing/lisp/test-ox.el
@@ -904,12 +904,13 @@ Footnotes[fn:1], [fn:test] and [fn:inline:anonymous 
footnote].
                        (org-element-property :label ref)))))))))))))
   ;; Footnotes labels are not local to each include keyword.
   (should
-   (= 3
+   (= 4
       (length
        (delete-dups
        (let ((contents "
-Footnotes[fn:1], [fn:test] and [fn:inline:anonymous footnote].
+Footnotes[fn:1], [fn:test], [2] and [fn:inline:anonymous footnote].
 \[fn:1] Footnote 1
+\[2] Footnote 2
 \[fn:test] Footnote \"test\""))
          (org-test-with-temp-text-in-file contents
            (let ((file (buffer-file-name)))
@@ -919,6 +920,33 @@ Footnotes[fn:1], [fn:test] and [fn:inline:anonymous 
footnote].
                (org-element-map (org-element-parse-buffer)
                    'footnote-reference
                  (lambda (ref) (org-element-property :label ref)))))))))))
+  ;; Footnotes are supported by :lines-like elements and unnecessary
+  ;; footnotes are dropped.
+  (should
+   (= 4
+      (length
+       (delete-dups
+       (let ((contents "
+* foo
+Footnotes[fn:1]
+* bar
+Footnotes[fn:2], foot[fn:test], digit only[3], and [fn:inline:anonymous 
footnote]
+
+\[fn:1] Footnote 1
+\[fn:2] Footnote 1
+* Footnotes
+\[fn:test] Footnote \"test\"
+\[3] Footnote 3
+"))
+         (org-test-with-temp-text-in-file contents
+           (let ((file (buffer-file-name)))
+             (org-test-with-temp-text
+                 (format "#+INCLUDE: \"%s::*bar\"
+" file)
+               (org-export-expand-include-keyword)
+               (org-element-map (org-element-parse-buffer)
+                   'footnote-definition
+                 (lambda (ref) (org-element-property :label ref)))))))))))
   ;; If only-contents is non-nil only include contents of element.
   (should
    (equal
-- 
2.2.1


reply via email to

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