Subject: [PATCH] Update `fill-region-as-paragraph-semlf' to follow fill.el protocols

From: Roi Martin <[email-masked]>
Date: Mon, 30 Jun 2025 13:09:57 +0200

Tags: patch

This patch updates the `fill-region-as-paragraph-semlf' function to
follow the `fill-region-as-paragraph-function' protocol.  This allows to
delete the `fill-paragraph-semlf' function, which is replaced by
`fill-paragraph' combined with assigning
`fill-region-as-paragraph-semlf' to `fill-region-as-paragraph-function'.

Stefan, I also took the opportunity to remove the `with-restriction'
call from `fill-region-as-paragraph-semlf', as discussed in:

https://debbugs.gnu.org/cgi/bugreport.cgi?bug=78561#47

Given that `fill-paragraph-semlf' is not part of any stable release of
GNU Emacs, I guess it is fine to remove it.  Is this a fair assumption?

        Roi

>From 964fc161e32a05d8b252d09b0c6f5fabbc4aa19a Mon Sep 17 00:00:00 2001
From: Roi Martin <[email-masked]>
Date: Tue, 17 Jun 2025 19:21:18 +0200
Subject: [PATCH] Update `fill-region-as-paragraph-semlf' to follow fill.el
 protocols

Update the `fill-region-as-paragraph-semlf' function to follow the
`fill-region-as-paragraph-function' protocol.  This allows to delete the
`fill-paragraph-semlf' function, which is replaced by `fill-paragraph'
combined with assigning `fill-region-as-paragraph-semlf' to
`fill-region-as-paragraph-function'.
* lisp/textmodes/fill.el (fill-region-as-paragraph-semlf): Make this
function compatible with `fill-region-as-paragraph-function'.  Remove
call to `with-restriction'.
(fill-paragraph-semlf): Delete function.
* test/lisp/textmodes/fill-tests.el (fill-tests--fill-paragraph-semlf):
Add helper function.
(fill-test-semlf-fill-region): Add test.
(fill-test-fill-paragraph-semlf): Remove test.
(fill-test-fill-paragraph-semlf-fill-paragraph-function)
(fill-test-semlf-fill-paragraph, fill-test-fill-paragraph-semlf-justify)
(fill-test-semlf-justify)
(fill-test-fill-paragraph-semlf-sentence-end-double-space)
(fill-test-semlf-sentence-end-double-space)
(fill-test-fill-paragraph-semlf-fill-column, fill-test-semlf-fill-column)
(fill-test-fill-paragraph-semlf-punctuation-marks)
(fill-test-semlf-punctuation-marks, fill-test-fill-paragraph-semlf-twice)
(fill-test-semlf-twice, fill-test-fill-paragraph-semlf-fill-prefix)
(fill-test-semlf-fill-prefix)
(fill-test-fill-paragraph-semlf-indented-block)
(fill-test-semlf-indented-block, fill-test-fill-paragraph-semlf-revert)
(fill-test-semlf-revert, fill-test-fill-paragraph-semlf-emacs-lisp-mode)
(fill-test-semlf-emacs-lisp-mode, fill-test-fill-paragraph-semlf-c-mode)
(fill-test-semlf-c-mode, fill-test-fill-paragraph-semlf-org-mode)
(fill-test-semlf-org-mode, fill-test-fill-paragraph-semlf-markdown-mode)
(fill-test-semlf-markdown-mode): Remove reference to
`fill-paragraph-semlf' from test names.
* test/lisp/textmodes/fill-resources/semlf-fill-region.erts: Add test
data.
* test/lisp/textmodes/fill-resources/semlf-fill-paragraph-function.erts:
Delete file.
* test/lisp/textmodes/fill-resources/semlf-emacs-lisp-mode.erts: Remove
newlines around indented block.
* doc/lispref/text.texi (Filling): Highlight that
`fill-region-as-paragraph-function' changes the behavior of
`fill-paragraph'.
---
 doc/lispref/text.texi                         |   9 +-
 lisp/textmodes/fill.el                        |  90 +++++----------
 .../fill-resources/semlf-emacs-lisp-mode.erts |   8 +-
 .../semlf-fill-paragraph-function.erts        |  12 --
 .../fill-resources/semlf-fill-region.erts     |  25 +++++
 test/lisp/textmodes/fill-tests.el             | 104 ++++++++++--------
 6 files changed, 122 insertions(+), 126 deletions(-)
 delete mode 100644 test/lisp/textmodes/fill-resources/semlf-fill-paragraph-function.erts
 create mode 100644 test/lisp/textmodes/fill-resources/semlf-fill-region.erts

diff --git a/doc/lispref/text.texi b/doc/lispref/text.texi
index fe3863db810d..b01df8512b72 100644
--- a/doc/lispref/text.texi
+++ b/doc/lispref/text.texi
@@ -1848,10 +1848,11 @@ Filling
 
 @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}.
+@code{fill-paragraph} and @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
diff --git a/lisp/textmodes/fill.el b/lisp/textmodes/fill.el
index bb10890141d6..87568c14c62b 100644
--- a/lisp/textmodes/fill.el
+++ b/lisp/textmodes/fill.el
@@ -1641,7 +1641,12 @@ fill-region-as-paragraph-semlf
 
 Return the `fill-prefix' used for filling.
 
-For more details about semantic linefeeds, see `fill-paragraph-semlf'."
+This function can be assigned to `fill-region-as-paragraph-function' to
+override how functions like `fill-paragraph' and `fill-region' fill
+text.
+
+For more details about semantic linefeeds, see `https://sembr.org/' and
+`https://rhodesmill.org/brandon/2012/one-sentence-per-line/'."
   (interactive (progn
 		 (barf-if-buffer-read-only)
 		 (list (region-beginning)
@@ -1651,67 +1656,32 @@ fill-region-as-paragraph-semlf
     (setq justify 'full))
 
   (let ((from (min from to))
-        (to (max from to))
+        (to (copy-marker (max from to) t))
         pfx)
     (goto-char from)
-    (with-restriction (line-beginning-position) to
-      (let ((fill-column (point-max)))
-        (setq pfx (or (save-excursion
-                        (fill-region-as-paragraph-default (point)
-                                                          (point-max)
-                                                          nil
-                                                          nosqueeze
-                                                          squeeze-after))
-                      "")))
-      (while (not (eobp))
-        (let ((fill-prefix pfx))
-	  (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)
-	  (insert "\n")
-	  (insert pfx))))
-    (unless (eobp) (forward-char 1))
+    (let ((fill-column (point-max)))
+      (setq pfx (or (save-excursion
+                      (fill-region-as-paragraph-default (point)
+                                                        (marker-position to)
+                                                        nil
+                                                        nosqueeze
+                                                        squeeze-after))
+                    "")))
+    (while (< (point) (marker-position to))
+      (let ((fill-prefix pfx))
+	(fill-region-as-paragraph-default (point)
+				          (min (marker-position to)
+                                               (save-excursion
+                                                 (forward-sentence)
+                                                 (point)))
+				          justify
+                                          t))
+      (when (and (> (point) (line-beginning-position))
+		 (< (point) (line-end-position))
+                 (< (point) (marker-position to)))
+	(delete-horizontal-space)
+	(insert "\n")
+	(insert pfx)))
     pfx))
 
-(defun fill-paragraph-semlf (&optional justify)
-  "Fill paragraph at or after point using semantic linefeeds.
-Refill text putting a newline character after each sentence, calling
-`forward-sentence' to find the ends of sentences.  If
-`sentence-end-double-space' is non-nil, period followed by one space is
-not the end of a sentence.
-
-If JUSTIFY is non-nil (interactively, with prefix argument), justify as
-well.  The variable `fill-column' controls the width for filling.
-
-Return the `fill-prefix' used for filling.
-
-You can use this function as the value of `fill-paragraph-function', so
-`fill-paragraph' and other filling commands will use it.
-
-For more details about semantic linefeeds, see `https://sembr.org/' and
-`https://rhodesmill.org/brandon/2012/one-sentence-per-line/'."
-  (interactive (progn
-		 (barf-if-buffer-read-only)
-		 (list (if current-prefix-arg 'full))))
-  (unless (memq justify '(t nil none full center left right))
-    (setq justify 'full))
-
-  (save-excursion
-    (let ((to (progn
-		(fill-forward-paragraph 1)
-		(backward-word)
-		(end-of-line)
-		(point)))
-	  (from (progn
-		  (fill-forward-paragraph -1)
-		  (forward-word)
-		  (beginning-of-line)
-		  (point))))
-      (fill-region-as-paragraph-semlf from to justify))))
-
 ;;; fill.el ends here
diff --git a/test/lisp/textmodes/fill-resources/semlf-emacs-lisp-mode.erts b/test/lisp/textmodes/fill-resources/semlf-emacs-lisp-mode.erts
index fe71ee32c1aa..1623b0dcf8aa 100644
--- a/test/lisp/textmodes/fill-resources/semlf-emacs-lisp-mode.erts
+++ b/test/lisp/textmodes/fill-resources/semlf-emacs-lisp-mode.erts
@@ -59,12 +59,12 @@ the comment.
 ;; eiusmod tempor.  Incididunt ut labore et dolore magna aliqua. Ut
 ;; enim ad minim veniam, quis nostrud exercitation ullamco laboris
 ;; nisi ut.
-
+;;
 ;; 	|Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed
 ;; 	do eiusmod tempor.  Incididunt ut labore et dolore magna
 ;; 	aliqua. Ut enim ad minim veniam, quis nostrud exercitation
 ;; 	ullamco laboris nisi ut.
-
+;;
 ;; Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do
 ;; eiusmod tempor.  Incididunt ut labore et dolore magna aliqua. Ut
 ;; enim ad minim veniam, quis nostrud exercitation ullamco laboris
@@ -74,12 +74,12 @@ the comment.
 ;; eiusmod tempor.  Incididunt ut labore et dolore magna aliqua. Ut
 ;; enim ad minim veniam, quis nostrud exercitation ullamco laboris
 ;; nisi ut.
-
+;;
 ;; 	Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed
 ;; 	do eiusmod tempor.
 ;; 	Incididunt ut labore et dolore magna aliqua. Ut enim ad minim
 ;; 	veniam, quis nostrud exercitation ullamco laboris nisi ut.
-
+;;
 ;; Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do
 ;; eiusmod tempor.  Incididunt ut labore et dolore magna aliqua. Ut
 ;; enim ad minim veniam, quis nostrud exercitation ullamco laboris
diff --git a/test/lisp/textmodes/fill-resources/semlf-fill-paragraph-function.erts b/test/lisp/textmodes/fill-resources/semlf-fill-paragraph-function.erts
deleted file mode 100644
index 467e7401cf50..000000000000
--- a/test/lisp/textmodes/fill-resources/semlf-fill-paragraph-function.erts
+++ /dev/null
@@ -1,12 +0,0 @@
-Name: fill-paragraph-function
-
-=-=
-Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do
-eiusmod tempor.  Incididunt ut labore et dolore magna aliqua. Ut enim
-ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut.
-=-=
-Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do
-eiusmod tempor.
-Incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam,
-quis nostrud exercitation ullamco laboris nisi ut.
-=-=-=
diff --git a/test/lisp/textmodes/fill-resources/semlf-fill-region.erts b/test/lisp/textmodes/fill-resources/semlf-fill-region.erts
new file mode 100644
index 000000000000..231019a082a4
--- /dev/null
+++ b/test/lisp/textmodes/fill-resources/semlf-fill-region.erts
@@ -0,0 +1,25 @@
+Point-Char: |
+
+Name: fill-region-as-paragraph-function
+
+=-=
+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 310d374a7adb..40ef907586fe 100644
--- a/test/lisp/textmodes/fill-tests.el
+++ b/test/lisp/textmodes/fill-tests.el
@@ -147,103 +147,115 @@ fill-test-fill-region-as-paragraph-semlf
                            (beginning-of-line)
                            (point))))))
 
-(ert-deftest fill-test-fill-paragraph-semlf ()
-  "Test the `fill-paragraph-semlf' function."
-  (ert-test-erts-file (ert-resource-file "semlf.erts")
+(ert-deftest fill-test-semlf-fill-region ()
+  "Test `fill-region' with `fill-region-as-paragraph-semlf'."
+  (ert-test-erts-file (ert-resource-file "semlf-fill-region.erts")
                       (lambda ()
-			(fill-paragraph-semlf))))
+			(setq-local fill-region-as-paragraph-function
+                                    #'fill-region-as-paragraph-semlf)
+			(fill-region
+                         (point)
+                         (progn
+                           (goto-char (point-max))
+                           (forward-line -1)
+                           (beginning-of-line)
+                           (point))))))
 
-(ert-deftest fill-test-fill-paragraph-semlf-fill-paragraph-function ()
-  "Test `fill-paragraph-semlf' as `fill-paragraph-function'."
-  (ert-test-erts-file (ert-resource-file "semlf-fill-paragraph-function.erts")
+(defun fill-tests--fill-paragraph-semlf (&optional justify region)
+  "Call `fill-paragraph' using `fill-region-as-paragraph-semlf'."
+  (let ((fill-region-as-paragraph-function #'fill-region-as-paragraph-semlf))
+    (fill-paragraph justify region)))
+
+(ert-deftest fill-test-semlf-fill-paragraph ()
+  "Test `fill-paragraph' with `fill-region-as-paragraph-semlf'."
+  (ert-test-erts-file (ert-resource-file "semlf.erts")
                       (lambda ()
-			(setq-local fill-paragraph-function #'fill-paragraph-semlf)
-			(fill-paragraph))))
+			(fill-tests--fill-paragraph-semlf))))
 
-(ert-deftest fill-test-fill-paragraph-semlf-justify ()
-  "Test the JUSTIFY parameter of the `fill-paragraph-semlf' function."
+(ert-deftest fill-test-semlf-justify ()
+  "Test semantic-linefeed filling with text justification."
   (ert-test-erts-file (ert-resource-file "semlf-justify.erts")
                       (lambda ()
-			(fill-paragraph-semlf 'justify))))
+			(fill-tests--fill-paragraph-semlf 'justify))))
 
-(ert-deftest fill-test-fill-paragraph-semlf-sentence-end-double-space ()
-  "Test the `fill-paragraph-semlf' function with `sentence-end-double-space'."
+(ert-deftest fill-test-semlf-sentence-end-double-space ()
+  "Test semantic-linefeed filling with `sentence-end-double-space'."
   (ert-test-erts-file (ert-resource-file "semlf-sentence-end-double-space.erts")
                       (lambda ()
 			(setq-local sentence-end-double-space nil)
-			(fill-paragraph-semlf))))
+			(fill-tests--fill-paragraph-semlf))))
 
-(ert-deftest fill-test-fill-paragraph-semlf-fill-column ()
-  "Test the `fill-paragraph-semlf' function with `fill-column'."
+(ert-deftest fill-test-semlf-fill-column ()
+  "Test semantic-linefeed filling with `fill-column'."
   (ert-test-erts-file (ert-resource-file "semlf-fill-column.erts")
                       (lambda ()
 			(setq-local fill-column 35)
-			(fill-paragraph-semlf))))
+			(fill-tests--fill-paragraph-semlf))))
 
-(ert-deftest fill-test-fill-paragraph-semlf-punctuation-marks ()
-  "Test the `fill-paragraph-semlf' function with different punctuation marks."
+(ert-deftest fill-test-semlf-punctuation-marks ()
+  "Test semantic-linefeed filling with different punctuation marks."
   (ert-test-erts-file (ert-resource-file "semlf-punctuation-marks.erts")
                       (lambda ()
-			(fill-paragraph-semlf))))
+			(fill-tests--fill-paragraph-semlf))))
 
-(ert-deftest fill-test-fill-paragraph-semlf-twice ()
-  "Test to run the `fill-paragraph-semlf' function twice."
+(ert-deftest fill-test-semlf-twice ()
+  "Test filling the same text twice using semantic linefeeds."
   (ert-test-erts-file (ert-resource-file "semlf-twice.erts")
                       (lambda ()
 			(goto-char (point-min))
-			(fill-paragraph-semlf)
+			(fill-tests--fill-paragraph-semlf)
 			(goto-char (point-min))
-			(fill-paragraph-semlf))))
+			(fill-tests--fill-paragraph-semlf))))
 
-(ert-deftest fill-test-fill-paragraph-semlf-fill-prefix ()
-  "Test the `fill-paragraph-semlf' function with different fill prefixes."
+(ert-deftest fill-test-semlf-fill-prefix ()
+  "Test semantic-linefeed filling with different fill prefixes."
   (ert-test-erts-file (ert-resource-file "semlf-fill-prefix.erts")
                       (lambda ()
-			(fill-paragraph-semlf))))
+			(fill-tests--fill-paragraph-semlf))))
 
-(ert-deftest fill-test-fill-paragraph-semlf-indented-block ()
-  "Test the `fill-paragraph-semlf' function with an indented block."
+(ert-deftest fill-test-semlf-indented-block ()
+  "Test semantic-linefeed filling with an indented block."
   (ert-test-erts-file (ert-resource-file "semlf-indented-block.erts")
                       (lambda ()
-			(fill-paragraph-semlf))))
+			(fill-tests--fill-paragraph-semlf))))
 
-(ert-deftest fill-test-fill-paragraph-semlf-revert ()
-  "Test that the `fill-paragraph-semlf' function can be reverted."
+(ert-deftest fill-test-semlf-revert ()
+  "Test that semantic-linefeed filling can be reverted."
   (ert-test-erts-file (ert-resource-file "semlf-revert.erts")
                       (lambda ()
                         (fill-paragraph)
-			(fill-paragraph-semlf)
+                        (fill-tests--fill-paragraph-semlf)
                         (fill-paragraph))))
 
-(ert-deftest fill-test-fill-paragraph-semlf-emacs-lisp-mode ()
-  "Test the `fill-paragraph-semlf' function with `emacs-lisp-mode'."
+(ert-deftest fill-test-semlf-emacs-lisp-mode ()
+  "Test semantic-linefeed filling with `emacs-lisp-mode'."
   (ert-test-erts-file (ert-resource-file "semlf-emacs-lisp-mode.erts")
                       (lambda ()
 			(emacs-lisp-mode)
-			(fill-paragraph-semlf))))
+			(fill-tests--fill-paragraph-semlf))))
 
-(ert-deftest fill-test-fill-paragraph-semlf-c-mode ()
-  "Test the `fill-paragraph-semlf' function with `c-mode'."
+(ert-deftest fill-test-semlf-c-mode ()
+  "Test semantic-linefeed filling with `c-mode'."
   (ert-test-erts-file (ert-resource-file "semlf-c-mode.erts")
                       (lambda ()
 			(c-mode)
-			(fill-paragraph-semlf))))
+			(fill-tests--fill-paragraph-semlf))))
 
-(ert-deftest fill-test-fill-paragraph-semlf-org-mode ()
-  "Test the `fill-paragraph-semlf' function with `org-mode'."
+(ert-deftest fill-test-semlf-org-mode ()
+  "Test semantic-linefeed filling with `org-mode'."
   (ert-test-erts-file (ert-resource-file "semlf-org-mode.erts")
                       (lambda ()
 			(org-mode)
-			(fill-paragraph-semlf))))
+			(fill-tests--fill-paragraph-semlf))))
 
 (declare-function markdown-mode "markdown-mode")
-(ert-deftest fill-test-fill-paragraph-semlf-markdown-mode ()
-  "Test the `fill-paragraph-semlf' function with `markdown-mode'."
+(ert-deftest fill-test-semlf-markdown-mode ()
+  "Test semantic-linefeed filling with `markdown-mode'."
   (skip-unless (functionp 'markdown-mode))
   (ert-test-erts-file (ert-resource-file "semlf-markdown-mode.erts")
                       (lambda ()
 			(markdown-mode)
-			(fill-paragraph-semlf))))
+			(fill-tests--fill-paragraph-semlf))))
 
 (provide 'fill-tests)
 
-- 
2.49.0