1
Fork 0
mirror of git://git.sv.gnu.org/emacs.git synced 2025-12-06 06:20:55 -08:00

lisp: Introduce a `lisp-fill-paragraph-as-displayed' variable.

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 variable allowing
opting out of this new behavior in specific scenarios (such as
when using the Scheme major mode, say).

* 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
This commit is contained in:
Maxim Cournoyer 2025-01-21 11:50:44 +09:00 committed by Eli Zaretskii
parent d4ca688abe
commit 192355e54a
2 changed files with 92 additions and 30 deletions

View file

@ -1431,6 +1431,19 @@ Any non-integer value means do not use a different value of
:group 'lisp
:version "30.1")
(defvar lisp-fill-paragraph-as-displayed nil
"Modify the behavior of `lisp-fill-paragraph'.
The default behavior of `lisp-fill-paragraph' is tuned for filling Emacs
Lisp doc strings, with their special treatment for the first line.
Particularly, strings are filled in a narrowed context to avoid filling
surrounding code, which means any leading indent is disregarded, which
can cause the filled string to extend passed the configured
`fill-column' variable value. If you would rather fill the string in
its original context and ensure the `fill-column' value is more strictly
respected, set this variable to true. Doing so makes
`lisp-fill-paragraph' behave as it used to in Emacs 27 and prior
versions.")
(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 +1493,44 @@ and initial semicolons."
(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)