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.
This commit is contained in:
Carsten Dominik 2009-01-03 09:03:04 +01:00
parent 3559b2dc93
commit 2b2c603903
2 changed files with 95 additions and 36 deletions

View File

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

View File

@ -42,6 +42,7 @@
(declare-function org-mark-ring-push "org" (&optional pos buffer)) (declare-function org-mark-ring-push "org" (&optional pos buffer))
(declare-function outline-next-heading "outline") (declare-function outline-next-heading "outline")
(declare-function org-trim "org" (s)) (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-back-to-heading "org" (&optional invisible-ok))
(declare-function org-end-of-subtree "org" (&optional invisible-ok to-heading)) (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 outline node. If can also be the name of a special outline heading
under which footnotes should be put. under which footnotes should be put.
This variable defines the place where Org puts the definition 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 If this is a string, during export, all subtrees starting with this
heading will be removed after extracting footnote definitions." heading will be removed after extracting footnote definitions."
:group 'org-footnotes :group 'org-footnotes
:type '(choice :type '(choice
(string :tag "Special outline node name") (string :tag "Collect fotnotes under heading")
(const :tag "Define footnotes in the current outline node" nil))) (const :tag "Define footnotes locally" nil)))
(defcustom org-footnote-tag-for-non-org-mode-files "Footnotes:" (defcustom org-footnote-tag-for-non-org-mode-files "Footnotes:"
"Tag marking the beginning of footnote section. "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 "Offer automatic [fn:N] for editing" confirm)
(const :tag "Create automatic [N]" plain))) (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 () (defun org-footnote-at-reference-p ()
"Is the cursor at a footnote reference? "Is the cursor at a footnote reference?
If yes, return the beginning position, the label, and the definition, if local." 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 (cond
((org-mode-p) ((org-mode-p)
(if (not org-footnote-section) (if (not org-footnote-section)
;; No section, put foornote into the curren outline node ;; No section, put footnote into the current outline node
nil nil
;; Try to find or make the special node ;; Try to find or make the special node
(setq re (concat "^\\*+[ \t]+" org-footnote-section "[ \t]*$")) (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)) (goto-char (point-max))
(insert "\n\n* " org-footnote-section))) (insert "\n\n* " org-footnote-section)))
;; Now go to the end of this entry and insert there. ;; Now go to the end of this entry and insert there.
(outline-next-heading) (org-footnote-goto-local-insertion-point))
(setq p (point))
(skip-chars-backward " \t\n\r")
(delete-region (point) p))
(t (t
(setq re (concat "^" org-footnote-tag-for-non-org-mode-files "[ \t]*$")) (setq re (concat "^" org-footnote-tag-for-non-org-mode-files "[ \t]*$"))
(unless (re-search-forward re nil 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)) (delete-region (point) (point-max))
(insert org-footnote-tag-for-non-org-mode-files "\n")) (insert org-footnote-tag-for-non-org-mode-files "\n"))
(goto-char (point-max)) (goto-char (point-max))
(skip-chars-backward " \t\r\n") (skip-chars-backward " \t\r\n")))
(delete-region (point) (point-max)))) (insert "\n\n")
(insert "\n\n\n")
(backward-char 1)
(insert "[" label "] ") (insert "[" label "] ")
(message "Edit definition and go back with `C-c &' or, if unique, with `C-c C-c'."))) (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 When SORT-ONLY is set, only sort the footnote definitions into the
referenced sequence." referenced sequence."
;; This is based on Paul's function, but rewritten. ;; 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) ins-point)
(save-excursion (save-excursion
;; Now find footnote references, ;; Now find footnote references, and extract the definitions
(goto-char (point-min)) (goto-char (point-min))
(while (re-search-forward org-footnote-re nil t) (while (re-search-forward org-footnote-re nil t)
(org-if-unprotected (org-if-unprotected
(setq def (match-string 4) (setq def (match-string 4)
idef def
ref (or (match-string 1) (match-string 2)) ref (or (match-string 1) (match-string 2))
before (char-to-string (char-after (match-beginning 0)))) before (char-to-string (char-after (match-beginning 0))))
(if (equal ref "fn:") (setq ref nil)) (if (equal ref "fn:") (setq ref nil))
(if (and ref (setq a (assoc ref ref-table))) (if (and ref (setq a (assoc ref ref-table)))
(progn
(setq marker (nth 1 a)) (setq marker (nth 1 a))
(unless (nth 2 a) (setf (caddr a) def)))
(setq marker (number-to-string (incf count)))) (setq marker (number-to-string (incf count))))
(save-match-data (save-match-data
(if def (if def
@ -337,8 +345,7 @@ referenced sequence."
(save-excursion (save-excursion
(if (not (re-search-forward (concat "^\\[" (regexp-quote ref) (if (not (re-search-forward (concat "^\\[" (regexp-quote ref)
"\\]") nil t)) "\\]") nil t))
(setq def (setq def nil)
(format "FOOTNOTE DEFINITION NOT FOUND: %s" ref))
(setq beg (match-beginning 0)) (setq beg (match-beginning 0))
(setq beg1 (match-end 0)) (setq beg1 (match-end 0))
(re-search-forward (re-search-forward
@ -346,7 +353,11 @@ referenced sequence."
nil 'move) nil 'move)
(setq def (buffer-substring beg1 (match-beginning 0))) (setq def (buffer-substring beg1 (match-beginning 0)))
(delete-region beg (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)))) (if (not a) (push (list ref marker def) ref-table))))
;; First find and remove the footnote section ;; First find and remove the footnote section
@ -358,7 +369,7 @@ referenced sequence."
(concat "^\\*[ \t]+" (regexp-quote org-footnote-section) (concat "^\\*[ \t]+" (regexp-quote org-footnote-section)
"[ \t]*$") "[ \t]*$")
nil t)) nil t))
(if for-preprocessor (if (or for-preprocessor (not org-footnote-section))
(replace-match "") (replace-match "")
(org-back-to-heading t) (org-back-to-heading t)
(forward-line 1) (forward-line 1)
@ -386,19 +397,62 @@ referenced sequence."
(goto-char (or ins-point (point-max))) (goto-char (or ins-point (point-max)))
(setq ref-table (reverse ref-table)) (setq ref-table (reverse ref-table))
(when sort-only (when sort-only
;; remove anonymous fotnotes from the list
(setq ref-table (setq ref-table
(delq nil (mapcar (delq nil (mapcar
(lambda (x) (and (car x) (lambda (x) (and (car x)
(not (equal (car x) "fn:")) (not (equal (car x) "fn:"))
x)) x))
ref-table)))) ref-table))))
;; Make sure each footnote has a description, or an error message.
(setq ref-table
(mapcar
(lambda (x)
(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 (setq def
(mapconcat (mapconcat
(lambda (x) (lambda (x)
(format "[%s] %s" (nth (if sort-only 0 1) x) (format "[%s] %s" (nth (if sort-only 0 1) x)
(org-trim (nth 2 x)))) (org-trim (nth 2 x))))
ref-table "\n\n")) ref-table "\n\n"))
(if ref-table (insert "\n" def "\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) (defun org-footnote-delete (&optional label)
"Delete the footnote at point. "Delete the footnote at point.