bug#81295: 32.0.50; dired-auto-toggle-b-switch problem with subdirectory

Stephen Berman via "Bug reports for GNU Emacs, the Swiss army knife of text editors" <[email protected]> Thu, 30 Jul 2026 12:07:35 +0200
Newsgroups gmane.emacs.bugs
Message-ID <[email protected]>
On Wed, 29 Jul 2026 18:06:46 +0300 Eli Zaretskii <[email protected]> wrote:

>> From: Filipp Gunbin <[email protected]>
>> Cc: [email protected],  [email protected],  [email protected]
>> Date: Wed, 29 Jul 2026 17:49:31 +0300
>> 
>> On 29/07/2026 17:00 +0300, Eli Zaretskii wrote:
>> 
>> >> From: Filipp Gunbin <[email protected]>
>> >> Cc: Eli Zaretskii <[email protected]>,  [email protected],
>> >>   [email protected]
>> >> Date: Wed, 29 Jul 2026 16:50:52 +0300
>> >> 
>> >> On 29/07/2026 15:32 +0200, Stephen Berman wrote:
>> >> 
>> >> [...]
>> >> 
>> >> > So that's the current situation, and why I've turned to you and Sean for
>> >> > a decision on how to proceed: (i) install my changes to handle file
>> >> > names with newlines in Dired subdirs, including the change that "fixes"
>> >> > the bug with `C-u i'; (ii) install the changes except for the one that
>> >> > "fixes" the `C-u i' bug, thus leaving that unfixed for now; (iii) wait
>> >> > for Filipp's alternative implementation, which will hopefully fix that
>> >> > bug without circumventing validation of subdir switches.
>> >> 
>> >> As I wrote already, I do not object to (ii), we agree on that patch.  I
>> >> object only to the fix of supposedly rare problem which we found in the
>> >> course of discussing this bug, and (i) additionally includes that fix.
>> >> We could create another bug report for that and see if anyone (me, or
>> >> you, or somebody else) comes up with the patch that we all agree with.
>> >> That is, (iii) is not an alternative to (ii) - we could install the
>> >> patch in (ii) right now, and that will fix the problem which I created
>> >> this bug about.
>> >
>> > Why not install (i) and _then_ wait for that one aspect to be fixed
>> > separately?
>> 
>> My concerns are that (i):
>> 
>> - Breaks the current logic, and thus will introduce more subtle bugs.
>> Given that the problem it fixes is minor, I don't see this as a good
>> trade-off.
>> 
>> - Makes the code harder to read and change later, as it adds a
>> non-obvious special case, and you need to read this discussion to
>> understand why it was added.  I always favor cleaner code, that's why
>> I'd prefer to create another bug, rather than fix it here "at all
>> costs", but that's me.
>
> Fair enough, let's wait for Sean to chime in.

While we're waiting, I'd like to propose the attached patch an
alternative to (ii) which is acceptable to me: it omits the fix the
Filipp objects to but issues a warning when the user enters `C-u i' and
triggers the bug.  This way I don't feel like we're disengenuously
exposing users to a known bug that has a fix, though one currently too
controversial to be installed.

While testing this I discovered that the code for displaying a warning
when `dired-auto-toggle-b-switch' is nil does not account for the case
where the subdir containing a file whose name contains a newline is more
deeply embedded than one subdir level in the Dired buffer, and the
attached patch fixes this; this fix should be included in the installed
changeset regardless of the decision on the `C-u i' case.

Steve Berman
(unnamed) (text/x-patch, 4.4 KB)
diff --git a/lisp/dired-aux.el b/lisp/dired-aux.el
index 50287a67129..e773bb6f2a1 100644
--- a/lisp/dired-aux.el
+++ b/lisp/dired-aux.el
@@ -3356,7 +3356,24 @@ dired-insert-subdir
 	(modflag (buffer-modified-p))
 	(old-switches switches)
 	switches-have-R mark-alist case-fold-search buffer-read-only)
-    (and (not switches) cons (setq switches (cdr cons)))
+    (and (not switches)
+         ;; FIXME: This line fixes a bug when entering `C-u i' with
+         ;; `dired-auto-toggle-b-switch' non-nil, but the fix is
+         ;; controversial so currently not used; see bug#81295.
+         ;; (not (dired-switches-escape-p dired-actual-switches))
+         cons (setq switches (cdr cons)))
+    ;; FIXME: Since the bug results is a bad Dired display, we warn the
+    ;; user; remove this warning when an acceptable fix is installed.
+    (when (and dired-auto-toggle-b-switch dired-switches-alist
+               (directory-files (caar dired-switches-alist) nil "\n")
+               (dired-switches-escape-p dired-actual-switches)
+               (not (dired-switches-escape-p (cdar dired-switches-alist))))
+      (display-warning 'dired
+                       "
+You have encountered a known Emacs bug
+for which there is currently no acceptable solution;
+see <https://debbugs.gnu.org/cgi/bugreport.cgi?bug=81295#56>
+and the related messages for details."))
     (dired-insert-subdir-validate dirname switches)
     ;; case-fold-search is nil now, so we can test for capital `R':
     (if (setq switches-have-R (and switches (string-match-p "R" switches)))
@@ -3382,6 +3399,16 @@ dired-insert-subdir
 		 (if cur-cons
 		     (setcdr cur-cons switches)
 		   (push (cons cur-dir switches) dired-switches-alist)))))))
+    ;; Since we insert subdirs without calling `dired-internal-noselect'
+    ;; we also have to test here whether the subdir contains a file name
+    ;; with a newline, and if so, pop up a warning.  FIXME: Is there a
+    ;; cleaner way to do this?  See bug#81295.
+    (unless (or dired-auto-toggle-b-switch
+                (dired-switches-escape-p dired-listing-switches)
+                (dired-switches-escape-p dired-actual-switches))
+      (when (and (dired--filename-with-newline-p)
+                 (dired--ls-accept-b-switch-p))
+        (dired--display-filename-with-newline-warning (current-buffer))))
     (dired-initial-position dirname)
     (save-excursion (dired-mark-remembered mark-alist))
     (restore-buffer-modified-p modflag)))
diff --git a/lisp/dired.el b/lisp/dired.el
index 53ec6779061..a4bfd81b5b9 100644
--- a/lisp/dired.el
+++ b/lisp/dired.el
@@ -1487,7 +1487,9 @@ dired-internal-noselect
     ;; and `ls' can take the `b' switch.  We do this here in order to
     ;; get the warning not only when interactively invoking `dired' on a
     ;; directory, but also e.g. when passing the directory name as a
-    ;; command line argument when starting Emacs from the shell.
+    ;; command line argument when starting Emacs from the shell (but
+    ;; inserting subdirs does not call `dired-internal-noselect' so we
+    ;; also have to run this test in `dired-insert-subdir').
     (unless (or dired-auto-toggle-b-switch
                 (dired-switches-escape-p dired-listing-switches)
                 (dired-switches-escape-p dired-actual-switches))
@@ -4060,11 +4062,18 @@ dired-buffer-more-recently-used-p
        (not (memq buffer1 (memq buffer2 (buffer-list))))))
 
 (defun dired--filename-with-newline-p ()
-  "Check whether a file name in this directory has a newline.
-Return non-nil if at least one file name in this directory contains a
-newline character (regardless of whether Dired displays the character as
-a literal newline or as \"\\n\")."
-  (directory-files default-directory nil "\n"))
+  "Check whether a file name in this Dired buffer has a newline.
+Return non-nil if at least one file name in this Dired buffer (including
+any Dired subdirectories in the buffer) contains a newline character
+(regardless of whether Dired displays the character as a literal newline
+or as \"\\n\")."
+  (if (length> dired-subdir-alist 1)
+      (let (res)
+        (catch 'found
+          (dolist (subdir dired-subdir-alist res)
+            (setq res (directory-files (car subdir) nil "\n"))
+            (and res (throw 'found res)))))
+    (directory-files default-directory nil "\n")))
 
 (defun dired--ls-accept-b-switch-p ()
   "Return non-nil if the `ls' used by Dired accepts the `b' switch."