: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
(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)
(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) ;variable under test
+ ;; The following is a contrived example that demonstrates the
+ ;; fill-column problem when the string to fill is indented.
+ (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
+ (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