refactor!(dired): use dirvish, drop +ranger

BREAKING CHANGE: This drops the Dired module's +ranger flag and replaces
much of this module's innards with (my maintained fork of) Dirvish,
which provides a spiritually similar (if not superior) experience to
Ranger. Plus, Dirvish makes most of our dired plugins unnecessary.

Also, I am now registering myself as this module's maintainer now that I
dogfood and maintain Dirvish.

Close: #6760
Co-authored-by: alexluigit <alexluigit@users.noreply.github.com>
Co-authored-by: hpfr <hpfr@users.noreply.github.com>
Co-authored-by: LemonBreezes <LemonBreezes@users.noreply.github.com>
Co-authored-by: pharcosyle <pharcosyle@users.noreply.github.com>
This commit is contained in:
Henrik Lissner 2024-08-18 00:09:25 -04:00
parent a8ed6c9f7d
commit e82dab3257
No known key found for this signature in database
GPG key ID: B60957CA074D39A3
4 changed files with 265 additions and 182 deletions

View file

@ -4,28 +4,28 @@
#+since: 2.0.0
* Description :unfold:
This module provides reasonable defaults and augmentations for dired.
This module provides reasonable defaults and augmentations for [[https://www.gnu.org/software/emacs/manual/html_node/emacs/Dired.html][Dired]] (the
built-in file manager for Emacs), powered by [[doom-package:dirvish][Dirvish]].
** Maintainers
/This module has no dedicated maintainers./ [[doom-contrib-maintainer:][Become a maintainer?]]
- [[doom-user:][@hlissner]]
[[doom-contrib-maintainer:][Become a maintainer?]]
** Module flags
- +icons ::
Enables the display of fancy icons depending on file types in dired buffers.
- +ranger ::
Enables dired to be more like [[https://github.com/ranger/ranger][ranger]]. Incompatible with =+dirvish=.
- +dirvish ::
Enables [[https://github.com/alexluigit/dirvish][dirvish]] integration. Incompatible with =+ranger=.
Enables full [[https://github.com/alexluigit/dirvish][dirvish]] integration, providing a more modern interface for Dired
that is reminiscent of [[https://github.com/ranger/ranger][Ranger]].
Without this flag, Dirvish is still installed and used, but only for its minor
augmentations to Dired.
- +icons ::
Enables the display of fancy icons depending on file types in dired buffers,
as well as arrows for expanded/collapsed directories.
** Packages
- [[doom-package:nerd-icons-dired]] if [[doom-module:+icons]]
- [[doom-package:dired-git-info]]
- [[doom-package:diff-hl]]
- [[doom-package:dirvish]]
- [[doom-package:diredfl]]
- [[doom-package:dired-rsync]]
- [[doom-package:dirvish]] if [[doom-module:+dirvish]]
- [[doom-package:fd-dired]]
- [[doom-package:ranger]] if [[doom-module:+ranger]]
** TODO Hacks
#+begin_quote
@ -42,29 +42,124 @@ This module provides reasonable defaults and augmentations for dired.
This module has no requirements *except on BSDs* like MacOS or FreeBSD, where
=GNU ls= (aka ~gls~) is required.
* TODO Usage
#+begin_quote
󱌣 /This module's usage documentation is incomplete./ [[doom-contrib-module:][Complete it?]]
#+end_quote
Optionally, install these dependencies to improve the preview experience:
- =imagemagick= for image previews
- =poppler= (or [[doom-module::tools pdf-tools]]) for pdf previews,
- =ffmpegthumbnailer= for video previews,
- =mediainfo= for audio/video metadata generation,
- =tar= and =unzip= for archive files previews.
| Keybind | Description |
|-------------------+---------------------------------------------|
| [[kbd:][SPC f d]] | Find directory with dired |
| [[kbd:][q]] | Exit dired buffer |
| [[kbd:][C-c C-r]] | Run [[doom-package:dired-rsync]] |
| [[kbd:][C-c C-e]] | Rename entries with [[doom-package:wdired]] |
** macOS
#+begin_src bash :eval no
$ brew install coreutils fd poppler ffmpegthumbnailer mediainfo imagemagick
#+end_src
Other keybindings can be found on the official [[https://www.gnu.org/software/emacs/refcards/pdf/dired-ref.pdf][Dired reference card]].
** Debian-based
#+begin_src bash :eval no
$ apt install fd-find poppler-utils ffmpegthumbnailer mediainfo imagemagick tar unzip
#+end_src
** Ranger
If [[doom-module:+ranger]] is enabled often a buffer will be opened in minimal ranger mode
(~deer-mode~). In this case [[kbd:][z P]] can be used to toggle between full ranger and
~deer-mode~.
** Arch-based
#+begin_src bash :eval no
$ pacman -S fd poppler ffmpegthumbnailer mediainfo imagemagick tar unzip
#+end_src
* TODO Configuration
#+begin_quote
󱌣 This module has no configuration documentation yet. [[doom-contrib-module:][Write some?]]
#+end_quote
** FreeBSD
#+begin_src bash :eval no
$ pkg install gnuls fd-find poppler ffmpegthumbnailer ImageMagick7 gtar
#+end_src
** Windows (not tested)
Via [[https://scoop.sh/][Scoop]]:
#+begin_src bash :eval no
$ scoop install coreutils fd poppler imagemagick unzip
#+end_src
* Usage
** Global bindings
You can access Dired/Dirvish by opening a directory entry in commands like
~find-file (SPC f f)~. Or you can create a Dired buffer directly with these
keybindings.
| Keybind | Description |
|------------------------------+------------------------------------|
| [[kbd:][SPC f d]] | Find directory with dired |
| [[kbd:][SPC o -]] | Jump to current directory in dired |
These commands are available but not bound to any keys.
| Command | Description |
|------------------+--------------------------------|
| [[kbd:][M-x dirvish]] | Open dired with preview |
| [[kbd:][M-x dirvish-dwim]] | Dirvish with smart layout |
| [[kbd:][M-x dirvish-fd]] | Search files in dired using fd |
| [[kbd:][M-x dirvish-side]] | Open project sidebar |
** Dired bindings
*** Basics
| Keybind | Description |
|----------+-------------------------------------------|
| [[kbd:][n]] | Move down a line |
| [[kbd:][p]] | Move up a line |
| [[kbd:][e]] or [[kbd][RET]] | Visit the file or directory on this line |
| [[kbd:][(]] | Toggle visibility of detailed information |
| [[kbd:][q]] | Exit dired buffer |
| [[kbd:][^]] | Go Up a directory |
| [[kbd:][m]] | Mark a file |
| [[kbd:][u]] | Unmark a file |
| [[kbd:][D]] | Delete a file |
| [[kbd:][+]] | Create a directory |
| ... | ... |
This is only a very small sample of dired keybindings, just for you to get a
sense of Dired. Other basic keybindings can be found on the official [[https://www.gnu.org/software/emacs/refcards/pdf/dired-ref.pdf][Dired
reference card]]. If you have enabled ~(evil +everywhere)~, you would get a
different set of bindings ([[kbd][j/k]] for move down/up a line), consult
=evil-collection= for the actual bindings.
*** Extras
You don't have to memorize all of Dired bindings because this module provided a
lot of easy-to-read menus such as ~dirvish-mark-menu~ (powered by
=transient.el=) for you to find the suitable command in a specific context. All
of these (sub-)menus are included in ~dirvish-dispatch (?)~, the main help menu.
Some extremely useful ones are bound to a separate keys as well.
| Keybind | Description |
|---------+------------------------------------------|
| [[kbd:][?]] | Ask for help |
| [[kbd:][a]] | Quick access frequently used directories |
| [[kbd:][f]] | Get file information under the cursor |
| [[kbd:][y]] ... | For copying marked files or their paths |
| [[kbd:][s]] ... | For creating symlinks |
| [[kbd:][S]] | Sort buffer with different criteria |
| [[kbd:][M-m]] | Commands relate to marking and actions |
| [[kbd:][M-s]] | Setup user interface for dirvish |
| [[kbd:][M-e]] | "Emerge" important files at the top |
Other bindings in this module:
| [[kbd:][TAB]] | Expand or contract directory under the cursor |
| [[kbd:][M-f]] | Jump to next dired history entry |
| [[kbd:][M-b]] | Jump to previous dired history entry |
| [[kbd:][M-n]] | Narrow the buffer with user input |
| [[kbd:][M-t]] | Toggle fullscreen (preview) |
| [[kbd:][C-c C-e]] | Rename entries with [[doom-package:wdired]] |
* Configuration
** Quick access entries
Use the following syntax to configure the entries displayed in
~dirvish-quick-access~ command.
#+begin_src emacs-lisp
;;; add to $DOOMDIR/config.el
(after! dirvish
(setq! dirvish-quick-access-entries
`(("h" "~/" "Home")
("e" ,user-emacs-directory "Emacs user directory")
("c" "~/Code/" "Code")
("d" "~/Downloads/" "Downloads")
("m" "/mnt/" "Mounted drives")
("t" "~/.local/share/Trash/files/" "Trash"))))
#+end_src
* Troubleshooting
/There are no known problems with this module./ [[doom-report:][Report one?]]
@ -72,6 +167,9 @@ If [[doom-module:+ranger]] is enabled often a buffer will be opened in minimal r
* Frequently asked questions
/This module has no FAQs yet./ [[doom-suggest-faq:][Ask one?]]
** How to kill all session buffers on quit?
Set ~dirvish-reuse-session~ to nil.
* TODO Appendix
#+begin_quote
󱌣 This module has no appendix yet. [[doom-contrib-module:][Write one?]]

View file

@ -1,9 +1,5 @@
;;; emacs/dired/config.el -*- lexical-binding: t; -*-
(defvar +dired-dirvish-icon-provider 'nerd-icons
"Icon provider to use for dirvish when the module is enabled.")
;;
;;; Packages
@ -11,7 +7,6 @@
:commands dired-jump
:init
(setq dired-dwim-target t ; suggest a target for moving/copying intelligently
dired-hide-details-hide-symlink-targets nil
;; don't prompt to revert, just do it
dired-auto-revert-buffer #'dired-buffer-stale-p
;; Always copy/delete recursively
@ -63,123 +58,146 @@ Fixes #3939: unsortable dired entries on Windows."
:before-while #'dired-buffer-stale-p
(not (eq revert-buffer-function #'dired-virtual-revert)))
(map! :map dired-mode-map
;; Kill all dired buffers on q
:ng "q" #'+dired/quit-all
;; To be consistent with ivy/helm+wgrep integration
"C-c C-e" #'wdired-change-to-wdired-mode))
(use-package! dired-rsync
:general (dired-mode-map "C-c C-r" #'dired-rsync))
(use-package! diredfl
:hook (dired-mode . diredfl-mode))
(use-package! ranger
:when (modulep! +ranger)
:after dired
:init (setq ranger-override-dired t)
:config
(unless (file-directory-p image-dired-dir)
(make-directory image-dired-dir))
(set-popup-rule! "^\\*ranger" :ignore t)
(defadvice! +dired--cleanup-header-line-a ()
"Ranger fails to clean up `header-line-format' when it is closed, so..."
:before #'ranger-revert
(dolist (buffer (buffer-list))
(when (buffer-live-p buffer)
(with-current-buffer buffer
(when (equal header-line-format '(:eval (ranger-header-line)))
(setq header-line-format nil))))))
(defadvice! +dired--cleanup-mouse1-bind-a ()
"Ranger binds an anonymous function to mouse-1 after previewing a buffer
that prevents the user from escaping the window with the mouse. This command is
never cleaned up if the buffer already existed before ranger was initialized, so
we have to clean it up ourselves."
:after #'ranger-setup-preview
(when (window-live-p ranger-preview-window)
(with-current-buffer (window-buffer ranger-preview-window)
(local-unset-key [mouse-1]))))
(defadvice! +dired--ranger-travel-a ()
"Temporary fix for this function until ralesi/ranger.el#236 gets merged."
:override #'ranger-travel
(interactive)
(let ((prompt "Travel: "))
(cond
((bound-and-true-p helm-mode)
(ranger-find-file (helm-read-file-name prompt)))
((bound-and-true-p ivy-mode)
(ivy-read prompt 'read-file-name-internal
:matcher #'counsel--find-file-matcher
:action
(lambda (x)
(with-ivy-window
(ranger-find-file (expand-file-name x default-directory))))))
((bound-and-true-p ido-mode)
(ranger-find-file (ido-read-file-name prompt)))
(t
(ranger-find-file (read-file-name prompt))))))
(setq ranger-cleanup-on-disable t
ranger-excluded-extensions '("mkv" "iso" "mp4")
ranger-deer-show-details t
ranger-max-preview-size 10
ranger-show-literal nil
ranger-hide-cursor nil))
;; To be consistent with vertico/ivy/helm+wgrep integration
(define-key dired-mode-map (kbd "C-c C-e") #'wdired-change-to-wdired-mode))
(use-package! dirvish
:when (modulep! +dirvish)
:defer t
:init (after! dired (dirvish-override-dired-mode))
:hook (dired-mode . dired-omit-mode)
:commands dirvish-find-entry-a dirvish-dired-noselect-a
:general (dired-mode-map "C-c C-r" #'dirvish-rsync)
:init
(setq dirvish-cache-dir (file-name-concat doom-cache-dir "dirvish/"))
;; HACK: ...
(advice-add #'dired-find-file :override #'dirvish-find-entry-a)
(advice-add #'dired-noselect :around #'dirvish-dired-noselect-a)
:config
(require 'dired-x)
(setq dirvish-cache-dir (concat doom-cache-dir "dirvish/")
dirvish-hide-details nil
dirvish-attributes '(git-msg)
dired-omit-files (concat dired-omit-files "\\|^\\..*$"))
(dirvish-override-dired-mode)
(set-popup-rule! "^ ?\\*Dirvish.*" :ignore t)
;; Don't recycle sessions. We don't want leftover buffers lying around,
;; especially if users are reconfiguring Dirvish or trying to recover from an
;; error. It's too easy to accidentally break Dirvish (e.g. by focusing the
;; header window) at the moment, or get stuck in a focus loop with the buried
;; buffers. Starting from scratch isn't even that expensive, anyway.
(setq dirvish-reuse-session nil)
;; A more reserved mode-line height that should match doom-modeline's (or the
;; vanilla mode-line's) height.
(add-hook! 'after-setting-font-hook
(defun +dired-update-mode-line-heigth-h ()
;; REVIEW: Too hardcoded.
(setq dirvish-mode-line-height (+ (frame-char-height) 4)
dirvish-header-line-height (+ (frame-char-height) 8))))
(+dired-update-mode-line-heigth-h)
(if (modulep! +dirvish)
(setq dirvish-attributes '(file-size)
dirvish-mode-line-format
'(:left (sort file-time symlink) :right (omit yank index)))
(setq dirvish-attributes nil
dirvish-use-header-line nil
dirvish-mode-line-format nil))
(when (modulep! :ui vc-gutter)
(push 'vc-state dirvish-attributes))
(when (modulep! +icons)
(push +dired-dirvish-icon-provider dirvish-attributes))
(setq dirvish-subtree-always-show-state t)
(appendq! dirvish-attributes '(nerd-icons subtree-state)))
;; HACK: Doom will treat an integer value for `dirvish-hide-details' to mean
;; hide file/dir details if window is less than N characters wide (e.g. for
;; side windows or small full-window layouts).
(setq dirvish-hide-details 50)
;; TODO: Proc this hook sooner. The delay on `dirvish-setup-hook' is jarring.
(add-hook! 'dirvish-setup-hook
(defun +dired-hide-details-in-side-mode-h ()
(when (integerp dirvish-hide-details)
(dired-hide-details-mode
(if (< (window-width dirvish--selected-window) dirvish-hide-details)
+1 -1)))))
(when (modulep! :ui tabs)
(after! centaur-tabs
(add-hook 'dired-mode-hook #'centaur-tabs-local-mode)
(add-hook 'dirvish-directory-view-mode-hook #'centaur-tabs-local-mode)))
;; TODO: Needs more polished keybinds for non-Evil users
(map! :map dirvish-mode-map
:n "b" #'dirvish-quick-access
:n "z" #'dirvish-history-jump
:n "f" #'dirvish-file-info-menu
:n "F" #'dirvish-layout-toggle
:n "l" #'dired-find-file
:n "h" #'dired-up-directory
:n "TAB" #'dirvish-subtree-toggle
:n "gh" #'dirvish-subtree-up
:n "gl" #'dirvish-subtree-down
:localleader
"h" #'dired-omit-mode))
:n "?" #'dirvish-dispatch
:n "q" #'dirvish-quit
:n "b" #'dirvish-quick-access
:ng "f" #'dirvish-file-info-menu
:n "p" #'dirvish-yank
:ng "S" #'dirvish-quicksort
:n "F" #'dirvish-layout-toggle
:n "z" #'dirvish-history-jump
:n "gh" #'dirvish-subtree-up
:n "gl" #'dirvish-subtree-down
:m "[h" #'dirvish-history-go-backward
:m "]h" #'dirvish-history-go-forward
:m "[e" #'dirvish-emerge-next-group
:m "]e" #'dirvish-emerge-previous-group
:n "TAB" #'dirvish-subtree-toggle
:ng "M-b" #'dirvish-history-go-backward
:ng "M-f" #'dirvish-history-go-forward
:ng "M-n" #'dirvish-narrow
:ng "M-m" #'dirvish-mark-menu
:ng "M-s" #'dirvish-setup-menu
:ng "M-e" #'dirvish-emerge-menu
(:prefix ("y" . "yank")
:n "l" #'dirvish-copy-file-true-path
:n "n" #'dirvish-copy-file-name
:n "p" #'dirvish-copy-file-path
:n "r" #'dirvish-copy-remote-path
:n "y" #'dired-do-copy)
(:prefix ("s" . "symlinks")
:n "s" #'dirvish-symlink
:n "S" #'dirvish-relative-symlink
:n "h" #'dirvish-hardlink))
;; HACK: Kill Dirvish session before switching projects/workspaces, otherwise
;; it errors out on trying to delete/change dedicated windows.
(add-hook! '(persp-before-kill-functions projectile-before-switch-project-hook)
(defun +dired--cleanup-dirvish-h (&rest _)
(when-let ((win
(or (and (featurep 'dirvish-side)
(dirvish-side--session-visible-p))
(and dirvish--this (selected-window)))))
(delete-window win))))
(use-package! nerd-icons-dired
:when (modulep! +icons)
:unless (modulep! +dirvish)
:hook (dired-mode . nerd-icons-dired-mode)
:config
(defadvice! +dired-disable-icons-in-wdired-mode-a (&rest _)
:before #'wdired-change-to-wdired-mode
(setq-local +wdired-icons-enabled (if nerd-icons-dired-mode 1 -1))
(when nerd-icons-dired-mode
(nerd-icons-dired-mode -1)))
;; HACK: If a directory has a .dir-locals.el, its settings could
;; interfere/crash Dirvish trying to preview it.
;; REVIEW: Upstream this later.
(defadvice! +dired--ignore-local-vars-for-dir-previews-a (fn &rest args)
:around #'dirvish-default-dp
(let ((result (apply fn args)))
(if (and (file-directory-p (car args))
(eq (car-safe result) 'dired))
`(dired . (,@(butlast (cdr result))
,(format "(let ((enable-local-variables nil)) %s)"
(car (last (cdr result))))))
result)))
(defadvice! +dired-restore-icons-after-wdired-mode-a (&rest _)
:after #'wdired-change-to-dired-mode
(nerd-icons-dired-mode +wdired-icons-enabled)))
;; HACK: Dirvish will complain that pdf-tools is required to preview PDFs,
;; even if the package is installed, so I advise it to try autoloading it
;; before complaining, otherwise complain if epdfinfo hasn't been built yet.
;; REVIEW: Upstream this later.
(defadvice! +dired--autoload-pdf-tools-a (fn &rest args)
:around #'dirvish-pdf-dp
(when (equal (nth 1 args) "pdf")
(require 'pdf-tools nil t)
(if (file-exists-p pdf-info-epdfinfo-program)
(apply fn args)
'(info . "`epdfinfo' program required to preview pdfs; run `M-x pdf-tools-install'")))))
(use-package! diredfl
:hook (dired-mode . diredfl-mode)
:hook (dirvish-directory-view-mode . diredfl-mode))
(use-package! dired-x
:unless (modulep! +ranger)
:hook (dired-mode . dired-omit-mode)
:config
(setq dired-omit-verbose nil
@ -214,37 +232,8 @@ we have to clean it up ourselves."
"h" #'dired-omit-mode))
(use-package! fd-dired
:when doom-fd-executable
:defer t
:init
(global-set-key [remap find-dired] #'fd-dired)
(set-popup-rule! "^\\*F\\(?:d\\|ind\\)\\*$" :ignore t))
(use-package! dired-aux
:defer t
:config
(setq dired-create-destination-dirs 'ask
dired-vc-rename-file t))
;;;###package dired-git-info
(map! :after dired
:map (dired-mode-map ranger-mode-map)
:ng ")" #'dired-git-info-mode)
(setq dgi-commit-message-format "%h %cs %s"
dgi-auto-hide-details-p nil)
(after! wdired
;; Temporarily disable `dired-git-info-mode' when entering wdired, due to
;; reported incompatibilities.
(defvar +dired--git-info-p nil)
(defadvice! +dired--disable-git-info-a (&rest _)
:before #'wdired-change-to-wdired-mode
(setq +dired--git-info-p (bound-and-true-p dired-git-info-mode))
(when +dired--git-info-p
(dired-git-info-mode -1)))
(defadvice! +dired--reactivate-git-info-a (&rest _)
:after '(wdired-exit
wdired-abort-changes
wdired-finish-edit)
(when +dired--git-info-p
(dired-git-info-mode +1))))

View file

@ -2,3 +2,6 @@
(when (and (featurep :system 'bsd) (not (executable-find "gls")))
(warn! "Cannot find gls (GNU ls). This may cause issues with dired"))
(when (modulep! +ranger)
(warn! "The +ranger flag was removed from this module and does nothing"))

View file

@ -1,14 +1,7 @@
;; -*- no-byte-compile: t; -*-
;;; emacs/dired/packages.el
(package! dirvish
:recipe (:host github :repo "hlissner/dirvish")
:pin "5f046190e886fb0a2dae7e884cc7cd9bcf48ac26")
(package! diredfl :pin "f6d599c30875ab4894c1deab9713ff2faea54e06")
(package! dired-git-info :pin "6b6f2a5d716debba9a7dcac623d5a1e4c799eb62")
(package! dired-rsync :pin "5bcb851f3bf9c4f7c07299fcc25be7c408a68cda")
(when (modulep! +ranger)
(package! ranger :pin "2498519cb21dcd5791d240607a72a204d1761668"))
(when (modulep! +dirvish)
(package! dirvish :pin "119f9f59a618bb7b476c93e9ab1d7542c5c1df41"))
(when (and (modulep! +icons)
(not (modulep! +dirvish)))
(package! nerd-icons-dired :pin "c1c73488630cc1d19ce1677359f614122ae4c1b9"))
(package! fd-dired :pin "458464771bb220b6eb87ccfd4c985c436e57dc7e")