master 5a58e371698: Handle file names with newlines in Dired subdirs (bug#81295)

Stephen Berman via Mailing list for Emacs changes <[email protected]> Thu, 30 Jul 2026 17:06:01 -0400 (EDT)
Newsgroups gmane.emacs.diffs
Message-ID <[email protected]>
branch: master
commit 5a58e371698c2d2c29dc8ca9616b3bfbe5fceaf3
Author: Stephen Berman <[email protected]>
Commit: Stephen Berman <[email protected]>

    Handle file names with newlines in Dired subdirs (bug#81295)
    
    * lisp/dired.el (dired-internal-noselect): Add to the comment
    about displaying a warning about literal newlines a reference to
    needing the same test with subdirs.
    (dired--filename-with-newline-p): If the Dired buffer has subdirs,
    check these for file names with newlines.
    
    * lisp/dired-aux.el (dired-insert-subdir): Test for file names
    with literal newlines in subdirs and if there are display a
    warning.  Add a comment about buggy Dired display when using extra
    'ls' switches on inserting a subdir, and display a temporary
    warning about this (to be removed when the bug is fixed).
---
 lisp/dired-aux.el | 31 ++++++++++++++++++++++++++++++-
 lisp/dired.el     | 21 +++++++++++++++------
 2 files changed, 45 insertions(+), 7 deletions(-)

diff --git a/lisp/dired-aux.el b/lisp/dired-aux.el
index 50287a67129..faa0317dd32 100644
--- a/lisp/dired-aux.el
+++ b/lisp/dired-aux.el
@@ -3356,7 +3356,26 @@ This function takes some pains to conform to `ls -lR' output."
 	(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
+         ;; <https://debbugs.gnu.org/cgi/bugreport.cgi?bug=81295#20> and
+         ;; the following messages and also bug#81522 for discussion.
+         ;; (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 +3401,16 @@ This function takes some pains to conform to `ls -lR' output."
 		 (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 and bug#81522.
+    (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 @@ The return value is the target column for the file names."
     ;; 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 @@ Considers buffers closer to the car of `buffer-list' to be more recent."
        (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."