Fixing Emacs Dired Defaults: Settings for Better File Management

This article presents a set of Emacs Dired configuration changes to enhance file management. The configurations sort directories before files for easier navigation, hide dotfiles, reduce unnecessary confirmation prompts, prevent UI lockups caused by network latency, among other improvements. Each configuration explains the behavior of the relevant setting, its benefits, and its tradeoffs, making it easier to determine which changes are appropriate.

Keeping Dired clean by hiding dotfiles

Using dired-omit-mode helps hide hidden files and directories, such as .git or .DS_Store, by applying a specific regular expression. The tradeoff is that required configuration files are hidden by default, forcing you to toggle dired-omit-mode off to see them. Disabling dired-omit-verbose prevents the mode from displaying status messages when omitting files.

(setq dired-omit-verbose nil)
(setq dired-omit-files (concat "\\`[.]\\'"
                               "\\|\\.\\(?:elc\\|a\\|o\\|pyc\\|pyo\\|swp\\|class\\)\\'"
                               "\\|^\\.DS_Store\\'"
                               "\\|^\\.\\(?:svn\\|git\\)\\'"
                               "\\|^flycheck_.*"
                               "\\|^flymake_.*"))

(add-hook 'dired-mode-hook #'dired-omit-mode)

To hide all hidden files whose names begin with a dot, add the following regular expression to the dired-omit-files variable:

(setq dired-omit-files (concat dired-omit-files "\\|^\\."))

Hiding details

Enabling dired-hide-details-mode automatically hides file details such as permissions, size, and modification dates.

(add-hook 'dired-mode-hook #'dired-hide-details-mode)

Sorting directories first

The following code snippet configures Dired to sort directories before files. The benefit is improved navigation, as folders are grouped at the top of the buffer, matching standard file managers. The tradeoff is a deviation from strict alphabetical sorting, which can disorient users accustomed to raw UNIX or Linux ls output.

(setq ls-lisp-verbosity nil
      ls-lisp-dirs-first t)

(when (eq system-type 'darwin)
  (setq dired-use-ls-dired nil)) ; macOS/BSD ls

(let ((args "--group-directories-first -ahlv"))
  (when (or (eq system-type 'darwin) (eq system-type 'berkeley-unix))
    (if-let* ((gls (executable-find "gls")))
        (setq insert-directory-program gls)
      (setq args nil)))
  (when args
    (setq dired-listing-switches args)))

Killing the current Dired buffer upon navigating into a different directory

Setting dired-kill-when-opening-new-dired-buffer to t (Emacs >= 28.1) causes Dired to automatically kill the current Dired buffer upon navigating into a different directory. The benefit is a cleaner buffer list, as it prevents leaving behind a trail of open buffers when traversing deep directory hierarchies. The tradeoff is the loss of buffer state. Navigating back to a parent directory requires generating a new buffer, which erases previous cursor positions, active file marks, and modified subdirectory visibility.

(setq dired-kill-when-opening-new-dired-buffer t)

Version control integration

Enabling dired-vc-rename-file causes Dired to perform file renames through the underlying version control system when supported, using the vc-rename-file function. The benefit is accurate version control history during Dired rename operations. The tradeoff is that VC renames can introduce slight latency on very large repositories.

(setq dired-vc-rename-file t)

Simplifying deletion confirmations

This configuration accelerates file cleanup by reducing the number of manual prompts required to delete files and directories.

(setq dired-deletion-confirmer 'y-or-n-p
      dired-recursive-deletes 'top
      dired-clean-confirm-killing-deleted-buffers nil)
  • Setting dired-deletion-confirmer to 'y-or-n-p: Changes the deletion prompt to accept a single 'y' or 'n' keypress instead of requiring you to type the full word 'yes'.
  • Setting dired-recursive-deletes to 'top: By default, deleting a non-empty directory in Dired can be a tedious process because Emacs will prompt you to confirm the deletion of every single nested subdirectory as it traverses down the tree. Setting this variable to 'top establishes a practical balance between speed and safety. Emacs will ask for your confirmation exactly once for the top-level directory you have marked. Once you confirm that initial prompt, it silently and recursively deletes all nested files and folders inside that tree without any further interruptions.
  • Setting dired-clean-confirm-killing-deleted-buffers to nil: Suppresses the prompt that asks for permission to close Dired buffers associated with directories you just deleted, closing them automatically instead. This makes sense because once a directory is removed from the disk, any open buffer pointing to it becomes orphaned and unusable. Automatically killing these dead buffers keeps your buffer list clean, as deleting the directory already establishes your intent to remove it from your workflow entirely.

The benefit is faster file management and fewer repetitive keystrokes. The tradeoff is an elevated risk of accidental data loss, as the safety barrier to executing destructive operations is significantly lowered.

Removing disk space indicator

Disabling dired-free-space (Emacs >= 29.1) removes disk space indicator from Dired buffers. The tradeoff is that you lose quick visibility into remaining disk capacity.

(setq dired-free-space nil)

Restricting vertical cursor movement

Setting dired-movement-style to 'bounded-files (Emacs >= 29.1) restricts vertical movement to file lines in the Dired buffer. When point reaches the first or last file line, further vertical movement stops instead of moving to other non-file lines. The benefit is increased navigation efficiency. When scrolling rapidly to the top or bottom of a directory, the cursor stops exactly on the first or last file or directory, avoiding empty space or metadata lines. The tradeoff is that placing the cursor on the directory header to copy its path requires alternative navigation commands, as standard vertical movement keys will no longer reach it.

(setq dired-movement-style 'bounded-files)

Managing recursive copies and destination directories

These variables force Dired to copy directories recursively by default without prompting, while explicitly asking for confirmation before creating new, non-existent destination directories. The benefit is bulk copying combined with a safety check against typos in destination paths. The tradeoff is that large, deeply nested directory structures might be copied unintentionally since the recursive copying happens automatically.

(setq dired-recursive-copies 'always
      dired-create-destination-dirs 'ask)

Efficient auto-reverting for dired buffers

Configuring dired-auto-revert-buffer to use dired-directory-changed-p causes Dired to automatically revert the buffer when the listed directory has changed. The benefit is improved efficiency because Dired does not unconditionally rebuild the listing. The tradeoff is that changes that do not modify the directory itself, such as in-place edits to existing files, might not trigger an automatic refresh.

(setq dired-auto-revert-buffer 'dired-directory-changed-p)

Note: On Unix-like filesystems, a directory's mtime (modification time) is updated when its directory entries change. This occurs when a file or subdirectory is created, deleted, or renamed within the directory. Modifying the data inside an existing file updates the file's mtime, but does not update the mtime of its parent directory.

Reverting destination buffers after file operations

This configuration automatically updates destination Dired buffers after file operations like copying or renaming, but uses a custom predicate to skip remote directories. The benefit is automatic synchronization of local Dired buffers without performing the same operation on remote directories, avoiding unnecessary TRAMP network activity and associated latency. The tradeoff is that remote directory buffers require a manual refresh to reflect recent file transfers.

(setq dired-do-revert-buffer (lambda (dir)
                               (not (file-remote-p dir))))

Enabling mouse drag-and-drop

Setting dired-mouse-drag-files to t (Emacs >= 29.1) allows you to click and drag files directly from a Dired buffer into external desktop applications, such as graphical file managers or web browsers.

(setq dired-mouse-drag-files t)

Cross-platform file associations

The following snippet configures Dired to open specific file extensions using the default application handler of the host operating system. It identifies the environment (macOS, Linux, or Windows) and assigns the corresponding system command (open, xdg-open, or start) to the dired-guess-shell-alist-user variable for documents, images, and media files. The main benefit is that it delegates file association management to the operating system, removing the need to configure individual applications within Emacs for every file type.

(defvar my-dired-xdg-open-cmd nil)
(with-eval-after-load 'dired
  (when-let* ((cmd (cond
                    ((eq system-type 'darwin)
                     "open")
                    ((memq system-type '(gnu gnu/linux gnu/kfreebsd
                                             berkeley-unix))
                     "xdg-open")
                    ((memq system-type '(cygwin windows-nt ms-dos))
                     "start"))))
    (setq dired-guess-shell-alist-user
          `(("\\.\\(?:docx\\|pdf\\|odt\\|odg\\|ods\\|djvu\\|eps\\)\\'" ,cmd)
            ("\\.\\(?:jpe?g\\|webp\\|png\\|gif\\|xpm\\)\\'" ,cmd)
            ("\\.\\(?:xcf\\)\\'" ,cmd)
            ("\\.tex\\'" ,cmd)
            ("\\.\\(?:mp4\\|mkv\\|m4a\\|avi\\|flv\\|rm\\|rmvb\\|ogv\\)\\(?:\\.part\\)?\\'" ,cmd)
            ("\\.\\(?:mp3\\|flac\\)\\'" ,cmd)))
    (when cmd
      (setq my-dired-xdg-open-cmd cmd))))

How to use it: To use this configuration in practice, navigate to a directory using Dired and place your cursor over a file. For example, if your cursor is on a video file, press ! (which invokes dired-do-shell-command) or & (for asynchronous execution). Dired will prompt you in the minibuffer with the appropriate system command already populated based on your operating system, such as xdg-open. Press RET to confirm, and the video will open in your operating system's default media player.

If you prefer forcing all file types to open asynchronously via the operating system handler (e.g., xdg-open), the following snippet routes every file through the system default application.

(defvar my-dired-xdg-open-cmd nil)
(with-eval-after-load 'dired
  (when-let* ((cmd (cond
                    ((eq system-type 'darwin)
                     "open")
                    ((memq system-type '(gnu gnu/linux gnu/kfreebsd
                                             berkeley-unix))
                     "xdg-open")
                    ((memq system-type '(cygwin windows-nt ms-dos))
                     "start"))))
    (setq dired-guess-shell-alist-user
          `((".*" ,cmd)))
    (when cmd
      (setq my-dired-xdg-open-cmd cmd))))

Leave a Reply

Your email address will not be published. Required fields are marked *