From mboxrd@z Thu Jan 1 00:00:00 1970 Path: news.gmane.org!.POSTED!not-for-mail From: Boruch Baum Newsgroups: gmane.emacs.devel Subject: Re: [Footnote-mode]: alignment option [CODE included] Date: Sun, 17 Dec 2017 19:13:06 -0500 Message-ID: <20171218001306.mqycrkyhva7h5ivi@E15-2016.optimum.net> References: <20171207061801.6ym3aeukjl3arlmg@E15-2016.optimum.net> NNTP-Posting-Host: blaine.gmane.org Mime-Version: 1.0 Content-Type: multipart/mixed; boundary="silsinndhfqcm5vk" Content-Transfer-Encoding: 8bit X-Trace: blaine.gmane.org 1513555916 27732 195.159.176.226 (18 Dec 2017 00:11:56 GMT) X-Complaints-To: usenet@blaine.gmane.org NNTP-Posting-Date: Mon, 18 Dec 2017 00:11:56 +0000 (UTC) User-Agent: NeoMutt/20171208 To: Stefan Monnier , Emacs-Devel List Original-X-From: emacs-devel-bounces+ged-emacs-devel=m.gmane.org@gnu.org Mon Dec 18 01:11:52 2017 Return-path: Envelope-to: ged-emacs-devel@m.gmane.org Original-Received: from lists.gnu.org ([208.118.235.17]) by blaine.gmane.org with esmtp (Exim 4.84_2) (envelope-from ) id 1eQj26-0006T4-Dl for ged-emacs-devel@m.gmane.org; Mon, 18 Dec 2017 01:11:50 +0100 Original-Received: from localhost ([::1]:56061 helo=lists.gnu.org) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1eQj40-0002Ft-0H for ged-emacs-devel@m.gmane.org; Sun, 17 Dec 2017 19:13:48 -0500 Original-Received: from eggs.gnu.org ([2001:4830:134:3::10]:39503) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1eQj3m-0002Fh-6j for emacs-devel@gnu.org; Sun, 17 Dec 2017 19:13:36 -0500 Original-Received: from Debian-exim by eggs.gnu.org with spam-scanned (Exim 4.71) (envelope-from ) id 1eQj3i-00051q-Sr for emacs-devel@gnu.org; Sun, 17 Dec 2017 19:13:34 -0500 Original-Received: from mout.gmx.net ([212.227.17.21]:49764) by eggs.gnu.org with esmtps (TLS1.0:DHE_RSA_AES_128_CBC_SHA1:16) (Exim 4.71) (envelope-from ) id 1eQj3i-0004zQ-DN for emacs-devel@gnu.org; Sun, 17 Dec 2017 19:13:30 -0500 Original-Received: from E15-2016.optimum.net ([108.6.168.221]) by mail.gmx.com (mrgmx102 [212.227.17.174]) with ESMTPSA (Nemesis) id 0Lpgew-1eu2Gg2cw2-00fOyO; Mon, 18 Dec 2017 01:13:25 +0100 Content-Disposition: inline In-Reply-To: X-Provags-ID: V03:K0:PpuY50zw+aX4zMEnSNN8/rqLiuj27BUZxCfyfv6XMljOWmKDsha rBh+x+Hlr68S0JXYkAAp8KD6ryYMkH6dnV7wr0fhftXUJLDxLdkPcWMaqEwqm5Aj5QDBwDd ZGegLRwA6FwaU2rVICf7+D3K2BBONm9T+qxvwMEQwaQUR8A9I+HMbA4I7Oa5a7h+gTu5BDh hD0UnCqk1YrLjKM4zcUZw== X-UI-Out-Filterresults: notjunk:1;V01:K0:ELcZldjpxGE=:J66svsSwm5M5boDM/Ff7op b8yiG51w3xLVQ0yTGtgguqUrCcuFbIL/f9pe4P5272pD4tou9n4VznbdkdV+6ww/FEjPLgux4 13VrTjCTKcXMS1J4OTBCoKYGnmR4jUmA5H2Dte+/U2Z1YSeGMRXOoLUYcBH2GD51/LLeqxUh3 xvpgLfthR+u13pqjy2RM4FXrG0z6gTaFgxPiVen1UuZajxjYMFC0J5WK8MAmkiBV2yWAwdmnz Qvb/RvAKSsrGlUt4jo/rcnGxBe1QTIXXGCbTpIzLy8bwlIPy+O0yJbfmZ70m4wMPvKSXR8YUj u/FmogBwwTEWcjwjcJuVTqXyP2sePfrUQK0HZWpq8aiJtrgXwgi2MWG7uX5NVt3SJTnAR0GOJ evPNocIXOzNMJQC1IjDvBvd4Ko5+9L9NBC4FEq37KpK4vtX4ZOkvapz6AQqnUqrdaK3Xx8rKe YugRBtdyUoodSEW5mfj7ZSfvEXUGcZrV6Sk5VMBgo5BJOrJzUtIx6ugzLNVsxEzZx73ub/nBk gUEPOuZwJyF0/YA3G6fJEsOgbnfz/+GKztMcwZBny6uig/2N03Vmn/GslLG/O13L8RsSREb48 Oe55DAL6DwQJQdjMDr8ACt7bKGHCTUcnjK7lJ4vznKFSXlXaYwgjO5Sq5EMHorDuc4TkbQtLa TLQaRzox1YQLLpOfGfr1La6TxwCUOT9GGO3XTl/LBDwVrY1vDKEKXU7vsgBXonjI/wdHvvLMu KHwiU0KNBW1GTJUA+oyR344EBIL7T9fRMY4Efhab5IvPDteZvL4c5v4FmpYoF9E1Se3AXNDb X-detected-operating-system: by eggs.gnu.org: GNU/Linux 2.2.x-3.x [generic] [fuzzy] X-Received-From: 212.227.17.21 X-BeenThere: emacs-devel@gnu.org X-Mailman-Version: 2.1.21 Precedence: list List-Id: "Emacs development discussions." List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: emacs-devel-bounces+ged-emacs-devel=m.gmane.org@gnu.org Original-Sender: "Emacs-devel" Xref: news.gmane.org gmane.emacs.devel:221196 Archived-At: --silsinndhfqcm5vk Content-Type: text/plain; charset=us-ascii Content-Disposition: inline On 2017-12-16 10:05, Stefan Monnier wrote: > Have you seen my reply last week in emacs-devel? No. Thanks for contacting me off-list about it. >> The attached code allows one to left-justify footnote text from the >> first column of text, instead of from the left margin. I find this >> aesthetically preferable, especially when I have long footnotes. > Could you give some example of the difference? Sure. The current behavior is: [1] Lorem ipsum dolor sit amet, consectetuer adipiscing elit. Donec hendrerit tempor tellus. Donec pretium posuere tellus. Proin quam nisl, The proposed optional alternative is: [1] Lorem ipsum dolor sit amet, consectetuer adipiscing elit. Donec hendrerit tempor tellus. Donec pretium posuere tellus. Proin quam >> Of course, if one has visual-line-mode enabled, the auto-fill acts >> automatically. > Hmm... how does visual-line-mode pay attention to > Footnote-align-to-fn-text (and know if it's inside a footnote)? I double-checked, and I wrote incorrectly. > Some comments about the code: > > body-auto-fill-prefix is just a var into which we temporarily save > the normal fill-prefix. So this should be named with a "[Ff]ootnote-" > prefix (arguably with a "--" somewhere to make it clear it's an > internal variable), and it should be made buffer-local (so there's no > cross-buffer pollution). Done. Note that the file `footnote.el' currently has all its `Private variables' labeled without the "--" convention. > The more serious problem is that `fill-prefix' is set with no guarantee > it will be reset to its proper value later. E.g. if the user returns to > the body "manually" rather than via Footnote-back-to-message. Yes. Corrected. > I suggest you make this into a minor mode: Why a minor mode just for a small option of another minor mode? >> (defadvice Footnote-add-footnote (around abort-when-in-fn-area activate) > I don't see how this relates to this new alignment feature. You're correct. It was part of my personal configuration to address a bug that I had neglected to report, now emacs-bug#29756. UPDATE: ======= The updated code is attached, in two forms: 1) As a patch to the 25.2 version of footnote.el (ie. fully integrated into footnote mode without any need for advising, and; 2) As a snippet, with the feature's functions advised around the mode's current functions. -- hkp://keys.gnupg.net CA45 09B5 5351 7C11 A9D1 7286 0036 9E45 1595 8BC0 --silsinndhfqcm5vk Content-Type: text/x-diff; charset=us-ascii Content-Disposition: attachment; filename="footnote.patch" --- footnote.el 2017-12-17 18:40:22.940312994 -0500 +++ footnote.el_new 2017-12-17 19:00:27.713722813 -0500 @@ -131,6 +131,14 @@ has no effect on buffers already display :type 'regexp :group 'footnote) +(defcustom Footnote-align-to-fn-text t +"Nil if footnote text is to be aligned flush left with left side +of the footnote number. Non-nil if footnote text is to be aligned +left with the first character of footnote text." + :type 'boolean + :group 'footnote) +(make-variable-buffer-local 'Footnote-align-to-fn-text) + ;;; Private variables (defvar footnote-style-number nil @@ -148,6 +156,12 @@ has no effect on buffers already display (defvar footnote-mouse-highlight 'highlight "Text property name to enable mouse over highlight.") +(defvar Footnote--body-auto-fill-prefix nil +"When Footnmote mode modifies variable `fill-prefix', store the +prior value here, so that it can be restored when leaving the +footnote area.") +(make-variable-buffer-local 'Footnote--body-auto-fill-prefix) + ;;; Default styles ;;; NUMERIC (defconst footnote-numeric-regexp "[0-9]+" @@ -609,8 +623,72 @@ Return nil if the cursor is not over a f (or (get-text-property (point) 'footnote-number) (Footnote-text-under-cursor))) +(defun Footnote--calc-fn-alignment-column() +"Calculate the left alignment for footnote text." + (+ footnote-body-tag-spacing + (length + (concat footnote-start-tag footnote-end-tag + (Footnote-index-to-string + (caar (last footnote-text-marker-alist))))))) + +(defun Footnote--align-to-body() + (when (not Footnote-align-to-fn-text) + (setq fill-prefix Footnote--body-auto-fill-prefix) + (setq Footnote--body-auto-fill-prefix nil))) + +(defun Footnote--point-in-body-p() + "Return `t' if point is in the buffer text area, ie. before the beginning of +the footnote area." + ; NOTE: This code is shared with a patch I've proposed for emacs-bug#29756 + (let + ((p (point)) + (q (if (not footnote-text-marker-alist) (point-max) + (if (string-equal footnote-section-tag "") + (cdr (first footnote-text-marker-alist)) + (goto-char (cdr (first footnote-text-marker-alist))) + (if (re-search-backward + (concat "^" footnote-section-tag-regexp) nil t) + (match-beginning 0) + ; This `else' should never happen, and indicates an error, ie. footnotes + ; already exist and a footnote-section-tag is defined, but the section tag + ; hasn't been found. We choose to assume that the user deleted it + ; intentionally and wants us to behave in this buffer as if the section tag + ; was set "", so we do that, now. + (setq footnote-section-tag "") + ; HOWEVER: The rest of footnote mode does not currently honor or account + ; for this. + ; + ; To illustrate the difference in behavior, create a few footnotes, delete + ; the section tag, and create another footnote. Then undo, comment the + ; above line (that sets the tag to ""), re-evaluate this function, and repeat. + (cdr (first footnote-text-marker-alist)) + ))))) + (goto-char p) ; undo `re-search-backward' side-effect + (if (< p q) t nil))) + ;;; User functions +(defun Footnote-toggle-alignment() + "Change whether footnote text is aligned flush left with the +left of a footnote's number, or flush left with the first +character of footnote text on the footnote's first line." + (interactive) + (setq Footnote-align-to-fn-text (not Footnote-align-to-fn-text)) + (when footnote-text-marker-alist + (if (>= (point) (cdr (first footnote-text-marker-alist))) + (if Footnote-align-to-fn-text + (Footnote--align-to-fn) + (Footnote--align-to-body)))) + (if Footnote-align-to-fn-text + (message "Footnotes will left-align to footnote text") + (message "Footnotes will left-align to body text"))) + +(defun Footnote-fill-paragraph(&optional justify region) + (when (and (Footnote--point-in-body-p) Footnote--body-auto-fill-prefix) + (setq fill-prefix Footnote--body-auto-fill-prefix) + (setq Footnote--body-auto-fill-prefix nil)) + (fill-paragraph justify region)) + (defun Footnote-make-hole () (save-excursion (let ((i 0) @@ -661,7 +739,10 @@ by using `Footnote-back-to-message'." (Footnote-narrow-to-footnotes))) ;; Emacs/XEmacs bug? save-excursion doesn't restore point when using ;; insert-before-markers. - (goto-char opoint)))) + (goto-char opoint)) + (when Footnote-align-to-fn-text + (setq Footnote--body-auto-fill-prefix (or fill-prefix "")) + (setq fill-prefix (make-string (Footnote--calc-fn-alignment-column) 32))))) (defun Footnote-delete-footnote (&optional arg) "Delete a numbered footnote. @@ -767,7 +848,9 @@ being set it is automatically widened." (when note (when footnote-narrow-to-footnotes-when-editing (widen)) - (goto-char (cadr (assq note footnote-pointer-marker-alist)))))) + (goto-char (cadr (assq note footnote-pointer-marker-alist))) + (setq fill-prefix Footnote--body-auto-fill-prefix) + (setq Footnote--body-auto-fill-prefix nil)))) (defvar footnote-mode-map (let ((map (make-sparse-keymap))) @@ -778,6 +861,8 @@ being set it is automatically widened." (define-key map "g" 'Footnote-goto-footnote) (define-key map "r" 'Footnote-renumber-footnotes) (define-key map "s" 'Footnote-set-style) + (define-key map (kbd "M-q") 'Footnote-toggle-alignment) + (define-key map [remap fill-paragraph] 'Footnote-fill-paragraph) map)) (defvar footnote-minor-mode-map --silsinndhfqcm5vk Content-Type: text/plain; charset=utf-8 Content-Disposition: attachment; filename="footnote-snippet.el" Content-Transfer-Encoding: 8bit l;━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ ; Footnote behavior customization ; + left-align footnote text to first character of first paragraph, ; not to left margin. ; + Instructions: ; + toggle the feature using 'mode-map-prefix M-q' (usually 'C-c ! M-q') ; + whenever you run `auto-fill' (M-q), it will act ; + if you set visual-line-mode, it acts automatically (require 'footnote) (defcustom Footnote-align-to-fn-text t "Nil if footnote text is to be aligned flush left with left side of the footnote number. Non-nil if footnote text is to be aligned left with the first character of footnote text." :type 'boolean :group 'footnote) (make-variable-buffer-local 'Footnote-align-to-fn-text) (defvar Footnote--body-auto-fill-prefix nil "When Footnmote mode modifies variable `fill-prefix', store the prior value here, so that it can be restored when leaving the footnote area.") (make-variable-buffer-local 'Footnote--body-auto-fill-prefix) (defun Footnote--calc-fn-alignment-column() "Calculate the left alignment for footnote text." (+ footnote-body-tag-spacing (length (concat footnote-start-tag footnote-end-tag (Footnote-index-to-string (caar (last footnote-text-marker-alist))))))) (defun Footnote--align-to-fn() "For the purpose of this feature proposal (only), this function is an advice :after function `Footnote-add-footnote'. For implementation within emacs, the code would be included at the end of that function." ; TODO: If the length has changed, eg. when adding footnote [10] after having ; footnote [9], refresh all footnotes with new alignment. (when Footnote-align-to-fn-text (setq Footnote--body-auto-fill-prefix (or fill-prefix "")) (setq fill-prefix (make-string (Footnote--calc-fn-alignment-column) 32)))) (defun Footnote--align-to-body() (when (not Footnote-align-to-fn-text) (setq fill-prefix Footnote--body-auto-fill-prefix) (setq Footnote--body-auto-fill-prefix nil))) (defun Footnote--return-to-body(arg) "For the purpose of this feature proposal (only), this function is an advice :after function `Footnote-back-to-message'. For implementation within emacs, the code would be included at the end of that function." (setq fill-prefix Footnote--body-auto-fill-prefix) (setq Footnote--body-auto-fill-prefix nil)) (defun Footnote--point-in-body-p() "Return `t' if point is in the buffer text area, ie. before the beginning of the footnote area." ; NOTE: This code is shared with a patch I've proposed for emacs-bug#29756 (let ((p (point)) (q (if (not footnote-text-marker-alist) (point-max) (if (string-equal footnote-section-tag "") (cdr (first footnote-text-marker-alist)) (goto-char (cdr (first footnote-text-marker-alist))) (if (re-search-backward (concat "^" footnote-section-tag-regexp) nil t) (match-beginning 0) ; This `else' should never happen, and indicates an error, ie. footnotes ; already exist and a footnote-section-tag is defined, but the section tag ; hasn't been found. We choose to assume that the user deleted it ; intentionally and wants us to behave in this buffer as if the section tag ; was set "", so we do that, now. (setq footnote-section-tag "") ; HOWEVER: The rest of footnote mode does not currently honor or account ; for this. ; ; To illustrate the difference in behavior, create a few footnotes, delete ; the section tag, and create another footnote. Then undo, comment the ; above line (that sets the tag to ""), re-evaluate this function, and repeat. (cdr (first footnote-text-marker-alist)) ))))) (goto-char p) ; undo `re-search-backward' side-effect (if (< p q) t nil))) (defun Footnote--fill-paragraph-in-body(orig-function &optional justify region) "For the purpose of this feature proposal (only), this function is an advice :before function `fill-paragraph' to ensure that variable `fill-prefix' is correctly restored and maintained when dealing with footnotes potentially possessing a different `fill-prefix' value. This is meant to cover cases of the user manually returning to the buffer text from the footnote area instead of using the function `Footnote-back-to-message'. For the purpose of implementation within emacs, this function would be a remap of `fill-paragraph', specific to the `Footnote-mode' minor mode." (when (and footnote-mode (Footnote--point-in-body-p) Footnote--body-auto-fill-prefix) (setq fill-prefix Footnote--body-auto-fill-prefix) (setq Footnote--body-auto-fill-prefix nil))) (defun Footnote-toggle-alignment() "Change whether footnote text is aligned flush left with the left of a footnote's number, or flush left with the first character of footnote text on the footnote's first line." (interactive) (setq Footnote-align-to-fn-text (not Footnote-align-to-fn-text)) (when footnote-text-marker-alist (if (>= (point) (cdr (first footnote-text-marker-alist))) (if Footnote-align-to-fn-text (Footnote--align-to-fn) (Footnote--align-to-body)))) (if Footnote-align-to-fn-text (message "Footnotes will left-align to footnote text") (message "Footnotes will left-align to body text"))) (define-key footnote-mode-map (kbd "M-q") 'Footnote-toggle-alignment) (advice-add 'Footnote-add-footnote :after #'Footnote--align-to-fn) (advice-add 'Footnote-back-to-message :after #'Footnote--return-to-body) (advice-add 'fill-paragraph :before #'Footnote--fill-paragraph-in-body) ;━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ --silsinndhfqcm5vk--