Browse Source

org-footnote: allow non Org mode files to have no footnote tag

* lisp/org-footnote.el (org-footnote-tag-for-non-org-mode-files):
  notify the opportunity to set the variable to the empty string.
(org-footnote-normalize, org-footnote-create-definition): carefully
  check for inserted newlines and presence of the footnote
  tag.
Nicolas Goaziou 13 years ago
parent
commit
baf7dde28e
1 changed files with 111 additions and 65 deletions
  1. 111 65
      lisp/org-footnote.el

+ 111 - 65
lisp/org-footnote.el

@@ -39,24 +39,25 @@
 (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-export-preprocess-string "org-exp"
+		  (string &rest parameters))
+(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-macro-p "org" ())
-(declare-function org-id-uuid "org-id" ())
-(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 outline-next-heading "outline")
 
 (defvar org-outline-regexp-bol)		; defined in org.el
 (defvar org-odd-levels-only)		; defined in org.el
@@ -109,13 +110,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.
@@ -466,46 +471,71 @@ or new, let the user edit the definition of the footnote."
   (interactive "sLabel: ")
   (let ((label (org-footnote-normalize-label label)))
     (cond
+     ;; In an Org file.
      ((org-mode-p)
-      ;; No section, put footnote into the current outline node Try to
-      ;; find or make the special node
+      ;; 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))))
 	(goto-char max)
-	(unless (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))))
+	;; 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.
+	(save-excursion
+	  (when (and tag (not (re-search-backward tag nil t)))
+	    (skip-chars-backward " \t\r\n")
+	    (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.
+	(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")
-    (backward-char)
-    (message "Edit definition and go back with `C-c &' or, if unique, with `C-c C-c'.")))
+    ;; Insert footnote label.
+    (insert "\n[" label "] ")
+    ;; Only notify user about next possible action when in an Org
+    ;; buffer, as the bindings may have different meanings otherwise.
+    (when (org-mode-p)
+      (message
+       "Edit definition and go back with `C-c &' or, if unique, with `C-c C-c'."))))
 
 ;;;###autoload
 (defun org-footnote-action (&optional special)
@@ -672,28 +702,37 @@ Additional note on `org-footnote-insert-pos-for-preprocessor':
 	    (progn
 	      (setq ins-point (match-beginning 0))
 	      (delete-region (match-beginning 0) (org-end-of-subtree t)))
-	  (setq ins-point (point-max))))
+	  ;; Remove superfluous blank lines at the end of buffer.
+	  (goto-char (point-max))
+	  (skip-chars-backward " \r\t\n")
+	  (delete-region (point) (point-max))
+	  (unless (bolp) (newline))
+	  (setq ins-point (point))))
        (t
-	(when (re-search-forward
-	       (concat "^"
-		       (regexp-quote org-footnote-tag-for-non-org-mode-files)
-		       "[ \t]*$")
-	       nil t)
+	(when (and (not (equal org-footnote-tag-for-non-org-mode-files ""))
+		   (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
+	;; 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))))
+	(let ((pt-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))
+			(point-max))))
 	  (goto-char pt-max)
 	  (skip-chars-backward " \t\n\r")
-	  (forward-line)
 	  (delete-region (point) pt-max))
+	(unless (bolp) (newline))
 	(setq ins-point (point))))
       ;; 3. Clean-up REF-TABLE.
       (setq ref-table
@@ -726,19 +765,26 @@ Additional note on `org-footnote-insert-pos-for-preprocessor':
        ((or (not (org-mode-p))
 	    org-footnote-section
 	    (not sort-only))
-	;; Insert again the section title.
+	;; 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'.
 	(cond
 	 ((not (org-mode-p))
-	  (insert "\n\n" org-footnote-tag-for-non-org-mode-files "\n"))
+	  (unless (bolp) (newline))
+	  (when org-footnote-tag-for-non-org-mode-files
+	    (insert "\n" org-footnote-tag-for-non-org-mode-files "\n")))
 	 ((and org-footnote-section (not export-props))
-	  (or (bolp) (insert "\n"))
+	  (unless (bolp) (newline))
+	  (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")))
-	;; Insert the footnotes.
-	(insert "\n"
-		(mapconcat (lambda (x) (format "[%s] %s"
+	;; Insert the footnotes, separated by a blank line.
+	(insert (mapconcat (lambda (x) (format "\n[%s] %s"
 					  (nth (if sort-only 0 1) x) (nth 2 x)))
-			   ref-table "\n\n")
-		"\n\n")
+			   ref-table "\n"))
 	;; When exporting, add newly inserted markers along with their
 	;; associated definition to `org-export-footnotes-seen'.
 	(when export-props