diff --git a/etc/NEWS b/etc/NEWS index a6abd23b4ac..25cddfa58e1 100644 --- a/etc/NEWS +++ b/etc/NEWS @@ -2536,7 +2536,8 @@ names relative to the root directory of the current project. +++ *** Warning when Dired displays a file name with a literal newline. -On visiting a directory that contains a file whose name has a newline, +If Dired uses an 'ls' implementation that supports the '-b' switch, then +on visiting a directory that contains a file whose name has a newline, and Dired displays that character as a literal newline, Emacs now automatically pops up a buffer warning that such a display can be problematic for Dired and showing a way to change the display to use the @@ -2544,7 +2545,8 @@ unproblematic character '\n'. +++ *** New user option 'dired-auto-toggle-b-switch'. -When this user option is non-nil and 'dired-listing-switches' does not +When this user option is non-nil and Dired uses an 'ls' implementation +that supports the '-b' switch and 'dired-listing-switches' does not include the '-b' switch, then on visiting a directory containing a file whose name has a newline, Emacs automatically adds the '-b' switch and redisplays the directory in Dired to show '\n' in the file name instead diff --git a/lisp/dired.el b/lisp/dired.el index 9b7b1271e66..9ce3f042f6b 100644 --- a/lisp/dired.el +++ b/lisp/dired.el @@ -553,7 +553,8 @@ displayed instead." (defcustom dired-auto-toggle-b-switch nil "Whether to automatically add or remove the `b' switch. If non-nil, the function `dired--toggle-b-switch' (which see) is added -to `post-command-hook' in Dired mode." +to `post-command-hook' in Dired mode, unless the `ls' used by Dired does +not accept the `b' switch." :type 'boolean :group 'dired :initialize #'custom-initialize-default @@ -1472,15 +1473,16 @@ The return value is the target column for the file names." (dired-initial-position dirname)) (when (consp dired-directory) (dired--align-all-files)) - ;; Pop up a warning if the Dired listing displays a literal newline. - ;; 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. + ;; Pop up a warning if the Dired listing displays a literal newline + ;; 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. (unless (or dired-auto-toggle-b-switch (dired-switches-escape-p dired-listing-switches) (dired-switches-escape-p dired-actual-switches)) - (when (dired--filename-with-newline-p) + (when (and (dired--filename-with-newline-p) + (dired--ls-accept-b-switch-p)) (dired--display-filename-with-newline-warning buffer))) (set-buffer old-buf) buffer)) @@ -4054,6 +4056,10 @@ newline character (regardless of whether Dired displays the character as a literal newline or as \"\\n\")." (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." + (eq 0 (call-process insert-directory-program nil nil nil "-b"))) + (defun dired--remove-b-switch () "Remove all variants of the `b' switch from `dired-actual-switches'. This removes not only all occurrences of the short form `-b' but also @@ -4071,8 +4077,9 @@ the long forms `--escape' and `--quoting-style=escape'." "Add or remove `b' switch and redisplay Dired buffer. When the current Dired buffer has a file name containing a newline, add the `b' switch to the actual switches if it isn't already among them; -otherwise remove the `b' switch unless it is in `dired-listing-switches'. -Then redisplay the Dired buffer. This function is called from +otherwise remove the `b' switch unless it is in +`dired-listing-switches'. Then redisplay the Dired buffer. When +`dired-auto-toggle-b-switch' is non-nil, this function is called from `post-command-hook' in Dired mode buffers." (when (eq major-mode 'dired-mode) (if (and (dired--filename-with-newline-p) dired-auto-toggle-b-switch) @@ -4087,12 +4094,13 @@ Then redisplay the Dired buffer. This function is called from (defun dired--set-auto-toggle-b-switch (symbol value) "The :set function for user option `dired-auto-toggle-b-switch'." (custom-set-default symbol value) - (if value - (add-hook 'post-command-hook #'dired--toggle-b-switch nil t) - (remove-hook 'post-command-hook #'dired--toggle-b-switch t)) - (dolist (b (buffer-list)) - (with-current-buffer b - (dired--toggle-b-switch)))) + (when (dired--ls-accept-b-switch-p) + (if value + (add-hook 'post-command-hook #'dired--toggle-b-switch nil t) + (remove-hook 'post-command-hook #'dired--toggle-b-switch t)) + (dolist (b (buffer-list)) + (with-current-buffer b + (dired--toggle-b-switch))))) (defun dired--display-filename-with-newline-warning (dir) "Display a warning if buffer DIR has a file name with a newline." diff --git a/test/lisp/dired-tests.el b/test/lisp/dired-tests.el index f5f92fd6485..b2e0f257a15 100644 --- a/test/lisp/dired-tests.el +++ b/test/lisp/dired-tests.el @@ -663,6 +663,7 @@ The current directory at call time should not affect the result (Bug#50630)." ;; File names with embedded newlines are not allowed on MS-Windows and ;; MS-DOS. (skip-when (memq system-type '(windows-nt ms-dos))) + (skip-unless (dired--ls-accept-b-switch-p)) (with-current-buffer "*Messages*" (let ((inhibit-read-only t)) (erase-buffer))) @@ -698,6 +699,7 @@ The current directory at call time should not affect the result (Bug#50630)." ;; File names with embedded newlines are not allowed on MS-Windows and ;; MS-DOS. (skip-when (memq system-type '(windows-nt ms-dos))) + (skip-unless (dired--ls-accept-b-switch-p)) (with-current-buffer "*Messages*" (let ((inhibit-read-only t)) (erase-buffer)))