]> code.delx.au - gnu-emacs/blobdiff - lisp/org/org-footnote.el
Update copyright year to 2016
[gnu-emacs] / lisp / org / org-footnote.el
index 5587e3eaa9465cba6ed32d507f60a02116c27e23..a25afee97f1edcc183450436fbf1230c7360b5da 100644 (file)
@@ -1,11 +1,10 @@
 ;;; org-footnote.el --- Footnote support in Org and elsewhere
 ;;
-;; Copyright (C) 2009, 2010 Free Software Foundation, Inc.
+;; Copyright (C) 2009-2016 Free Software Foundation, Inc.
 ;;
 ;; Author: Carsten Dominik <carsten at orgmode dot org>
 ;; Keywords: outlines, hypermedia, calendar, wp
 ;; Homepage: http://orgmode.org
-;; Version: 7.7
 ;;
 ;; This file is part of GNU Emacs.
 ;;
 (require 'org-macs)
 (require 'org-compat)
 
+(declare-function message-point-in-header-p "message" ())
+(declare-function org-back-over-empty-lines "org" ())
+(declare-function org-back-to-heading "org" (&optional invisible-ok))
 (declare-function org-combine-plists "org" (&rest plists))
+(declare-function org-end-of-subtree "org"  (&optional invisible-ok to-heading))
+(declare-function org-fill-paragraph "org" (&optional justify))
+(declare-function org-icompleting-read "org" (&rest args))
+(declare-function org-id-uuid "org-id" ())
+(declare-function org-in-block-p "org" (names))
 (declare-function org-in-commented-line "org" ())
 (declare-function org-in-indented-comment-line "org" ())
 (declare-function org-in-regexp "org" (re &optional nlines visually))
-(declare-function org-in-block-p "org" (names))
-(declare-function org-mark-ring-push "org" (&optional pos buffer))
-(declare-function outline-next-heading "outline")
-(declare-function org-trim "org" (s))
-(declare-function org-show-context "org" (&optional key))
-(declare-function org-back-to-heading "org" (&optional invisible-ok))
-(declare-function org-end-of-subtree "org"  (&optional invisible-ok to-heading))
 (declare-function org-in-verbatim-emphasis "org" ())
+(declare-function org-inside-LaTeX-fragment-p "org" ())
 (declare-function org-inside-latex-macro-p "org" ())
-(declare-function org-id-uuid "org" ())
-(declare-function org-fill-paragraph "org" (&optional justify))
-(declare-function org-export-preprocess-string "org-exp"
-                 (string &rest parameters))
+(declare-function org-mark-ring-push "org" (&optional pos buffer))
+(declare-function org-show-context "org" (&optional key))
+(declare-function org-trim "org" (s))
+(declare-function org-skip-whitespace "org" ())
+(declare-function outline-next-heading "outline")
+(declare-function org-skip-whitespace "org" ())
 
-(defvar org-outline-regexp-bol) ; defined in org.el
-(defvar org-odd-levels-only) ;; defined in org.el
-(defvar org-bracket-link-regexp) ; defined in org.el
-(defvar message-signature-separator) ;; defined in message.el
+(defvar org-outline-regexp-bol)                ; defined in org.el
+(defvar org-odd-levels-only)           ; defined in org.el
+(defvar org-bracket-link-regexp)       ; defined in org.el
+(defvar message-cite-prefix-regexp)    ; defined in message.el
+(defvar message-signature-separator)   ; defined in message.el
 
 (defconst org-footnote-re
   ;; Only [1]-like footnotes are closed in this regexp, as footnotes
   ;; their definition.
   ;;
   ;; `org-re' is used for regexp compatibility with XEmacs.
-  (org-re (concat "\\[\\(?:"
-                 ;; Match inline footnotes.
-                 "fn:\\([-_[:word:]]+\\)?:\\|"
-                 ;; Match other footnotes.
-                 "\\(?:\\([0-9]+\\)\\]\\)\\|"
-                 "\\(fn:[-_[:word:]]+\\)"
-                 "\\)"))
+  (concat "\\[\\(?:"
+         ;; Match inline footnotes.
+         (org-re "fn:\\([-_[:word:]]+\\)?:\\|")
+         ;; Match other footnotes.
+         "\\(?:\\([0-9]+\\)\\]\\)\\|"
+         (org-re "\\(fn:[-_[:word:]]+\\)")
+         "\\)")
   "Regular expression for matching footnotes.")
 
 (defconst org-footnote-definition-re
-  (org-re "^\\(\\[\\([0-9]+\\|fn:[-_[:word:]]+\\)\\]\\)")
+  (org-re "^\\[\\([0-9]+\\|fn:[-_[:word:]]+\\)\\]")
   "Regular expression matching the definition of a footnote.")
 
-(defvar org-footnote-forbidden-blocks '("example" "verse" "src" "ascii" "beamer"
-                                       "docbook" "html" "latex" "odt")
+(defconst org-footnote-forbidden-blocks
+  '("ascii" "beamer" "comment" "example" "html" "latex" "odt" "src")
   "Names of blocks where footnotes are not allowed.")
 
 (defgroup org-footnote nil
   :group 'org)
 
 (defcustom org-footnote-section "Footnotes"
-  "Outline heading containing footnote definitions before export.
-This can be nil, to place footnotes locally at the end of the current
-outline node.  If can also be the name of a special outline heading
-under which footnotes should be put.
+  "Outline heading containing footnote definitions.
+
+This can be nil, to place footnotes locally at the end of the
+current outline node.  If can also be the name of a special
+outline heading under which footnotes should be put.
+
 This variable defines the place where Org puts the definition
-automatically, i.e. when creating the footnote, and when sorting the notes.
-However, by hand you may place definitions *anywhere*.
-If this is a string, during export, all subtrees starting with this
-heading will be removed after extracting footnote definitions."
+automatically, i.e. when creating the footnote, and when sorting
+the notes.  However, by hand you may place definitions
+*anywhere*.
+
+If this is a string, during export, all subtrees starting with
+this heading will be ignored."
   :group 'org-footnote
   :type '(choice
          (string :tag "Collect footnotes under heading")
@@ -106,13 +114,17 @@ heading will be removed after extracting footnote definitions."
 
 (defcustom org-footnote-tag-for-non-org-mode-files "Footnotes:"
   "Tag marking the beginning of footnote section.
-The Org-mode footnote engine can be used in arbitrary text files as well
-as in Org-mode.  Outside Org-mode, new footnotes are always placed at
+The Org footnote engine can be used in arbitrary text files as well
+as in Org-mode.  Outside Org mode, new footnotes are always placed at
 the end of the file.  When you normalize the notes, any line containing
 only this tag will be removed, a new one will be inserted at the end
-of the file, followed by the collected and normalized footnotes."
+of the file, followed by the collected and normalized footnotes.
+
+If you don't want any tag in such buffers, set this variable to nil."
   :group 'org-footnote
-  :type 'string)
+  :type '(choice
+         (string :tag "Collect footnotes under tag")
+         (const :tag "Don't use a tag" nil)))
 
 (defcustom org-footnote-define-inline nil
   "Non-nil means define footnotes inline, at reference location.
@@ -126,13 +138,13 @@ will be used to define the footnote at the reference position."
   "Non-nil means define automatically new labels for footnotes.
 Possible values are:
 
-nil        prompt the user for each label
-t          create unique labels of the form [fn:1], [fn:2], ...
-confirm    like t, but let the user edit the created value.  In particular,
-           the label can be removed from the minibuffer, to create
+nil        Prompt the user for each label.
+t          Create unique labels of the form [fn:1], [fn:2], etc.
+confirm    Like t, but let the user edit the created value.
+           The label can be removed from the minibuffer to create
            an anonymous footnote.
 random    Automatically generate a unique, random label.
-plain      Automatically create plain number labels like [1]"
+plain      Automatically create plain number labels like [1]."
   :group 'org-footnote
   :type '(choice
          (const :tag "Prompt for label" nil)
@@ -154,6 +166,7 @@ The main values of this variable can be set with in-buffer options:
 #+STARTUP: nofnadjust"
   :group 'org-footnote
   :type '(choice
+         (const :tag "No adjustment" nil)
          (const :tag "Renumber" renumber)
          (const :tag "Sort" sort)
          (const :tag "Renumber and Sort" t)))
@@ -171,8 +184,9 @@ extracted will be filled again."
   (save-match-data
     (not (or (org-in-commented-line)
             (org-in-indented-comment-line)
-            (org-in-verbatim-emphasis)
+            (org-inside-LaTeX-fragment-p)
             ;; Avoid literal example.
+            (org-in-verbatim-emphasis)
             (save-excursion
               (beginning-of-line)
               (looking-at "[ \t]*:[ \t]+"))
@@ -194,13 +208,13 @@ positions, and the definition, when inlined."
             (or (looking-at org-footnote-re)
                 (org-in-regexp org-footnote-re)
                 (save-excursion (re-search-backward org-footnote-re nil t)))
-            ;; Only inline footnotes can start at bol.
-            (or (eq (char-before (match-end 0)) 58)
-                (/= (match-beginning 0) (point-at-bol))))
+            (/= (match-beginning 0) (point-at-bol)))
     (let* ((beg (match-beginning 0))
-          (label (or (match-string 2) (match-string 3)
+          (label (or (org-match-string-no-properties 2)
+                     (org-match-string-no-properties 3)
                      ;; Anonymous footnotes don't have labels
-                     (and (match-string 1) (concat "fn:" (match-string 1)))))
+                     (and (match-string 1)
+                          (concat "fn:" (org-match-string-no-properties 1)))))
           ;; Inline footnotes don't end at (match-end 0) as
           ;; `org-footnote-re' stops just after the second colon.
           ;; Find the real ending with `scan-sexps', so Org doesn't
@@ -217,55 +231,53 @@ positions, and the definition, when inlined."
                                 (org-in-regexp org-bracket-link-regexp))))
                          (and linkp (< (point) (cdr linkp))))))
                 ;; Verify point doesn't belong to a LaTeX macro.
-                ;; Beware though, when two footnotes are side by
-                ;; side, once the first one is changed into LaTeX,
-                ;; the second one might then be considered as an
-                ;; optional argument of the command.  Thus, check
-                ;; the `org-protected' property of that command.
-                (or (not (org-inside-latex-macro-p))
-                    (and (get-text-property (1- beg) 'org-protected)
-                         (not (get-text-property beg 'org-protected)))))
+                (not (org-inside-latex-macro-p)))
        (list label beg end
              ;; Definition: ensure this is an inline footnote first.
              (and (or (not label) (match-string 1))
-                  (org-trim (buffer-substring (match-end 0) (1- end)))))))))
+                  (org-trim (buffer-substring-no-properties
+                             (match-end 0) (1- end)))))))))
 
 (defun org-footnote-at-definition-p ()
-  "Is the cursor at a footnote definition?
+  "Is point within a footnote definition?
 
-This matches only pure definitions like [1] or [fn:name] at the beginning
-of a line.  It does not match references like [fn:name:definition], where the
-footnote text is included and defined locally.
+This matches only pure definitions like [1] or [fn:name] at the
+beginning of a line.  It does not match references like
+[fn:name:definition], where the footnote text is included and
+defined locally.
 
-The return value will be nil if not at a footnote definition, and a list with
-label, start, end and definition of the footnote otherwise."
-  (when (org-footnote-in-valid-context-p)
+The return value will be nil if not at a footnote definition, and
+a list with label, start, end and definition of the footnote
+otherwise."
+  (when (save-excursion (beginning-of-line) (org-footnote-in-valid-context-p))
     (save-excursion
       (end-of-line)
-      (let ((lim (save-excursion (re-search-backward
-                                 (concat org-outline-regexp-bol
-                                         "\\|^[ \t]*$") nil t))))
+      ;; Footnotes definitions are separated by new headlines, another
+      ;; footnote definition or 2 blank lines.
+      (let ((lim (save-excursion
+                  (re-search-backward
+                   (concat org-outline-regexp-bol
+                           "\\|^\\([ \t]*\n\\)\\{2,\\}") nil t))))
        (when (re-search-backward org-footnote-definition-re lim t)
-         (end-of-line)
-         (list (match-string 2)
-               (match-beginning 0)
-               (save-match-data
-                 ;; In a message, limit search to signature.
-                 (let ((bound (and (derived-mode-p 'message-mode)
-                                   (save-excursion
-                                     (goto-char (point-max))
-                                     (re-search-backward
-                                      message-signature-separator nil t)))))
-                   (or (and (re-search-forward
-                             (org-re
-                              (concat "^[ \t]*$" "\\|"
-                                      org-outline-regexp-bol
-                                      "\\|"
-                                      "^\\[\\([0-9]+\\|fn:[-_[:word:]]+\\)\\]"))
-                             bound 'move)
-                            (progn (skip-chars-forward " \t\n") (point-at-bol)))
-                       (point))))
-               (org-trim (buffer-substring (match-end 0) (point)))))))))
+         (let ((label (org-match-string-no-properties 1))
+               (beg (match-beginning 0))
+               (beg-def (match-end 0))
+               ;; In message-mode, do not search after signature.
+               (end (let ((bound (and (derived-mode-p 'message-mode)
+                                      (save-excursion
+                                        (goto-char (point-max))
+                                        (re-search-backward
+                                         message-signature-separator nil t)))))
+                      (if (progn
+                            (end-of-line)
+                            (re-search-forward
+                             (concat org-outline-regexp-bol "\\|"
+                                     org-footnote-definition-re "\\|"
+                                     "^\\([ \t]*\n\\)\\{2,\\}") bound 'move))
+                          (match-beginning 0)
+                        (point)))))
+           (list label beg end
+                 (org-trim (buffer-substring-no-properties beg-def end)))))))))
 
 (defun org-footnote-get-next-reference (&optional label backward limit)
   "Return complete reference of the next footnote.
@@ -295,10 +307,11 @@ LIMIT is the buffer position bounding the search.
 Return value is a list like those provided by
 `org-footnote-at-reference-p' or `org-footnote-at-definition-p'.
 If no footnote is found, return nil."
-  (let* (ref)
+  (let* (ref (origin (point)))
     (catch 'exit
       (while t
        (unless (re-search-forward org-footnote-re limit t)
+         (goto-char origin)
          (throw 'exit nil))
        ;; Beware: with [1]-like footnotes point will be just after
        ;; the closing square bracket.
@@ -320,19 +333,21 @@ If no footnote is found, return nil."
         (re (format "^\\[%s\\]\\|.\\[%s:" label label))
         pos)
     (save-excursion
-      (when (or (re-search-forward re nil t)
-               (and (goto-char (point-min))
-                    (re-search-forward re nil t))
-               (and (progn (widen) t)
-                    (goto-char (point-min))
-                    (re-search-forward re nil t)))
-       (let ((refp (org-footnote-at-reference-p)))
-         (cond
-          ((and (nth 3 refp) refp))
-          ((org-footnote-at-definition-p))))))))
+      (save-restriction
+       (when (or (re-search-forward re nil t)
+                 (and (goto-char (point-min))
+                      (re-search-forward re nil t))
+                 (and (progn (widen) t)
+                      (goto-char (point-min))
+                      (re-search-forward re nil t)))
+         (let ((refp (org-footnote-at-reference-p)))
+           (cond
+            ((and (nth 3 refp) refp))
+            ((org-footnote-at-definition-p)))))))))
 
 (defun org-footnote-goto-definition (label)
-  "Move point to the definition of the footnote LABEL."
+  "Move point to the definition of the footnote LABEL.
+Return a non-nil value when a definition has been found."
   (interactive "sLabel: ")
   (org-mark-ring-push)
   (let ((def (org-footnote-get-definition label)))
@@ -342,7 +357,9 @@ If no footnote is found, return nil."
       (looking-at (format "\\[%s\\]\\|\\[%s:" label label))
       (goto-char (match-end 0))
       (org-show-context 'link-search)
-      (message "Edit definition and go back with `C-c &' or, if unique, with `C-c C-c'."))))
+      (when (derived-mode-p 'org-mode)
+       (message "Edit definition and go back with `C-c &' or, if unique, with `C-c C-c'."))
+      t)))
 
 (defun org-footnote-goto-previous-reference (label)
   "Find the first closest (to point) reference of footnote with label LABEL."
@@ -406,7 +423,12 @@ and value definition."
 
 (defun org-footnote-unique-label (&optional current)
   "Return a new unique footnote label.
-The returns the firsts fn:N labels that is currently not used."
+
+The function returns the first \"fn:N\" or \"N\" label that is
+currently not used.
+
+Optional argument CURRENT is the list of labels active in the
+buffer."
   (unless current (setq current (org-footnote-all-labels)))
   (let ((fmt (if (eq org-footnote-auto-label 'plain) "%d" "fn:%d"))
        (cnt 1))
@@ -414,21 +436,18 @@ The returns the firsts fn:N labels that is currently not used."
       (incf cnt))
     (format fmt cnt)))
 
-(defvar org-footnote-label-history nil
-  "History of footnote labels entered in current buffer.")
-(make-variable-buffer-local 'org-footnote-label-history)
-
 (defun org-footnote-new ()
   "Insert a new footnote.
 This command prompts for a label.  If this is a label referencing an
 existing label, only insert the label.  If the footnote label is empty
 or new, let the user edit the definition of the footnote."
   (interactive)
-  (unless (and (not (bolp)) (org-footnote-in-valid-context-p))
+  (unless (org-footnote-in-valid-context-p)
     (error "Cannot insert a footnote here"))
-  (let* ((labels (and (not (equal org-footnote-auto-label 'random))
-                     (org-footnote-all-labels)))
-        (propose (org-footnote-unique-label labels))
+  (let* ((lbls (and (not (equal org-footnote-auto-label 'random))
+                   (org-footnote-all-labels)))
+        (propose (and (not (equal org-footnote-auto-label 'random))
+                      (org-footnote-unique-label lbls)))
         (label
          (org-footnote-normalize-label
           (cond
@@ -438,16 +457,16 @@ or new, let the user edit the definition of the footnote."
             (require 'org-id)
             (substring (org-id-uuid) 0 8))
            (t
-            (completing-read
+            (org-icompleting-read
              "Label (leave empty for anonymous): "
-             (mapcar 'list labels) nil nil
-             (if (eq org-footnote-auto-label 'confirm) propose nil)
-             'org-footnote-label-history))))))
+             (mapcar 'list lbls) nil nil
+             (if (eq org-footnote-auto-label 'confirm) propose nil)))))))
     (cond
+     ((bolp) (error "Cannot create a footnote reference at left margin"))
      ((not label)
       (insert "[fn:: ]")
       (backward-char 1))
-     ((member label labels)
+     ((member label lbls)
       (insert "[" label "]")
       (message "New reference to existing note"))
      (org-footnote-define-inline
@@ -459,51 +478,81 @@ or new, let the user edit the definition of the footnote."
       (org-footnote-create-definition label)
       (org-footnote-auto-adjust-maybe)))))
 
+(defvar org-blank-before-new-entry) ; silence byte-compiler
 (defun org-footnote-create-definition (label)
   "Start the definition of a footnote with label LABEL."
   (interactive "sLabel: ")
-  (let ((label (org-footnote-normalize-label label)))
+  (let ((label (org-footnote-normalize-label label))
+       electric-indent-mode) ;; Prevent wrong indentation
     (cond
-     ((org-mode-p)
-      ;; No section, put footnote into the current outline node Try to
-      ;; find or make the special node
+     ;; In an Org file.
+     ((derived-mode-p 'org-mode)
+      ;; If `org-footnote-section' is defined, find it, or create it
+      ;; at the end of the buffer.
       (when org-footnote-section
        (goto-char (point-min))
        (let ((re (concat "^\\*+[ \t]+" org-footnote-section "[ \t]*$")))
          (unless (or (re-search-forward re nil t)
                      (and (progn (widen) t)
                           (re-search-forward re nil t)))
-         (goto-char (point-max))
-         (insert "\n\n* " org-footnote-section "\n"))))
-      ;; Now go to the end of this entry and insert there.
+           (goto-char (point-max))
+           (skip-chars-backward " \t\r\n")
+           (unless (bolp) (newline))
+           ;; Insert new section.  Separate it from the previous one
+           ;; with a blank line, unless `org-blank-before-new-entry'
+           ;; explicitly says no.
+           (when (and (cdr (assq 'heading org-blank-before-new-entry))
+                      (zerop (save-excursion (org-back-over-empty-lines))))
+             (insert "\n"))
+           (insert "* " org-footnote-section "\n"))))
+      ;; Move to the end of this entry (which may be
+      ;; `org-footnote-section' or the current one).
       (org-footnote-goto-local-insertion-point)
       (org-show-context 'link-search))
      (t
       ;; In a non-Org file.  Search for footnote tag, or create it if
-      ;; necessary (at the end of buffer, or before a signature if in
+      ;; specified (at the end of buffer, or before signature if in
       ;; Message mode).  Set point after any definition already there.
-      (let ((tag (concat "^" org-footnote-tag-for-non-org-mode-files "[ \t]*$"))
-           (max (save-excursion
-                  (if (and (derived-mode-p 'message-mode)
-                           (re-search-forward
-                            message-signature-separator nil t))
-                      (copy-marker (point-at-bol) t)
-                    (copy-marker (point-max) t)))))
+      (let ((tag (and org-footnote-tag-for-non-org-mode-files
+                     (concat "^" (regexp-quote
+                                  org-footnote-tag-for-non-org-mode-files)
+                             "[ \t]*$")))
+           (max (if (and (derived-mode-p 'message-mode)
+                         (goto-char (point-max))
+                         (re-search-backward
+                          message-signature-separator nil t))
+                    (progn
+                      ;; Ensure one blank line separates last
+                      ;; footnote from signature.
+                      (beginning-of-line)
+                      (open-line 2)
+                      (point-marker))
+                  (point-max-marker))))
+       (set-marker-insertion-type max t)
        (goto-char max)
-       (unless (re-search-backward tag nil t)
+       ;; Check if the footnote tag is defined but missing.  In this
+       ;; case, insert it, before any footnote or one blank line
+       ;; after any previous text.
+       (when (and tag (not (re-search-backward tag nil t)))
          (skip-chars-backward " \t\r\n")
-         (delete-region (point) max)
-         (insert "\n\n" org-footnote-tag-for-non-org-mode-files "\n"))
-       ;; Skip existing footnotes.
-       (while (re-search-forward org-footnote-definition-re max t))
-       (let ((def (org-footnote-at-definition-p)))
-         (when def (goto-char (nth 2 def))))
+         (while (re-search-backward org-footnote-definition-re nil t))
+         (unless (bolp) (newline 2))
+         (insert org-footnote-tag-for-non-org-mode-files "\n\n"))
+       ;; Remove superfluous white space and clear marker.
+       (goto-char max)
+       (skip-chars-backward " \t\r\n")
+       (delete-region (point) max)
+       (unless (bolp) (newline))
        (set-marker max nil))))
-    ;; Insert footnote label, position point and notify user.
-    (unless (bolp) (insert "\n"))
-    (insert "\n[" label "] \n")
+    ;; Insert footnote label.
+    (when (zerop (org-back-over-empty-lines)) (newline))
+    (insert "[" label "] \n")
     (backward-char)
-    (message "Edit definition and go back with `C-c &' or, if unique, with `C-c C-c'.")))
+    ;; Only notify user about next possible action when in an Org
+    ;; buffer, as the bindings may have different meanings otherwise.
+    (when (derived-mode-p 'org-mode)
+      (message
+       "Edit definition and go back with `C-c &' or, if unique, with `C-c C-c'."))))
 
 ;;;###autoload
 (defun org-footnote-action (&optional special)
@@ -549,38 +598,15 @@ With prefix arg SPECIAL, offer additional commands in a menu."
       (org-footnote-goto-previous-reference (car tmp)))
      (t (org-footnote-new)))))
 
-(defvar org-footnote-insert-pos-for-preprocessor 'point-max
-  "See `org-footnote-normalize'.")
-
-(defvar org-export-footnotes-seen nil) ; silence byte-compiler
-(defvar org-export-footnotes-data nil) ; silence byte-compiler
-
 ;;;###autoload
-(defun org-footnote-normalize (&optional sort-only export-props)
+(defun org-footnote-normalize (&optional sort-only)
   "Collect the footnotes in various formats and normalize them.
 
 This finds the different sorts of footnotes allowed in Org, and
-normalizes them to the usual [N] format that is understood by the
-Org-mode exporters.
+normalizes them to the usual [N] format.
 
 When SORT-ONLY is set, only sort the footnote definitions into the
-referenced sequence.
-
-If Org is amidst an export process, EXPORT-PROPS will hold the
-export properties of the buffer.
-
-When EXPORT-PROPS is non-nil, the default action is to insert
-normalized footnotes towards the end of the pre-processing buffer.
-Some exporters like docbook, odt, etc. expect that footnote
-definitions be available before any references to them.  Such
-exporters can let bind `org-footnote-insert-pos-for-preprocessor' to
-symbol 'point-min to achieve the desired behaviour.
-
-Additional note on `org-footnote-insert-pos-for-preprocessor':
-1. This variable has not effect when FOR-PREPROCESSOR is nil.
-2. This variable (potentially) obviates the need for extra scan
-   of pre-processor buffer as witnessed in
-   `org-export-docbook-get-footnotes'."
+referenced sequence."
   ;; This is based on Paul's function, but rewritten.
   ;;
   ;; Re-create `org-with-limited-levels', but not limited to Org
@@ -590,17 +616,12 @@ Additional note on `org-footnote-insert-pos-for-preprocessor':
               org-inlinetask-min-level
               (1- org-inlinetask-min-level)))
         (nstars (and limit-level
-                     (if org-odd-levels-only
-                         (and limit-level (1- (* limit-level 2)))
+                     (if org-odd-levels-only (1- (* limit-level 2))
                        limit-level)))
         (org-outline-regexp
          (concat "\\*" (if nstars (format "\\{1,%d\\} " nstars) "+ ")))
-        ;; Determine the highest marker used so far.
-        (ref-table (when export-props org-export-footnotes-seen))
-        (count (if (and export-props ref-table)
-                   (apply 'max (mapcar (lambda (e) (nth 1 e)) ref-table))
-                 0))
-        ins-point ref)
+        (count 0)
+        ins-point ref ref-table)
     (save-excursion
       ;; 1. Find every footnote reference, extract the definition, and
       ;;    collect that data in REF-TABLE.  If SORT-ONLY is nil, also
@@ -608,6 +629,7 @@ Additional note on `org-footnote-insert-pos-for-preprocessor':
       (goto-char (point-min))
       (while (setq ref (org-footnote-get-next-reference))
        (let* ((lbl (car ref))
+              (pos (nth 1 ref))
               ;; When footnote isn't anonymous, check if it's label
               ;; (REF) is already stored in REF-TABLE.  In that case,
               ;; extract number used to identify it (MARKER).  If
@@ -621,77 +643,60 @@ Additional note on `org-footnote-insert-pos-for-preprocessor':
          ;; Replace footnote reference with [MARKER].  Maybe fill
          ;; paragraph once done.  If SORT-ONLY is non-nil, only move
          ;; to the end of reference found to avoid matching it twice.
-         ;; If EXPORT-PROPS isn't nil, also add `org-footnote'
-         ;; property to it, so it can be easily recognized by
-         ;; exporters.
-         (if sort-only
-             (goto-char (nth 2 ref))
+         (if sort-only (goto-char (nth 2 ref))
            (delete-region (nth 1 ref) (nth 2 ref))
            (goto-char (nth 1 ref))
-           (let ((new-ref (format "[%d]" marker)))
-             (when export-props (org-add-props new-ref '(org-footnote t)))
-             (insert new-ref))
+           (insert (format "[%d]" marker))
            (and inlinep
                 org-footnote-fill-after-inline-note-extraction
                 (org-fill-paragraph)))
-         ;; Add label (REF), identifier (MARKER) and definition (DEF)
-         ;; to REF-TABLE if data was unknown.
+         ;; Add label (REF), identifier (MARKER), definition (DEF)
+         ;; type (INLINEP) and position (POS) to REF-TABLE if data
+         ;; was unknown.
          (unless a
-           (let ((def (or (nth 3 ref)  ; inline
-                          (and export-props
-                               (cdr (assoc lbl org-export-footnotes-data)))
+           (let ((def (or (nth 3 ref)  ; Inline definition.
                           (nth 3 (org-footnote-get-definition lbl)))))
-             (push (list lbl marker
-                         ;; When exporting, each definition goes
-                         ;; through `org-export-preprocess-string' so
-                         ;; it is ready to insert in the
-                         ;; backend-specific buffer.
-                         (if export-props
-                             (let ((parameters
-                                    (org-combine-plists
-                                     export-props
-                                     '(:todo-keywords t :tags t :priority t))))
-                               (org-export-preprocess-string def parameters))
-                           def)
-                         inlinep) ref-table)))
-         ;; Remove definition of non-inlined footnotes.
-         (unless inlinep (org-footnote-delete-definitions lbl))))
+             (push (list lbl marker def
+                         ;; Reference beginning position is a marker
+                         ;; to preserve it during further buffer
+                         ;; modifications.
+                         inlinep (copy-marker pos)) ref-table)))))
       ;; 2. Find and remove the footnote section, if any.  Also
       ;;    determine where footnotes shall be inserted (INS-POINT).
-      (goto-char (point-min))
       (cond
-       ((org-mode-p)
-       (if (and org-footnote-section
-                (re-search-forward
-                 (concat "^\\*[ \t]+" (regexp-quote org-footnote-section)
-                         "[ \t]*$")
-                 nil t))
-           (progn
-             (setq ins-point (match-beginning 0))
-             (delete-region (match-beginning 0) (org-end-of-subtree t)))
-         (setq ins-point (point-max))))
+       ((and org-footnote-section (derived-mode-p 'org-mode))
+       (goto-char (point-min))
+       (if (re-search-forward
+            (concat "^\\*[ \t]+" (regexp-quote org-footnote-section)
+                    "[ \t]*$") nil t)
+           (delete-region (match-beginning 0) (org-end-of-subtree t t)))
+       ;; A new footnote section is inserted by default at the end of
+       ;; the buffer.
+       (goto-char (point-max))
+       (skip-chars-backward " \r\t\n")
+       (forward-line)
+       (unless (bolp) (newline)))
+       ;; No footnote section set: Footnotes will be added at the end
+       ;; of the section containing their first reference.
+       ((derived-mode-p 'org-mode))
        (t
-       (when (re-search-forward
-              (concat "^"
-                      (regexp-quote org-footnote-tag-for-non-org-mode-files)
-                      "[ \t]*$")
-              nil t)
-         (replace-match ""))
-       ;; In message-mode, ensure footnotes are inserted before the
+       ;; Remove any left-over tag in the buffer, if one is set up.
+       (when org-footnote-tag-for-non-org-mode-files
+         (let ((tag (concat "^" (regexp-quote
+                                 org-footnote-tag-for-non-org-mode-files)
+                            "[ \t]*$")))
+           (goto-char (point-min))
+           (while (re-search-forward tag nil t)
+             (replace-match "")
+             (delete-region (point) (progn (forward-line) (point))))))
+       ;; In Message mode, ensure footnotes are inserted before the
        ;; signature.
-       (let ((pt-max
-              (or (and (derived-mode-p 'message-mode)
-                       (save-excursion
-                         (goto-char (point-max))
-                         (re-search-backward
-                          message-signature-separator nil t)
-                         (1- (point))))
-                  (point-max))))
-         (goto-char pt-max)
-         (skip-chars-backward " \t\n\r")
-         (forward-line)
-         (delete-region (point) pt-max))
-       (setq ins-point (point))))
+       (if (and (derived-mode-p 'message-mode)
+                (goto-char (point-max))
+                (re-search-backward message-signature-separator nil t))
+           (beginning-of-line)
+         (goto-char (point-max)))))
+      (setq ins-point (point-marker))
       ;; 3. Clean-up REF-TABLE.
       (setq ref-table
            (delq nil
@@ -699,64 +704,69 @@ Additional note on `org-footnote-insert-pos-for-preprocessor':
                   (lambda (x)
                     (cond
                      ;; When only sorting, ignore inline footnotes.
-                     ((and sort-only (nth 3 x)) nil)
+                     ;; Also clear position marker.
+                     ((and sort-only (nth 3 x))
+                      (set-marker (nth 4 x) nil) nil)
                      ;; No definition available: provide one.
                      ((not (nth 2 x))
-                      (append (butlast x 2)
-                              (list (format "DEFINITION NOT FOUND: %s" (car x))
-                                    (nth 3 x))))
+                      (append
+                       (list (car x) (nth 1 x)
+                             (format "DEFINITION NOT FOUND: %s" (car x)))
+                       (nthcdr 3 x)))
                      (t x)))
                   ref-table)))
       (setq ref-table (nreverse ref-table))
-      ;; 4. Insert the footnotes again in the buffer, at the
+      ;; 4. Remove left-over definitions in the buffer.
+      (mapc (lambda (x)
+             (unless (nth 3 x) (org-footnote-delete-definitions (car x))))
+           ref-table)
+      ;; 5. Insert the footnotes again in the buffer, at the
       ;;    appropriate spot.
-      (goto-char (or
-                 (and export-props
-                      (eq org-footnote-insert-pos-for-preprocessor 'point-min)
-                      (point-min))
-                 ins-point
-                 (point-max)))
+      (goto-char ins-point)
       (cond
        ;; No footnote: exit.
        ((not ref-table))
        ;; Cases when footnotes should be inserted in one place.
-       ((or (not (org-mode-p))
-           org-footnote-section
-           (not sort-only))
-       ;; Insert again the section title.
-       (cond
-        ((not (org-mode-p))
-         (insert "\n\n" org-footnote-tag-for-non-org-mode-files "\n"))
-        ((and org-footnote-section (not export-props))
-         (or (bolp) (insert "\n"))
-         (insert "* " org-footnote-section "\n")))
-       ;; Insert the footnotes.
-       (insert "\n"
-               (mapconcat (lambda (x) (format "[%s] %s"
-                                         (nth (if sort-only 0 1) x) (nth 2 x)))
-                          ref-table "\n\n")
-               "\n\n")
-       ;; When exporting, add newly inserted markers along with their
-       ;; associated definition to `org-export-footnotes-seen'.
-       (when export-props
-         (setq org-export-footnotes-seen ref-table)))
-       ;; Else, insert each definition at the end of the section
-       ;; containing their first reference.  Happens only in Org files
-       ;; with no special footnote section, and only when doing
-       ;; sorting.
-       (t (mapc 'org-insert-footnote-reference-near-definition
-               ref-table))))))
-
-(defun org-insert-footnote-reference-near-definition (entry)
-  "Find first reference of footnote ENTRY and insert the definition there.
-ENTRY is (fn-label num-mark definition)."
-  (when (car entry)
-    (goto-char (point-min))
-    (let ((ref (org-footnote-get-next-reference (car entry))))
-      (when ref
-       (goto-char (nth 2 ref))
-       (org-footnote-goto-local-insertion-point)
-       (insert (format "\n[%s] %s\n" (car entry) (nth 2 entry)))))))
+       ((or (not (derived-mode-p 'org-mode)) org-footnote-section)
+       ;; Insert again the section title, if any.  Ensure that title,
+       ;; or the subsequent footnotes, will be separated by a blank
+       ;; lines from the rest of the document.  In an Org buffer,
+       ;; separate section with a blank line, unless explicitly
+       ;; stated in `org-blank-before-new-entry'.
+       (if (not (derived-mode-p 'org-mode))
+           (progn (skip-chars-backward " \t\n\r")
+                  (delete-region (point) ins-point)
+                  (unless (bolp) (newline))
+                  (when org-footnote-tag-for-non-org-mode-files
+                    (insert "\n" org-footnote-tag-for-non-org-mode-files "\n")))
+         (when (and (cdr (assq 'heading org-blank-before-new-entry))
+                    (zerop (save-excursion (org-back-over-empty-lines))))
+           (insert "\n"))
+         (insert "* " org-footnote-section "\n"))
+       (set-marker ins-point nil)
+       ;; Insert the footnotes, separated by a blank line.
+       (insert
+        (mapconcat
+         (lambda (x)
+           ;; Clean markers.
+           (set-marker (nth 4 x) nil)
+           (format "\n[%s] %s" (nth (if sort-only 0 1) x) (nth 2 x)))
+         ref-table "\n"))
+       (unless (eobp) (insert "\n\n")))
+       ;; Each footnote definition has to be inserted at the end of
+       ;; the section where its first reference belongs.
+       (t
+       (mapc
+        (lambda (x)
+          (let ((pos (nth 4 x)))
+            (goto-char pos)
+            ;; Clean marker.
+            (set-marker pos nil))
+          (org-footnote-goto-local-insertion-point)
+          (insert (format "\n[%s] %s\n"
+                          (if sort-only (car x) (nth 1 x))
+                          (nth 2 x))))
+        ref-table))))))
 
 (defun org-footnote-goto-local-insertion-point ()
   "Find insertion point for footnote, just before next outline heading."
@@ -765,7 +775,7 @@ ENTRY is (fn-label num-mark definition)."
   (beginning-of-line 0)
   (while (and (not (bobp)) (= (char-after) ?#))
     (beginning-of-line 0))
-  (if (looking-at "[ \t]*#\\+TBLFM:") (beginning-of-line 2))
+  (if (let ((case-fold-search t)) (looking-at "[ \t]*#\\+tblfm:")) (beginning-of-line 2))
   (end-of-line 1)
   (skip-chars-backward "\n\r\t ")
   (forward-line))
@@ -791,8 +801,13 @@ Return the number of footnotes removed."
          (ndef 0))
       (while (re-search-forward def-re nil t)
        (let ((full-def (org-footnote-at-definition-p)))
-         (delete-region (nth 1 full-def) (nth 2 full-def)))
-       (incf ndef))
+         (when full-def
+           ;; Remove the footnote, and all blank lines before it.
+           (goto-char (nth 1 full-def))
+           (skip-chars-backward " \r\t\n")
+           (unless (bolp) (forward-line))
+           (delete-region (point) (nth 2 full-def))
+           (incf ndef))))
       ndef)))
 
 (defun org-footnote-delete (&optional label)
@@ -807,7 +822,7 @@ If LABEL is non-nil, delete that footnote instead."
           (label (cond
                   ;; LABEL is provided as argument.
                   (label)
-                  ;; Footnote reference at point. If the footnote is
+                  ;; Footnote reference at point.  If the footnote is
                   ;; anonymous, delete it and exit instead.
                   ((setq x (org-footnote-at-reference-p))
                    (or (car x)
@@ -831,20 +846,21 @@ If LABEL is non-nil, delete that footnote instead."
 (defun org-footnote-renumber-fn:N ()
   "Renumber the simple footnotes like fn:17 into a sequence in the document."
   (interactive)
-  (let (map i (n 0))
-    (save-excursion
-      (save-restriction
-       (widen)
-       (goto-char (point-min))
-       (while (re-search-forward "\\[fn:\\([0-9]+\\)[]:]" nil t)
-         (setq i (string-to-number (match-string 1)))
-         (when (and (string-match "\\S-" (buffer-substring
-                                          (point-at-bol) (match-beginning 0)))
-                    (not (assq i map)))
-           (push (cons i (number-to-string (incf n))) map)))
-       (goto-char (point-min))
-       (while (re-search-forward "\\(\\[fn:\\)\\([0-9]+\\)\\([]:]\\)" nil t)
-         (replace-match (concat "\\1" (cdr (assq (string-to-number (match-string 2)) map)) "\\3")))))))
+  (let (map (n 0))
+    (org-with-wide-buffer
+     (goto-char (point-min))
+     (while (re-search-forward "\\[fn:\\([0-9]+\\)[]:]" nil t)
+       (save-excursion
+        (goto-char (match-beginning 0))
+        ;; Ensure match is a footnote reference or definition.
+        (when (save-match-data (if (bolp)
+                                   (org-footnote-at-definition-p)
+                                 (org-footnote-at-reference-p)))
+          (let ((new-val (or (cdr (assoc (match-string 1) map))
+                             (number-to-string (incf n)))))
+            (unless (assoc (match-string 1) map)
+              (push (cons (match-string 1) new-val) map))
+            (replace-match new-val nil nil nil 1))))))))
 
 (defun org-footnote-auto-adjust-maybe ()
   "Renumber and/or sort footnotes according to user settings."
@@ -862,6 +878,8 @@ If LABEL is non-nil, delete that footnote instead."
 
 (provide 'org-footnote)
 
-
+;; Local variables:
+;; generated-autoload-file: "org-loaddefs.el"
+;; End:
 
 ;;; org-footnote.el ends here