Subject: [PATCH] Add variable `fill-region-as-paragraph-function'
From: Roi Martin <[email-masked]>
To: [email-masked]
Date: Tue, 17 Jun 2025 12:52:01 +0200
List-Id: <debbugs-submit.debbugs.gnu.org>

Tags: patch

Right now it is not possible to customize how the `fill-region' function
fills text.  This patch adds a new variable named
`fill-region-as-paragraph-function' that allows to override the default
behavior.

For more details, see the discussion in Bug#78561.

From 4533782f57f43befda22ab62f58f02c3fb9ed040 Mon Sep 17 00:00:00 2001
From: Roi Martin <[email-masked]>
Date: Tue, 17 Jun 2025 10:45:13 +0200
Subject: [PATCH] Add variable `fill-region-as-paragraph-function'

Add the variable `fill-region-as-paragraph-function' to provide a way to
override how the function `fill-region' fills text.

* doc/emacs/text.texi (Fill Commands):
* doc/lispref/text.texi (Filling): Document
`fill-region-as-paragraph-function'.
* lisp/textmodes/fill.el (fill-region-as-paragraph-function): Add
variable.
(fill-region): Call `fill-region-as-paragraph-function' internally.
* 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.
---
 doc/emacs/text.texi                           |  9 ++++++++
 doc/lispref/text.texi                         |  9 ++++++++
 lisp/textmodes/fill.el                        | 13 +++++++++--
 .../textmodes/fill-resources/fill-region.erts | 23 +++++++++++++++++++
 test/lisp/textmodes/fill-tests.el             | 11 +++++++++
 5 files changed, 63 insertions(+), 2 deletions(-)
 create mode 100644 test/lisp/textmodes/fill-resources/fill-region.erts

diff --git a/doc/emacs/text.texi b/doc/emacs/text.texi
index 5635171f5cfe..cc21d7c8756a 100644
--- a/doc/emacs/text.texi
+++ b/doc/emacs/text.texi
@@ -607,6 +607,15 @@ Fill Commands
 deletes any blank lines within the region, so separate blocks of text
 end up combined into one block.
 
+@vindex fill-region-as-paragraph-function
+  The variable @code{fill-region-as-paragraph-function} provides a way
+to override how the function @code{fill-region} fills text.  Its value
+should be a function, which is called with the arguments @var{from},
+@var{to}, @var{justify} and @var{nosqueeze}, defined by
+@code{fill-region-as-paragraph}.  It should return the
+@code{fill-prefix} used for filling.  The default value of this variable
+is @code{fill-region-as-paragraph}.
+
 @cindex justification
   A numeric argument to @kbd{M-q} tells it to @dfn{justify} the text
 as well as filling it.  This means that extra spaces are inserted to
diff --git a/doc/lispref/text.texi b/doc/lispref/text.texi
index 75b2b1c3d60e..fb6eacfc3ed9 100644
--- a/doc/lispref/text.texi
+++ b/doc/lispref/text.texi
@@ -1841,6 +1841,15 @@ Filling
 Manual}.
 @end defvar
 
+@defvar fill-region-as-paragraph-function
+This variable provides a way to override how the function
+@code{fill-region} fills text.  Its value should be a function, which is
+called with the arguments @var{from}, @var{to}, @var{justify} and
+@var{nosqueeze}, defined by @code{fill-region-as-paragraph}.  It should
+return the @code{fill-prefix} used for filling.  The default value of
+this variable is @code{fill-region-as-paragraph}.
+@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
diff --git a/lisp/textmodes/fill.el b/lisp/textmodes/fill.el
index 386a88bda3a8..bf7749b885d2 100644
--- a/lisp/textmodes/fill.el
+++ b/lisp/textmodes/fill.el
@@ -1040,6 +1040,12 @@ fill-comment-paragraph
 	   ;; Make sure we don't return nil.
 	   t))))))
 
+(defvar fill-region-as-paragraph-function 'fill-region-as-paragraph
+  "Function to fill the region as if it were a single paragraph.
+It is called with the arguments FROM, TO, JUSTIFY and NOSQUEEZE, defined
+by `fill-region-as-paragraph'. It should return the `fill-prefix' used
+for filling.")
+
 (defun fill-region (from to &optional justify nosqueeze to-eop)
   "Fill each of the paragraphs in the region.
 A prefix arg means justify as well.
@@ -1058,7 +1064,10 @@ fill-region
 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)
@@ -1095,7 +1104,7 @@ fill-region
 	    (goto-char beg))
 	(if (and (>= (point) initial) (< (point) end))
 	    (setq fill-pfx
-		  (fill-region-as-paragraph (point) end justify nosqueeze))
+		  (funcall fill-region-as-paragraph-function (point) end justify nosqueeze))
 	  (goto-char end))))
     (goto-char start-point)
     (set-marker start-point nil)
diff --git a/test/lisp/textmodes/fill-resources/fill-region.erts b/test/lisp/textmodes/fill-resources/fill-region.erts
new file mode 100644
index 000000000000..95e08248309f
--- /dev/null
+++ b/test/lisp/textmodes/fill-resources/fill-region.erts
@@ -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.
+=-=-=
diff --git a/test/lisp/textmodes/fill-tests.el b/test/lisp/textmodes/fill-tests.el
index 8fbd9919bad0..40095fc99417 100644
--- a/test/lisp/textmodes/fill-tests.el
+++ b/test/lisp/textmodes/fill-tests.el
@@ -122,6 +122,17 @@ test-fill-haskell
   ;; 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."
-- 
2.49.0