[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
Re: [O] Moving footnotes
From: |
Nicolas Goaziou |
Subject: |
Re: [O] Moving footnotes |
Date: |
Sat, 31 May 2014 11:30:41 +0200 |
Bastien <address@hidden> writes:
> Nicolas Goaziou <address@hidden> writes:
>> All in all, I'm not convinced this should be a function provided in Org.
>
> Okay. Still, it's useful to have it *somewhere*. If you have a
> moment, could you revert the commit
Done.
> rewrite the function with the suggested enhancements
Here it is. It could be prettier but I think it should get the job done.
(defun org-footnote-inline-footnotes ()
"Convert external footnotes into inline ones."
(interactive)
(org-with-wide-buffer
(let ((random-labels (make-hash-table :test #'equal)) failed seen)
(goto-char (point-min))
(while (re-search-forward org-footnote-re nil t)
(let ((context (save-excursion (backward-char) (org-element-context))))
;; Ignore false positives.
(when (eq (org-element-type context) 'footnote-reference)
(let ((label (org-element-property :label context)))
;; Ignore anonymous footnotes.
(when label
(if (member label seen)
(let ((normalized-label (gethash label random-labels)))
(when normalized-label
(search-backward "[" nil t)
(forward-char)
(insert normalized-label)
(delete-region
(point)
(progn (skip-chars-forward "0-9") (point)))))
(push label seen)
(when (eq (org-element-property :type context) 'standard)
(let ((beg (copy-marker (org-element-property :begin
context)))
(end (copy-marker
(save-excursion
(goto-char (org-element-property :end context))
(skip-chars-backward " \t")
(point))))
(definition
(save-excursion
(goto-char (point-min))
(catch 'exit
(while (re-search-forward
(format "^\\[%s\\]" (regexp-quote label))
nil t)
(let ((def (save-excursion
(backward-char)
(org-element-at-point))))
(when (eq (org-element-type def)
'footnote-definition)
(let ((cbeg (org-element-property
:contents-begin def))
(cend (org-element-property
:contents-end def)))
;; Ensure definition can be inline,
;; i.e., contains a single
;; paragraph. Return nil if it
;; cannot.
(if (not cbeg) (throw 'exit "")
(goto-char cbeg)
(let ((contents
(org-element-at-point)))
(if (or (not (eq (org-element-type
contents) 'paragraph))
(< (org-element-property
:end contents) cend))
(throw 'exit nil)
(throw 'exit
(prog1 (org-trim
(buffer-substring cbeg cend))
(delete-region
(org-element-property
:begin def)
(org-element-property
:end def)))))))))))))))
(if (not definition) (push label failed)
(delete-region beg end)
(goto-char beg)
;; Convert [1] to [fn:random-id] to avoid
;; confusion between [1] and [fn:1].
(let ((normalized-label
(if (not (org-string-match-p "\\`[0-9]+\\'"
label))
label
(require 'org-id)
(puthash
label
(concat "fn:" (substring (org-id-uuid) 0 8))
random-labels))))
(insert "[" normalized-label ":" definition "]")))
(set-marker beg nil)
(set-marker end nil)))))))))
(cond (failed (user-error "Some footnotes could not be converted : %s"
(mapconcat #'identity failed ", ")))
;; If process completed without failure, there is no regular
;; footnote definition left, so we remove footnote sections,
;; if any.
(org-footnote-section
(goto-char (point-min))
(let ((section-re (concat "^\\*+ " org-footnote-section "[ \t]*$")))
(while (re-search-forward section-re nil t)
(delete-region (match-beginning 0) (org-end-of-subtree t t))))))
(message "Footnotes successfully inlined."))))
> and add it to worg/org-hacks.org?
I suggest to test it first.
> PS: I think it's useful to trigger the org-footnote-action menu
> when org-footnote-new cannot do anything useful.
Sure, I will add it back later today, unless you're faster than me.
Regards,
--
Nicolas Goaziou