#+AUTHOR: Alex Lu
#+EMAIL: alexluigit@gmail.com
#+startup: content

Several small extension packages to Dirvish are maintained in the subdirectory
/extensions/.  They are installed together with Dirvish if you pull the package
from MELPA.  All of these extensions are inactive by default and will be loaded
on demand (usually you don't have to require them explicitly).

These extensions can augment Dirvish through different ways such as providing
extra commands/attributes/preview methods, improving UI by the help of
=transient.el=, integration with external tools, among other things.  With them it
is possible to adapt Dirvish such that it matches your preference or behaves
similar to other familiar file explorers.

* Multi-stage copy/pasting of files (dirvish-yank.el)

Here is a quote from [[https://github.com/Fuco1/dired-hacks][dired-ranger]] that justified the ~dired-ranger-move/paste~ commands:

#+begin_quote
A feature present in most orthodox file managers is a "two-stage" copy/paste
process. Roughly, the user first selects some files, "copies" them into a
clipboard and then pastes them to the target location. This workflow is missing
in dired.

In dired, user first marks the files, then issues the dired-do-copy command
which prompts for the destination. The files are then copied there. The
dired-dwim-target option makes this a bit friendlier---if two dired windows are
opened, the other one is automatically the default target.

With the multi-stage operations, you can gather files from multiple dired
buffers into a single "clipboard", then copy or move all of them to the target
location.
#+end_quote

In addition to implementing the core logic described above, this extension also
supports several frequently used commands.  To transfer files from source to
destination, mark the desired files, navigate to the destination, and use one of
the =dirvish-yank=, =dirvish-move=, =dirvish-symlink=, =dirvish-relative-symlink= or
=dirvish-hardlink= commands to complete the transfer.  All of these commands are
executed *ASYNCHRONOUSLY* without any extra setups.

See also: [[https://github.com/alexluigit/dirvish/blob/main/docs/FAQ.org#dired-ranger][comparison with dired-ranger]]

* Integration with *rsync* command (dirvish-rsync.el)

This extension introduces =dirvish-rsync=, which requires [[https://github.com/RsyncProject/rsync][rsync]] executable,
mirroring the functionality of Alex Bennée's =dired-rsync=.  It also provides a
transient menu =dirvish-rsync-switches-menu=, for temporary adjustments to
=dirvish-rsync-args=.

** Compare to =dired-rsync=

+ =dirvish-rsync= also handles file operations on the same remote host.
  See: https://github.com/stsquad/dired-rsync/issues/24.

+ =dirvish-rsync= takes advantages of the same multi-stage action mechanism in
  =dirvish-yank=.  Meaning that you should mark files first then goto target
  directory and invoke =dirvish-rsync= there, instead of trying to do it in the
  way of =dired-do-copy=.

+ It gathers marked files from multiple Dired buffers.

** User options

Configure ~dirvish-rsync-program~ and ~dirvish-rsync-args~ to specify the executable
path and command line arguments of =rsync=.

~dirvish-rsync-r2r-ssh-port~, ~dirvish-rsync-r2r-ssh-user~ and
~dirvish-rsync-r2r-use-direct-connection~ are provided to deal with the remote to
remote connections (thanks to @dvzubarev).

Use ~dirvish-rsync-shortcut-key-for-yank-menu~ and ~dirvish-rsync-use-yank-menu~ to
adjust the shortcut key of =dirvish-rsync= in =dirvish-yank-menu=.

* Group files with custom filter stack (dirvish-emerge.el)

This extension organizes your file list into groups based on your chosen
criteria, presented similarly to ~ibuffer~.  You can collapse and expand these
groups by pressing ~TAB~ on the group header. For a quick demonstration, see this
video:

https://user-images.githubusercontent.com/16313743/190387614-16f8d660-7e48-483b-ae54-db471324b4e0.mp4

The variable ~dirvish-emerge-groups~ specifies filter criteria for groups. In the
video, the value used appears to be:

#+begin_src emacs-lisp
;; Header string |    Type    |    Criterias
'(("Recent files"  (predicate . recent-files-2h))
  ("Documents"     (extensions "pdf" "tex" "bib" "epub"))
  ("Video"         (extensions "mp4" "mkv" "webm"))
  ("Pictures"      (extensions "jpg" "png" "svg" "gif"))
  ("Audio"         (extensions "mp3" "flac" "wav" "ape" "aac"))
  ("Archives"      (extensions "gz" "rar" "zip")))
#+end_src

Avoid manually editing this variable. The recommended way to modify, compose,
apply, or save it (to *.dir-locals.el*) is with the ~dirvish-emerge-menu~ transient
menu, which is how the value above was created.

While you can set this variable globally, saving it to *.dir-locals.el* is more
preferable because:

+ Different directory types may require different groups to be emerged.
+ Applying these filters in large directories can take a significant amount of time.

To ensure the groups defined in ~dirvish-emerge-groups~ are emerged upon entering
a directory, add ~dirvish-emerge-mode~ to ~dirvish-setup-hook~.

#+begin_src emacs-lisp
(add-hook 'dirvish-setup-hook 'dirvish-emerge-mode)
#+end_src

* Minibuffer file preview (dirvish-peek.el)

This extension introduces =dirvish-peek-mode=, a minor mode that enables file
previews within the minibuffer as you narrow down candidates.  By leveraging
=dirvish.el= for its core functionality, it delivers a seamless and consistent
preview experience.  It currently supports =vertico=, =ivy= and =icomplete=.

https://user-images.githubusercontent.com/16313743/158052790-22e6cf49-e18e-435c-908e-f5d91ba316a6.mp4

*Figure 1.* A demo of ~find-library~ and ~find-file~ commands after ~dirvish-peek-mode~ enabled.

=dirvish-peek-mode= enables previews by default. You can disable them by adjusting
the =dirvish-peek-key= variable (adopted from ~consult-preview-key~).  Furthermore
it is possible to specify keybindings which trigger the preview manually. The
default setting of =dirvish-peek-key= is =any= which means that =dirvish-peek-mode=
triggers the preview /immediately/ on any key press when the selected candidate
changes.  The following settings are possible:

- Automatic and immediate ='any=
- Automatic and delayed =(list :debounce 0.5 'any)=
- Manual and immediate ="M-."=
- Manual and delayed =(list :debounce 0.5 "M-.")=
- Disabled =nil=

* Version-control (*git*) integration (dirvish-vc.el)

This extension gives Dirvish the ablity to display version-control data in
different ways.  For now we have:

+ ~vc-state~: an attribute to display the VC state as a bitmap at left fringe
+ ~git-msg~: an attribute to display git commit messages after the file name
+ ~vc-[log|diff|blame]~: VC info preview dispatchers

Be sure to put the ~vc-**~ preview dispatcher at the *beginning* of
~dirvish-preview-dispatchers~ if you want to enable them by default, otherwise the
preview content might be intercepted by other preview dispatchers.

These 3 ~vc-*~ preview dispatchers are mutually exclusive, which means you should
/not/ set ~dirvish-preview-dispatchers~ like this:

#+begin_src emacs-lisp
;; `vc-diff' will be ignored
(vc-log vc-diff ...)
#+end_src

The ~dirvish-vc-menu~ (bound to =? v= by default) allows you to call all available
VC commands, it also provides a way to cycle through the ~vc-*~ preview methods.

[[https://user-images.githubusercontent.com/16313743/182787337-92222d67-c57c-4037-ac11-7280be92ce78.mp4][https://user-images.githubusercontent.com/16313743/182787337-92222d67-c57c-4037-ac11-7280be92ce78.mp4]]

*Figure 2*. Toggle ~vc-state~ and ~git-msg~ (attribute), cycle through ~vc-[log|diff|blame]~.

* Show icons at front of file name (dirvish-icons.el)

This extension provides file icons integration from various backends:

+ ~nerd-icons~:    https://github.com/rainstormstudio/nerd-icons.el
+ ~all-the-icons~: https://github.com/domtronn/all-the-icons.el
+ ~vscode-icon~:   https://github.com/jojojames/vscode-icon-emacs

To tweak the appearance of the icons, you have these options:

+ ~dirvish-all-the-icons-height~: Height of icons from =all-the-icons=.
+ ~dirvish-all-the-icons-offset~: Vertical offset of icons from =all-the-icons=.
+ ~dirvish-all-the-icons-palette~: Coloring style used for =all-the-icons=.
+ ~dirvish-vscode-icon-size~: Image size of icons from =vscode-icon=.

* Toggle Dirvish in side window (dirvish-side.el)

This extension provides the ~dirvish-side~ command, which toggles a Dirvish
sidebar within the current frame.  The width is fixed to prevent the window from
unexpected resizing, but you can adjust it using the ~dirvish-side-increase-width~
and ~dirvish-side-decrease-width~ commands.

When ~dirvish-side-follow-mode~ is enabled, the visible side session will select
the current buffer's filename, similar to ~treemacs-follow-mode~ in =treemacs=. It
will also visits the latest ~project-root~ after switching to a new project.

These customization options are available:

+ ~dirvish-side-attributes~: like ~dirvish-attributes~, but for side window.
+ ~dirvish-side-mode-line-format~: like ~dirvish-mode-line-format~, but for side window.
+ ~dirvish-side-header-line-format~: like ~dirvish-header-line-format~, but for side window.
+ ~dirvish-side-display-alist~: Display actions for the side window.
+ ~dirvish-side-window-parameters~: Window parameters for the side window.
+ ~dirvish-side-width~: Width of the side window.
+ ~dirvish-side-open-file-action~: Action to perform before opening a file in a side window.
+ ~dirvish-side-auto-expand~: Whether to auto expand parent directories of current file.

* Setup ls switches on the fly (dirvish-ls.el)

This extension provides commands to changing the ls listing switches like a
breeze. No manual editing anymore!

[[https://user-images.githubusercontent.com/16313743/178141860-784e5744-a5b7-4a7b-9bdb-f0f981ca2dba.svg][https://user-images.githubusercontent.com/16313743/178141860-784e5744-a5b7-4a7b-9bdb-f0f981ca2dba.svg]]

*Figure 3*. left: ~dirvish-quicksort~  right: ~dirvish-ls-switches-menu~

* Turn Dirvish into a tree browser (dirvish-subtree.el)

This extension enhances Dirvish with the ~dirvish-subtree-toggle~ command, a
streamlined alternative to =dired-subtree= for toggling a directory under the
cursor as a subtree.

+ To visually indicate the expansion state of directories, add ~subtree-state~ to
  ~dirvish-attributes~.

+ Customize the appearance of the expansion indicator using
  ~dirvish-subtree-state-style~ and ~dirvish-subtree-icon-scale-factor~ to adjust
  its placement and size.  See this [[https://github.com/alexluigit/dirvish/issues/185][related issue]]

+ To hide the indicator when no directories are expanded, set
  ~dirvish-subtree-always-show-state~ to nil.

* History navigation (dirvish-history.el)

This extension offers a collection of straightforward and useful history
navigation commands.

*Commands*:

+ ~dirvish-history-jump~         Go to recently visited directories
+ ~dirvish-history-go-forward~   Go forward history (session locally)
+ ~dirvish-history-go-backward~  Go backward history (session locally)
+ ~dirvish-history-last~         Go to most recent used Dirvish buffer

*Options*:

+ =dirvish-history-sort-function=
  Sorting criteria for ~dirvish-history-jump~ command.

* Quick keys for frequently visited places (dirvish-quick-access.el)

This extension gives you the ability of jumping to anywhere in the filesystem
with minimal (2 usually) keystrokes.  Just define the entries in
~dirvish-quick-access-entries~ and access them by calling ~dirvish-quick-access~.

* Collapse unique nested paths (dirvish-collapse.el)

This extension provides the ~collapse~ attribute.

#+begin_quote
Often times we find ourselves in a situation where a single file or directory is
nested in a chain of nested directories with no other content. This is sometimes
due to various mandatory layouts demanded by packaging tools or tools generating
these deeply-nested "unique" paths to disambiguate architectures or versions
(but we often use only one anyway). If the user wants to access these
directories they have to quite needlessly drill-down through varying number of
"uninteresting" directories to get to the content.

                                                   -- from [[https://github.com/Fuco1/dired-hacks][dired-collapse]]
#+end_quote

See also: [[https://github.com/alexluigit/dirvish/blob/main/docs/FAQ.org#dired-collapse][comparison with dired-collapse]]

* Live-narrowing of Dirvish buffer (dirvish-narrow.el)

This extension provides live filtering of files within Dirvish buffers. Invoke
~dirvish-narrow~, then type a filter string in the minibuffer, the buffer updates
automatically as you type. Press =RET= to finalize the narrowed view, or =C-g= to
cancel and restore the original buffer.  To restore the full view after
finalizing with =RET=, use ~revert-buffer~ (typically bound to =g=).

https://github.com/user-attachments/assets/539e1a74-ddf2-41fa-9dc2-3358108828fc

If [[https://github.com/oantolin/orderless][orderless]] is installed, it is automatically used to generate the
=completion-regexp-list= from your input string for file list filtering. The
matching style is determined by your =orderless= configuration. If =orderless= is
not available, the regexp list is generated using ~split-string~ instead.

~dirvish-narrow~ also operates within buffers generated by ~dirvish-fd~.  When
narrowing in such buffers, input starting with "#" enables two-stage filtering.
A new =fd= process is spawned whenever the minibuffer input changes.  The portion
of the input immediately following the initial "#" is passed as a pattern
argument to =fd=, while the remainder of the input (after the =fd= pattern) serves
as a secondary filter applied by Dirvish. For example, with the minibuffer input
=#foo,bar baz=, the =fd= process runs with a pattern like =--and=foo --and=bar=, and
its results are then filtered within Dirvish using =baz=.  If you remove the
leading "#" character, =fd= is instructed to list all entries recursively without
any pattern filtering, and the entire minibuffer content is used as the filter
pattern within Dirvish.  This two-level filtering is advantageous for
directories containing a large number of files (e.g. =/= or =$HOME=), as the initial
=fd= filtering significantly reduces the processing time.
