瀏覽代碼

Footnotes: When sorting footnotes, respect the location settings.

Sorting footnotes used to be almost like normalization, in that all
footnotes would be collected into a single location.  Now sorting
respects the setting of `org-footnote-section'.  If that is nil,
sorting will actually move each footnote into the outline node of its
first reference.
Carsten Dominik 16 年之前
父節點
當前提交
2b2c603903
共有 2 個文件被更改,包括 95 次插入36 次删除
  1. 14 9
      doc/org.texi
  2. 81 27
      lisp/org-footnote.el

+ 14 - 9
doc/org.texi

@@ -1415,20 +1415,25 @@ for details.
 @table @kbd
 @kindex C-c C-x f
 @item C-c C-x f
-The footnote action command.  When the cursor is on a footnote reference,
-jump to the definition.  When it is at a definition, jump to the (first)
-reference.  Otherwise, create a new footnote.  Depending on the variable
+The footnote action command.
+
+When the cursor is on a footnote reference, jump to the definition.  When it
+is at a definition, jump to the (first) reference.
+
+Otherwise, create a new footnote.  Depending on the variable
 @code{org-footnote-define-inline}@footnote{The corresponding in-buffer
 setting is: @code{#+STARTUP: fninline} or @code{#+STARTUP: nofninline}}, the
-definitions will be placed locally, or into the nearest outline section with
-the heading @samp{Footnotes}.  If no such section is found after the
-reference point, one will be created at the end of the file.@* When this
-command is called with a prefix argument, a menu of additional options is
-offered:
+definition will be placed right into the text as part of the reference, or
+separately into the location determined by the variable
+@code{org-footnote-section}.
+
+When this command is called with a prefix argument, a menu of additional
+options is offered:
 @example
 s   @r{Sort the footnote definitions by reference sequence.  During editing,}
     @r{Org makes no effort to sort footnote definitions into a particular}
-    @r{sequence.  If you want them sorted, use this command.}
+    @r{sequence.  If you want them sorted, use this command, which will}
+    @r{also move entries according to @code{org-footnote-section}.}
 n   @r{Normalize the footnotes by collecting all definitions (including}
     @r{inline definitions) into a special section, and then numbering them}
     @r{in sequence.  The references will then also be numbers.  This is}

+ 81 - 27
lisp/org-footnote.el

@@ -42,6 +42,7 @@
 (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))
 
@@ -66,13 +67,14 @@ 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.  However, by hand you may place definitions *anywhere*.
+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."
   :group 'org-footnotes
   :type '(choice
-	  (string :tag "Special outline node name")
-	  (const :tag "Define footnotes in the current outline node" nil)))
+	  (string :tag "Collect fotnotes under heading")
+	  (const :tag "Define footnotes locally" nil)))
 
 (defcustom org-footnote-tag-for-non-org-mode-files "Footnotes:"
   "Tag marking the beginning of footnote section.
@@ -109,6 +111,14 @@ plain      Automatically create plain number labels like [1]"
 	  (const :tag "Offer automatic [fn:N] for editing" confirm)
 	  (const :tag "Create automatic [N]" plain)))
 
+(defcustom org-footnote-fill-after-inline-note-extraction nil
+  "Non-nil means, fill paragraphs after extracting footnotes.
+When extracting inline footnotes, the lengths of lines can change a lot.
+When this option is set, paragraphs from which an inline footnote has been
+extracted will be filled again."
+  :group 'org-footnote
+  :type 'boolean)
+
 (defun org-footnote-at-reference-p ()
   "Is the cursor at a footnote reference?
 If yes, return the beginning position, the label, and the definition, if local."
@@ -249,7 +259,7 @@ or new, let the user edit the definition of the footnote."
     (cond
      ((org-mode-p)
       (if (not org-footnote-section)
-	  ;; No section, put foornote into the curren outline node
+	  ;; No section, put footnote into the current outline node
 	  nil
 	;; Try to find or make the special node
 	(setq re (concat "^\\*+[ \t]+" org-footnote-section "[ \t]*$"))
@@ -259,10 +269,7 @@ or new, let the user edit the definition of the footnote."
 	  (goto-char (point-max))
 	  (insert "\n\n* " org-footnote-section)))
       ;; Now go to the end of this entry and insert there.
-      (outline-next-heading)
-      (setq p (point))
-      (skip-chars-backward " \t\n\r")
-      (delete-region (point) p))
+      (org-footnote-goto-local-insertion-point))
      (t
       (setq re (concat "^" org-footnote-tag-for-non-org-mode-files "[ \t]*$"))
       (unless (re-search-forward re nil t)
@@ -272,10 +279,8 @@ or new, let the user edit the definition of the footnote."
 	(delete-region (point) (point-max))
 	(insert org-footnote-tag-for-non-org-mode-files "\n"))
       (goto-char (point-max))
-      (skip-chars-backward " \t\r\n")
-      (delete-region (point) (point-max))))
-    (insert "\n\n\n")
-    (backward-char 1)
+      (skip-chars-backward " \t\r\n")))
+    (insert "\n\n")
     (insert "[" label "] ")
     (message "Edit definition and go back with `C-c &' or, if unique, with `C-c C-c'.")))
 
@@ -317,19 +322,22 @@ Org-mode exporters.
 When SORT-ONLY is set, only sort the footnote definitions into the
 referenced sequence."
   ;; This is based on Paul's function, but rewritten.
-  (let ((count 0) ref def ref-table liste beg beg1 ref def marker a before
+  (let ((count 0) ref def idef ref-table liste beg beg1 marker a before
 	ins-point)
      (save-excursion
-      ;; Now find footnote references,
+      ;; Now find footnote references, and extract the definitions
       (goto-char (point-min))
       (while (re-search-forward org-footnote-re nil t)
 	(org-if-unprotected
 	 (setq def (match-string 4)
+	       idef def
 	       ref (or (match-string 1) (match-string 2))
 	       before (char-to-string (char-after (match-beginning 0))))
 	 (if (equal ref "fn:") (setq ref nil))
 	 (if (and ref (setq a (assoc ref ref-table)))
-	     (setq marker (nth 1 a))
+	     (progn
+	       (setq marker (nth 1 a))
+	       (unless (nth 2 a) (setf (caddr a) def)))
 	   (setq marker (number-to-string (incf count))))
 	 (save-match-data
 	   (if def
@@ -337,8 +345,7 @@ referenced sequence."
 	     (save-excursion
 	       (if (not (re-search-forward (concat "^\\[" (regexp-quote ref)
 						   "\\]") nil t))
-		   (setq def
-			 (format "FOOTNOTE DEFINITION NOT FOUND: %s" ref))
+		   (setq def nil)
 		 (setq beg (match-beginning 0))
 		 (setq beg1 (match-end 0))
 		 (re-search-forward
@@ -346,7 +353,11 @@ referenced sequence."
 		  nil 'move)
 		 (setq def (buffer-substring beg1 (match-beginning 0)))
 		 (delete-region beg (match-beginning 0))))))
-	 (unless sort-only (replace-match (concat before "[" marker "]")))
+	 (unless sort-only
+	   (replace-match (concat before "[" marker "]"))
+	   (and idef
+		org-footnote-fill-after-inline-note-extraction
+		(fill-paragraph)))
 	 (if (not a) (push (list ref marker def) ref-table))))
       
       ;; First find and remove the footnote section
@@ -358,7 +369,7 @@ referenced sequence."
 		  (concat "^\\*[ \t]+" (regexp-quote org-footnote-section)
 			  "[ \t]*$")
 		  nil t))
-	    (if for-preprocessor
+	    (if (or for-preprocessor (not org-footnote-section))
 		(replace-match "")
 	      (org-back-to-heading t)
 	      (forward-line 1)
@@ -381,24 +392,67 @@ referenced sequence."
 	(delete-region (point) (point-max))
 	(insert "\n\n" org-footnote-tag-for-non-org-mode-files "\n")
 	(setq ins-point (point))))
-
+      
       ;; Insert the footnotes again
       (goto-char (or ins-point (point-max)))
       (setq ref-table (reverse ref-table))
       (when sort-only
+	;; remove anonymous fotnotes from the list
 	(setq ref-table
 	      (delq nil (mapcar
 			 (lambda (x) (and (car x)
 					  (not (equal (car x) "fn:"))
 					  x))
 			 ref-table))))
-      (setq def
-	    (mapconcat
+      ;; Make sure each footnote has a description, or an error message.
+      (setq ref-table
+	    (mapcar
 	     (lambda (x)
-	       (format "[%s] %s" (nth (if sort-only 0 1) x)
-		       (org-trim (nth 2 x))))
-	     ref-table "\n\n"))
-      (if ref-table (insert "\n" def "\n\n")))))
+	       (if (not (nth 2 x))
+		   (setcar (cddr x)
+			   (format "FOOTNOTE DEFINITION NOT FOUND: %s" (car x)))
+		 (setcar (cddr x) (org-trim (nth 2 x))))
+	       x)
+	     ref-table))
+
+      (if (or (not (org-mode-p))     ; not an Org file
+	      org-footnote-section   ; we do not use a footnote section
+	      (not sort-only)	     ; this is normalization
+	      for-preprocessor)       ; the is the preprocessor
+	  ;; Insert the footnotes together in one place
+	  (progn
+	    (setq def
+		  (mapconcat
+		   (lambda (x)
+		     (format "[%s] %s" (nth (if sort-only 0 1) x)
+			     (org-trim (nth 2 x))))
+		   ref-table "\n\n"))
+	    (if ref-table (insert "\n" def "\n\n")))
+	;; Insert each footnote near the first reference
+	;; Happens only in Org files with no special footnote section,
+	;; and only when doing sorting
+	(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)
+    (let ((pos (point)))
+      (goto-char (point-min))
+      (when (re-search-forward (format ".\\[%s[]:]" (regexp-quote (car entry)))
+			       nil t)
+	(org-footnote-goto-local-insertion-point)
+	(insert (format "\n\n[%s] %s" (car entry) (nth 2 entry)))))))
+
+(defun org-footnote-goto-local-insertion-point ()
+  "Find insertion point for footnote, just before next outline heading."
+  (outline-next-heading)
+  (beginning-of-line 0)
+  (while (and (not (bobp)) (= (char-after) ?#))
+    (beginning-of-line 0))
+  (if (looking-at "#\\+TBLFM:") (beginning-of-line 2))
+  (skip-chars-backward "\n\r\t "))
 
 (defun org-footnote-delete (&optional label)
   "Delete the footnote at point.
@@ -439,4 +493,4 @@ and all references of a footnote label."
 (provide 'org-footnote)
 
 ;; arch-tag: 1b5954df-fb5d-4da5-8709-78d944dbfc37
-;;; org-footnote.el ends here
+;;; org-footnote.el ends here