Add variable `fill-region-as-paragraph-function'

Add the variable `fill-region-as-paragraph-function' to provide
a way to override how functions like `fill-region' fill text.
* doc/lispref/text.texi (Filling): Document
`fill-region-as-paragraph-function' variable.
* doc/emacs/text.texi (Fill Commands): Reference
`fill-region-as-paragraph-function' variable.
* lisp/textmodes/fill.el (fill-region-as-paragraph-function):
Add variable.
(fill-region-as-paragraph): Convert into
`fill-region-as-paragraph-function' wrapper.
(fill-region-as-paragraph-default): Rename old
`fill-region-as-paragraph' function.
(fill-region-as-paragraph-semlf): Update calls to
`fill-region-as-paragraph-default'.
(fill-region): Add reference to `fill-region-as-paragraph-function'
in doc string.
* test/lisp/textmodes/fill-tests.el (fill-test-fill-region): Add
test case for the `fill-region' function.
* test/lisp/textmodes/fill-resources/fill-region.erts: Add test
data.  (Bug#78816)
This commit is contained in:
Roi Martin 2025-06-17 10:45:13 +02:00 committed by Eli Zaretskii
parent bca0ce9d07
commit 99ec286d78
5 changed files with 104 additions and 18 deletions

View file

@ -600,12 +600,15 @@ can also call @kbd{M-x fill-region} to specifically fill the text in
the region.
@findex fill-region-as-paragraph
@vindex fill-region-as-paragraph-function
@kbd{M-q} and @code{fill-region} use the usual Emacs criteria for
finding paragraph boundaries (@pxref{Paragraphs}). For more control,
you can use @kbd{M-x fill-region-as-paragraph}, which refills
everything between point and mark as a single paragraph. This command
deletes any blank lines within the region, so separate blocks of text
end up combined into one block.
you can use @kbd{M-x fill-region-as-paragraph}, which refills everything
between point and mark as a single paragraph. The behavior of this
command is controlled by the variable
@code{fill-region-as-paragraph-function}. By default, it deletes any
blank lines within the region, so separate blocks of text end up
combined into one block.
@cindex justification
A numeric argument to @kbd{M-q} tells it to @dfn{justify} the text

View file

@ -1737,7 +1737,12 @@ described above.
@deffn Command fill-region-as-paragraph start end &optional justify nosqueeze squeeze-after
This command considers a region of text as a single paragraph and fills
it. If the region was made up of many paragraphs, the blank lines
it. The behavior of this command is controlled by the variable
@code{fill-region-as-paragraph-function}, with the default
implementation being @code{fill-region-as-paragraph-default}, which is
described in detail below.
If the region was made up of many paragraphs, the blank lines
between paragraphs are removed. This function justifies as well as
filling when @var{justify} is non-@code{nil}.
@ -1841,6 +1846,14 @@ paragraphs actually moved. The default value of this variable is
Manual}.
@end defvar
@defvar fill-region-as-paragraph-function
This variable provides a way to override how functions like
@code{fill-region} fill text. Its value should be a function, which
should accept the arguments defined by @code{fill-region-as-paragraph}
and return the fill prefix used for filling. The default value of this
variable is @code{fill-region-as-paragraph-default}.
@end defvar
@defvar use-hard-newlines
If this variable is non-@code{nil}, the filling functions do not delete
newlines that have the @code{hard} text property. These hard

View file

@ -647,8 +647,8 @@ The break position will be always after LINEBEG and generally before point."
(indent-line-to (current-left-margin))
(put-text-property beg (point) 'face 'default)))
(defun fill-region-as-paragraph (from to &optional justify
nosqueeze squeeze-after)
(defun fill-region-as-paragraph-default (from to &optional justify
nosqueeze squeeze-after)
"Fill the region as if it were a single paragraph.
This command removes any paragraph breaks in the region and
extra newlines at the end, and indents and fills lines between the
@ -800,6 +800,39 @@ space does not end a sentence, so don't break a line there."
;; Return the fill-prefix we used
fill-prefix)))
(defvar fill-region-as-paragraph-function #'fill-region-as-paragraph-default
"Function to fill the region as if it were a single paragraph.
It should accept the arguments defined by `fill-region-as-paragraph' and
return the `fill-prefix' used for filling.")
(defun fill-region-as-paragraph (from to &optional justify
nosqueeze squeeze-after)
"Fill the region as if it were a single paragraph.
The behavior of this command is controlled by the variable
`fill-region-as-paragraph-function', with the default implementation
being `fill-region-as-paragraph-default'.
The arguments FROM and TO define the boundaries of the region.
The optional third argument JUSTIFY, when called interactively with a
prefix arg, is assigned the value `full'.
When called from Lisp, JUSTIFY can specify any type of justification;
see `default-justification' for the possible values.
Optional fourth arg NOSQUEEZE non-nil means not to make spaces between
words canonical before filling.
Fifth arg SQUEEZE-AFTER, if non-nil, should be a buffer position; it
means canonicalize spaces only starting from that position.
See `canonically-space-region' for the meaning of canonicalization of
spaces.
It returns the `fill-prefix' used for filling."
(interactive (progn
(barf-if-buffer-read-only)
(list (region-beginning) (region-end)
(if current-prefix-arg 'full))))
(funcall fill-region-as-paragraph-function
from to justify nosqueeze squeeze-after))
(defsubst skip-line-prefix (prefix)
"If point is inside the string PREFIX at the beginning of line, move past it."
(when (and prefix
@ -1061,7 +1094,10 @@ if variable `use-hard-newlines' is on).
Return the `fill-prefix' used for filling the last paragraph.
If `sentence-end-double-space' is non-nil, then period followed by one
space does not end a sentence, so don't break a line there."
space does not end a sentence, so don't break a line there.
The variable `fill-region-as-paragraph-function' can be used to override
how paragraphs are filled."
(interactive (progn
(barf-if-buffer-read-only)
(list (region-beginning) (region-end)
@ -1621,19 +1657,19 @@ For more details about semantic linefeeds, see `fill-paragraph-semlf'."
(with-restriction (line-beginning-position) to
(let ((fill-column (point-max)))
(setq pfx (or (save-excursion
(fill-region-as-paragraph (point)
(point-max)
nil
nosqueeze
squeeze-after))
(fill-region-as-paragraph-default (point)
(point-max)
nil
nosqueeze
squeeze-after))
"")))
(while (not (eobp))
(let ((fill-prefix pfx))
(fill-region-as-paragraph (point)
(progn (forward-sentence) (point))
justify
nosqueeze
squeeze-after))
(fill-region-as-paragraph-default (point)
(progn (forward-sentence) (point))
justify
nosqueeze
squeeze-after))
(when (and (> (point) (line-beginning-position))
(< (point) (line-end-position)))
(delete-horizontal-space)

View file

@ -0,0 +1,23 @@
Point-Char: |
Name: fill region
=-=
Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor. Incididunt ut labore et dolore magna aliqua.
|Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor. Incididunt ut labore et dolore magna aliqua.
Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor. Incididunt ut labore et dolore magna aliqua.
Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor. Incididunt ut labore et dolore magna aliqua.
=-=
Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor. Incididunt ut labore et dolore magna aliqua.
Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do
eiusmod tempor. Incididunt ut labore et dolore magna aliqua.
Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do
eiusmod tempor. Incididunt ut labore et dolore magna aliqua.
Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor. Incididunt ut labore et dolore magna aliqua.
=-=-=

View file

@ -122,6 +122,17 @@ eius. Foo")))
;; w
")))
(ert-deftest fill-test-fill-region ()
"Test the `fill-region' function."
(ert-test-erts-file (ert-resource-file "fill-region.erts")
(lambda ()
(fill-region
(point)
(progn
(goto-char (point-max))
(forward-line -1)
(beginning-of-line)
(point))))))
(ert-deftest fill-test-fill-region-as-paragraph-semlf ()
"Test the `fill-region-as-paragraph-semlf' function."