all messages for Emacs-related lists mirrored at yhetil.org
 help / color / mirror / code / Atom feed
From: Maxim Cournoyer <maxim.cournoyer@gmail.com>
To: 56197@debbugs.gnu.org
Cc: Maxim Cournoyer <maxim.cournoyer@gmail.com>,
	eliz@gnu.org, larsi@gnus.org, felix.lechner@lease-up.com,
	stefankangas@gmail.com
Subject: bug#56197: [PATCH] lisp: Introduce lisp-fill-paragraph-as-displayed option.
Date: Sat,  4 Jan 2025 22:03:43 +0900	[thread overview]
Message-ID: <20250104130343.4801-1-maxim.cournoyer@gmail.com> (raw)
In-Reply-To: <87zgi2xcgm.fsf@gmail.com>

Starting with Emacs 28, filling strings now happens in a narrowed scope,
and looses the leading indentation and can cause the string to extend
past the fill-column value.  Introduce lisp-fill-paragraph-as-displayed
as a new option allowing users to easily opt out of this new behavior.

* lisp/emacs-lisp/lisp-mode.el (lisp-fill-paragraph-as-displayed): New
variable.
(lisp-fill-paragraph): Honor it, by avoiding the logic narrow to strings
before applying fill-paragraph.
* test/lisp/emacs-lisp/lisp-mode-tests.el
(lisp-fill-paragraph-respects-fill-column): Test it.
(lisp-fill-paragraph-docstring-boundaries): New test, as a safeguard to
avoid regressions.

Fixes: bug#56197
---
 lisp/emacs-lisp/lisp-mode.el            | 74 ++++++++++++++-----------
 test/lisp/emacs-lisp/lisp-mode-tests.el | 47 ++++++++++++++++
 2 files changed, 90 insertions(+), 31 deletions(-)

diff --git a/lisp/emacs-lisp/lisp-mode.el b/lisp/emacs-lisp/lisp-mode.el
index d0c32d238bc..cc9f6f51cb5 100644
--- a/lisp/emacs-lisp/lisp-mode.el
+++ b/lisp/emacs-lisp/lisp-mode.el
@@ -1,6 +1,6 @@
 ;;; lisp-mode.el --- Lisp mode, and its idiosyncratic commands  -*- lexical-binding:t -*-
 
-;; Copyright (C) 1985-1986, 1999-2024 Free Software Foundation, Inc.
+;; Copyright (C) 1985-1986, 1999-2025 Free Software Foundation, Inc.
 
 ;; Maintainer: emacs-devel@gnu.org
 ;; Keywords: lisp, languages
@@ -1431,6 +1431,16 @@ emacs-lisp-docstring-fill-column
   :group 'lisp
   :version "30.1")
 
+(defcustom lisp-fill-paragraph-as-displayed nil
+  "Fill paragraphs as displayed in the buffer, preserving surrounding
+context such as the leading indentation.  This is useful if respecting
+`fill-column' is more important than avoiding surrounding code from
+being filled, and makes `lisp-fill-paragraph' behave as it used to in
+Emacs 27 and prior versions."
+  :type 'boolean
+  :group 'lisp
+  :version "31.0")
+
 (defun lisp-fill-paragraph (&optional justify)
   "Like \\[fill-paragraph], but handle Emacs Lisp comments and docstrings.
 If any of the current line is a comment, fill the comment or the
@@ -1480,42 +1490,44 @@ lisp-fill-paragraph
                                   (derived-mode-p 'emacs-lisp-mode))
                              emacs-lisp-docstring-fill-column
                            fill-column)))
-        (let ((ppss (syntax-ppss))
-              (start (point))
-              ;; Avoid recursion if we're being called directly with
-              ;; `M-x lisp-fill-paragraph' in an `emacs-lisp-mode' buffer.
-              (fill-paragraph-function t))
+        (let* ((ppss (syntax-ppss))
+               (start (point))
+               ;; Avoid recursion if we're being called directly with
+               ;; `M-x lisp-fill-paragraph' in an `emacs-lisp-mode' buffer.
+               (fill-paragraph-function t)
+               (string-start (ppss-comment-or-string-start ppss)))
           (save-excursion
             (save-restriction
               ;; If we're not inside a string, then do very basic
               ;; filling.  This avoids corrupting embedded strings in
               ;; code.
-              (if (not (ppss-comment-or-string-start ppss))
+              (if (not string-start)
                   (lisp--fill-line-simple)
-                ;; If we're in a string, then narrow (roughly) to that
-                ;; string before filling.  This avoids filling Lisp
-                ;; statements that follow the string.
-                (when (ppss-string-terminator ppss)
-                  (goto-char (ppss-comment-or-string-start ppss))
-                  ;; The string may be unterminated -- in that case, don't
-                  ;; narrow.
-                  (when (ignore-errors
-                          (progn
-                            (forward-sexp 1)
-                            t))
-                    (narrow-to-region (1+ (ppss-comment-or-string-start ppss))
-                                      (1- (point)))))
-                ;; Move back to where we were.
-                (goto-char start)
-                ;; We should fill the first line of a string
-                ;; separately (since it's usually a doc string).
-                (if (= (line-number-at-pos) 1)
-                    (narrow-to-region (line-beginning-position)
-                                      (line-beginning-position 2))
-                  (save-excursion
-                    (goto-char (point-min))
-                    (forward-line 1)
-                    (narrow-to-region (point) (point-max))))
+                (unless lisp-fill-paragraph-as-displayed
+                  ;; If we're in a string, then narrow (roughly) to that
+                  ;; string before filling.  This avoids filling Lisp
+                  ;; statements that follow the string.
+                  (when (ppss-string-terminator ppss)
+                    (goto-char string-start)
+                    ;; The string may be unterminated -- in that case, don't
+                    ;; narrow.
+                    (when (ignore-errors
+                            (progn
+                              (forward-sexp 1)
+                              t))
+                      (narrow-to-region (1+ string-start)
+                                        (1- (point)))))
+                  ;; Move back to where we were.
+                  (goto-char start)
+                  ;; We should fill the first line of a string
+                  ;; separately (since it's usually a doc string).
+                  (if (= (line-number-at-pos) 1)
+                      (narrow-to-region (line-beginning-position)
+                                        (line-beginning-position 2))
+                    (save-excursion
+                      (goto-char (point-min))
+                      (forward-line 1)
+                      (narrow-to-region (point) (point-max)))))
 	        (fill-paragraph justify)))))))
   ;; Never return nil.
   t)
diff --git a/test/lisp/emacs-lisp/lisp-mode-tests.el b/test/lisp/emacs-lisp/lisp-mode-tests.el
index da02be65d03..347b3d5b642 100644
--- a/test/lisp/emacs-lisp/lisp-mode-tests.el
+++ b/test/lisp/emacs-lisp/lisp-mode-tests.el
@@ -308,6 +308,53 @@ lisp-indent-defun
       (indent-region (point-min) (point-max))
       (should (equal (buffer-string) orig)))))
 
+\f
+;;; Filling
+
+(ert-deftest lisp-fill-paragraph-docstring-boundaries ()
+  "Test bug#28937, ensuring filling the docstring filled is properly
+bounded."
+  (with-temp-buffer
+    (insert "\
+(defun test ()
+  \"This is a test docstring.
+Here is some more text.\"
+  1
+  2
+  3
+  4
+  5)")
+    (let ((correct (buffer-string)))
+      (emacs-lisp-mode)
+      (search-backward "This is a test docstring")
+      (fill-paragraph)                  ;function under test
+      (should (equal (buffer-string) correct)))))
+
+(ert-deftest lisp-fill-paragraph-as-displayed ()
+  "Test bug#56197 -- more specifically, validate that a leading indentation
+for a string is preserved in the filled string."
+  (let ((lisp-fill-paragraph-as-displayed t) ;option under test
+        (source "\
+'(description \"This is a very long string which is indented by a considerable value, causing it to
+protrude from the configured `fill-column' since
+lisp-fill-paragraph was refactored in version 28.\")"))
+    (with-temp-buffer
+      ;; The following is a contrived example that demonstrates the
+      ;; fill-column problem when the string to fill is indented.
+      (insert source)
+      (emacs-lisp-mode)
+      (search-backward "This is a very long string")
+      (fill-paragraph)                  ;function under test
+      (goto-char (point-min))
+      (message "%s" (buffer-substring-no-properties (point-min) (point-max)))
+      (let ((i 1)
+            (lines-count (count-lines (point-min) (point-max))))
+        (while (< i lines-count)
+          (beginning-of-line i)
+          (end-of-line)
+          (should (<= (current-column) fill-column))
+          (setq i (1+ i)))))))
+
 \f
 ;;; Fontification
 
-- 
2.46.0






  parent reply	other threads:[~2025-01-04 13:03 UTC|newest]

Thread overview: 28+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2022-06-24 16:17 bug#56197: 28.1; lisp-fill-paragraph result regressed with Emacs 28 Maxim Cournoyer
2022-06-25 11:53 ` Lars Ingebrigtsen
2022-06-25 12:42   ` Eli Zaretskii
2022-06-25 12:45     ` Lars Ingebrigtsen
2022-06-25 12:48       ` Lars Ingebrigtsen
2022-06-25 13:00         ` Lars Ingebrigtsen
2022-06-29 18:03           ` Stefan Kangas
2022-06-30  9:32             ` Lars Ingebrigtsen
2022-06-30  9:33               ` Lars Ingebrigtsen
2024-12-26 15:16                 ` Stefan Kangas
2024-12-28  5:52                   ` Maxim Cournoyer
2024-12-28  8:47                     ` Eli Zaretskii
2024-12-28 14:51                       ` Maxim Cournoyer
2024-12-28  8:52                     ` Stefan Kangas
2022-06-30 11:31               ` Maxim Cournoyer
2022-07-01  9:05                 ` Lars Ingebrigtsen
2024-12-25 20:15             ` Felix Lechner via Bug reports for GNU Emacs, the Swiss army knife of text editors
2024-12-26  6:21               ` Eli Zaretskii
2024-12-28  5:26                 ` Maxim Cournoyer
2024-12-28  8:45                   ` Eli Zaretskii
2024-12-28 15:14                     ` Maxim Cournoyer
2025-01-04 10:09                       ` bug#56197: lisp-fill-paragraph behavior changed in " Maxim Cournoyer
2025-01-04 10:14                         ` Maxim Cournoyer
2025-01-04 14:04                         ` Eli Zaretskii
2025-01-04 14:19                           ` Eli Zaretskii
2022-06-27  1:53   ` bug#56197: 28.1; lisp-fill-paragraph result regressed with " Maxim Cournoyer
2025-01-04 13:03 ` Maxim Cournoyer [this message]
2025-01-04 14:02   ` bug#56197: [PATCH] lisp: Introduce lisp-fill-paragraph-as-displayed option Eli Zaretskii

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=20250104130343.4801-1-maxim.cournoyer@gmail.com \
    --to=maxim.cournoyer@gmail.com \
    --cc=56197@debbugs.gnu.org \
    --cc=eliz@gnu.org \
    --cc=felix.lechner@lease-up.com \
    --cc=larsi@gnus.org \
    --cc=stefankangas@gmail.com \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
Code repositories for project(s) associated with this external index

	https://git.savannah.gnu.org/cgit/emacs.git
	https://git.savannah.gnu.org/cgit/emacs/org-mode.git

This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.