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 #+since: 2.0.0
* Description :unfold: * 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 ** Maintainers
/This module has no dedicated maintainers./ [[doom-contrib-maintainer:][Become a maintainer?]] - [[doom-user:][@hlissner]]
[[doom-contrib-maintainer:][Become a maintainer?]]
** Module flags ** 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 :: - +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 ** Packages
- [[doom-package:nerd-icons-dired]] if [[doom-module:+icons]] - [[doom-package:dirvish]]
- [[doom-package:dired-git-info]]
- [[doom-package:diff-hl]]
- [[doom-package:diredfl]] - [[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 ** TODO Hacks
#+begin_quote #+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 This module has no requirements *except on BSDs* like MacOS or FreeBSD, where
=GNU ls= (aka ~gls~) is required. =GNU ls= (aka ~gls~) is required.
* TODO Usage Optionally, install these dependencies to improve the preview experience:
#+begin_quote - =imagemagick= for image previews
󱌣 /This module's usage documentation is incomplete./ [[doom-contrib-module:][Complete it?]] - =poppler= (or [[doom-module::tools pdf-tools]]) for pdf previews,
#+end_quote - =ffmpegthumbnailer= for video previews,
- =mediainfo= for audio/video metadata generation,
- =tar= and =unzip= for archive files previews.
| Keybind | Description | ** macOS
|-------------------+---------------------------------------------| #+begin_src bash :eval no
| [[kbd:][SPC f d]] | Find directory with dired | $ brew install coreutils fd poppler ffmpegthumbnailer mediainfo imagemagick
| [[kbd:][q]] | Exit dired buffer | #+end_src
| [[kbd:][C-c C-r]] | Run [[doom-package:dired-rsync]] |
| [[kbd:][C-c C-e]] | Rename entries with [[doom-package:wdired]] |
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 ** Arch-based
If [[doom-module:+ranger]] is enabled often a buffer will be opened in minimal ranger mode #+begin_src bash :eval no
(~deer-mode~). In this case [[kbd:][z P]] can be used to toggle between full ranger and $ pacman -S fd poppler ffmpegthumbnailer mediainfo imagemagick tar unzip
~deer-mode~. #+end_src
* TODO Configuration ** FreeBSD
#+begin_quote #+begin_src bash :eval no
󱌣 This module has no configuration documentation yet. [[doom-contrib-module:][Write some?]] $ pkg install gnuls fd-find poppler ffmpegthumbnailer ImageMagick7 gtar
#+end_quote #+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 * Troubleshooting
/There are no known problems with this module./ [[doom-report:][Report one?]] /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 * Frequently asked questions
/This module has no FAQs yet./ [[doom-suggest-faq:][Ask one?]] /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 * TODO Appendix
#+begin_quote #+begin_quote
󱌣 This module has no appendix yet. [[doom-contrib-module:][Write one?]] 󱌣 This module has no appendix yet. [[doom-contrib-module:][Write one?]]

View file

@ -1,9 +1,5 @@
;;; emacs/dired/config.el -*- lexical-binding: t; -*- ;;; 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 ;;; Packages
@ -11,7 +7,6 @@
:commands dired-jump :commands dired-jump
:init :init
(setq dired-dwim-target t ; suggest a target for moving/copying intelligently (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 ;; don't prompt to revert, just do it
dired-auto-revert-buffer #'dired-buffer-stale-p dired-auto-revert-buffer #'dired-buffer-stale-p
;; Always copy/delete recursively ;; Always copy/delete recursively
@ -63,123 +58,146 @@ Fixes #3939: unsortable dired entries on Windows."
:before-while #'dired-buffer-stale-p :before-while #'dired-buffer-stale-p
(not (eq revert-buffer-function #'dired-virtual-revert))) (not (eq revert-buffer-function #'dired-virtual-revert)))
(map! :map dired-mode-map ;; To be consistent with vertico/ivy/helm+wgrep integration
;; Kill all dired buffers on q (define-key dired-mode-map (kbd "C-c C-e") #'wdired-change-to-wdired-mode))
: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))
(use-package! dirvish (use-package! dirvish
:when (modulep! +dirvish) :commands dirvish-find-entry-a dirvish-dired-noselect-a
:defer t :general (dired-mode-map "C-c C-r" #'dirvish-rsync)
:init (after! dired (dirvish-override-dired-mode)) :init
:hook (dired-mode . dired-omit-mode) (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 :config
(require 'dired-x) (dirvish-override-dired-mode)
(setq dirvish-cache-dir (concat doom-cache-dir "dirvish/") (set-popup-rule! "^ ?\\*Dirvish.*" :ignore t)
dirvish-hide-details nil
dirvish-attributes '(git-msg) ;; Don't recycle sessions. We don't want leftover buffers lying around,
dired-omit-files (concat dired-omit-files "\\|^\\..*$")) ;; 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) (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 (map! :map dirvish-mode-map
:n "b" #'dirvish-quick-access :n "?" #'dirvish-dispatch
:n "z" #'dirvish-history-jump :n "q" #'dirvish-quit
:n "f" #'dirvish-file-info-menu :n "b" #'dirvish-quick-access
:n "F" #'dirvish-layout-toggle :ng "f" #'dirvish-file-info-menu
:n "l" #'dired-find-file :n "p" #'dirvish-yank
:n "h" #'dired-up-directory :ng "S" #'dirvish-quicksort
:n "TAB" #'dirvish-subtree-toggle :n "F" #'dirvish-layout-toggle
:n "gh" #'dirvish-subtree-up :n "z" #'dirvish-history-jump
:n "gl" #'dirvish-subtree-down :n "gh" #'dirvish-subtree-up
:localleader :n "gl" #'dirvish-subtree-down
"h" #'dired-omit-mode)) :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 ;; HACK: If a directory has a .dir-locals.el, its settings could
:when (modulep! +icons) ;; interfere/crash Dirvish trying to preview it.
:unless (modulep! +dirvish) ;; REVIEW: Upstream this later.
:hook (dired-mode . nerd-icons-dired-mode) (defadvice! +dired--ignore-local-vars-for-dir-previews-a (fn &rest args)
:config :around #'dirvish-default-dp
(defadvice! +dired-disable-icons-in-wdired-mode-a (&rest _) (let ((result (apply fn args)))
:before #'wdired-change-to-wdired-mode (if (and (file-directory-p (car args))
(setq-local +wdired-icons-enabled (if nerd-icons-dired-mode 1 -1)) (eq (car-safe result) 'dired))
(when nerd-icons-dired-mode `(dired . (,@(butlast (cdr result))
(nerd-icons-dired-mode -1))) ,(format "(let ((enable-local-variables nil)) %s)"
(car (last (cdr result))))))
result)))
(defadvice! +dired-restore-icons-after-wdired-mode-a (&rest _) ;; HACK: Dirvish will complain that pdf-tools is required to preview PDFs,
:after #'wdired-change-to-dired-mode ;; even if the package is installed, so I advise it to try autoloading it
(nerd-icons-dired-mode +wdired-icons-enabled))) ;; 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 (use-package! dired-x
:unless (modulep! +ranger)
:hook (dired-mode . dired-omit-mode) :hook (dired-mode . dired-omit-mode)
:config :config
(setq dired-omit-verbose nil (setq dired-omit-verbose nil
@ -214,37 +232,8 @@ we have to clean it up ourselves."
"h" #'dired-omit-mode)) "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 (use-package! dired-aux
:defer t :defer t
:config :config
(setq dired-create-destination-dirs 'ask (setq dired-create-destination-dirs 'ask
dired-vc-rename-file t)) 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"))) (when (and (featurep :system 'bsd) (not (executable-find "gls")))
(warn! "Cannot find gls (GNU ls). This may cause issues with dired")) (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; -*- ;; -*- no-byte-compile: t; -*-
;;; emacs/dired/packages.el ;;; emacs/dired/packages.el
(package! dirvish
:recipe (:host github :repo "hlissner/dirvish")
:pin "5f046190e886fb0a2dae7e884cc7cd9bcf48ac26")
(package! diredfl :pin "f6d599c30875ab4894c1deab9713ff2faea54e06") (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")