bug#81516: 31.0.91; delete-file-local-variable(-prop-line) should delete "Local Variables" block (prop-line)

Daniel Mendler via "Bug reports for GNU Emacs, the Swiss army knife of text editors" <[email protected]> Thu, 30 Jul 2026 08:45:23 +0200
Newsgroups gmane.emacs.bugs
Message-ID <[email protected]>
Eli Zaretskii <[email protected]> writes:

>> > The patch looks OK to me, and indeed the most important aspect is to
>> > remove this error.  But I think it's also a good idea to remove the
>> > overall block in `delete-file-local-variable(-prop-line)` when that
>> > block becomes empty, as a matter of aesthetics.
>> 
>> Granted, I'm not opposed to removing those, in addition to fixing the
>> error.
>
> I've now installed my patch on the master branch.
>
> Should we close this bug, or does anyone want to work on removing the
> local vars block and the prop line when they become empty?

Thanks. I would like to see this change. Patch attached.

Daniel
0001-modify-file-local-variable-prop-line-Delete-empty-va.patch (text/x-diff, 3.7 KB)
From b105b8a1ab062eeb05c0c9d634d462b60b3ebd39 Mon Sep 17 00:00:00 2001
From: Daniel Mendler <[email protected]>
Date: Thu, 30 Jul 2026 07:53:17 +0200
Subject: [PATCH] modify-file-local-variable(-prop-line): Delete empty variable
 block

Delete local variable block or prop line when it became empty after
deleting a variable. bug#81516

* lisp/files-x.el (modify-file-local-variable)
(modify-file-local-variable-prop-line): Delete empty block or prop-line.
---
 lisp/files-x.el | 39 +++++++++++++++++++++++++++++++++++----
 1 file changed, 35 insertions(+), 4 deletions(-)

diff --git a/lisp/files-x.el b/lisp/files-x.el
index 0d8c1d96a9f..090893c601c 100644
--- a/lisp/files-x.el
+++ b/lisp/files-x.el
@@ -201,7 +201,8 @@ modify-file-local-variable
 				       (match-beginning 0)))
 	     (suffix (buffer-substring (point) (line-end-position)))
 	     (prefix-re (concat "^" (regexp-quote prefix)))
-	     (suffix-re (concat (regexp-quote suffix) "$")))
+	     (suffix-re (concat (regexp-quote suffix) "$"))
+	     (deleted nil))
 
 	;; Find or add missing "End:".
 	(forward-line 1)
@@ -224,7 +225,17 @@ modify-file-local-variable
 	    (while (re-search-forward
 		    (format "%s%S:.*%s" prefix-re variable suffix-re) end t)
 	      (delete-region (match-beginning 0) (1+ (match-end 0)))
-	      (setq replaced-pos (point)))))
+	      (setq replaced-pos (point)
+		    deleted t))
+	    ;; Delete empty local variables block.
+	    (when (and (eq op 'delete) deleted (= beg end))
+	      (save-excursion
+		(delete-region (progn (goto-char beg)
+				      (forward-line -1)
+				      (point))
+			       (progn (goto-char end)
+				      (forward-line 1)
+				      (point)))))))
 
 	;; Add a new variable/value pair.  Add `mode' to the start, add new
 	;; variable to the end, and add a replaced variable to its last location.
@@ -295,7 +306,7 @@ modify-file-local-variable-prop-line
 If optional variable INTERACTIVE is non-nil, display a message telling
 the user how to make the new value take effect."
   (catch 'exit
-    (let ((beg (point)) end replaced-pos)
+    (let ((beg (point)) end replaced-pos deleted)
       (unless enable-local-variables
 	(throw 'exit (message "File-local variables are disabled")))
 
@@ -357,6 +368,7 @@ modify-file-local-variable-prop-line
 	    ;; Replace or delete MODENAME
 	    (progn
 	      (when (member op '(add-or-replace delete))
+		(setq deleted t)
 		(delete-region (match-beginning 1) (match-end 1)))
 	      (when (eq op 'add-or-replace)
 		(goto-char (match-beginning 1))
@@ -387,7 +399,8 @@ modify-file-local-variable-prop-line
 		(skip-chars-forward " \t;")
 		(when (eq key variable)
 		  (delete-region (match-beginning 0) (point))
-		  (setq replaced-pos (point)))))))
+		  (setq replaced-pos (point)
+                        deleted t))))))
 	;; Add a new variable/value pair.  Add `mode' to the start, add new
 	;; variable to the end, and add a replaced variable to its last location.
 	(when (eq op 'add-or-replace)
@@ -406,6 +419,24 @@ modify-file-local-variable-prop-line
 	  (insert (format "%S: %S;" variable value))
 	  (unless (eq (char-after) ?\s) (insert " ")))))
 
+      ;; Delete empty prop-line.
+      (when (and (eq op 'delete) deleted (= beg end))
+	(save-excursion
+	  (delete-region
+	   (progn
+	     (goto-char beg)
+	     (search-backward "-*-" (line-beginning-position))
+	     (point))
+	   (progn
+	     (goto-char end)
+	     (search-forward "-*-" (line-end-position))
+	     (point)))
+	  (goto-char (line-beginning-position))
+	  (when (looking-at-p
+		 (concat "^[ \t]*" (regexp-quote comment-start)
+			 "[ \t]*" (regexp-quote comment-end) "[ \t]*$"))
+	    (delete-region (point) (progn (forward-line 1) (point))))))
+
       (when interactive
 	(modify-file-local-variable-message variable value op)))))
 
-- 
2.47.3