branch: elpa/dirvish
commit 2d63995d3296c259cef90830cf0433602429ecec
Author: Alex Lu <[email protected]>
Commit: Alex Lu <[email protected]>

    feat: add `dirvish-peek-key` user option (closes #191)
---
 dirvish.el                 |  9 ++++++---
 docs/CUSTOMIZING.org       | 28 +++++++++++++--------------
 docs/EXTENSIONS.org        | 18 ++++++++++++-----
 extensions/dirvish-peek.el | 48 +++++++++++++++++++++++++++++++++++++++++++---
 extensions/dirvish-side.el |  2 +-
 5 files changed, 78 insertions(+), 27 deletions(-)

diff --git a/dirvish.el b/dirvish.el
index 641c8b58b4..de9e96e841 100644
--- a/dirvish.el
+++ b/dirvish.el
@@ -6,7 +6,7 @@
 ;; Keywords: files, convenience
 ;; Homepage: https://github.com/alexluigit/dirvish
 ;; SPDX-License-Identifier: GPL-3.0-or-later
-;; Package-Requires: ((emacs "28.1"))
+;; Package-Requires: ((emacs "28.1") (compat "30"))
 
 ;; This file is not part of GNU Emacs.
 
@@ -22,7 +22,7 @@
 ;;; Code:
 
 (require 'dired)
-(require 'cl-lib)
+(require 'compat)
 
 ;;;; User Options
 
@@ -336,7 +336,10 @@ Set the PROP with BODY if given."
         `val)))
 
 (defun dirvish-run-with-delay (action fun &optional debounce throttle record)
-  "DV ACTION FUN DEBOUNCE THROTTLE RECORD."
+  "Run function FUN accroding to ACTION with delay.
+DEBOUNCE defaults to `dirvish-input-debounce'.
+THROTTLE defaults to `dirvish-input-throttle'.
+RECORD defaults to `dirvish--delay-timer'."
   (declare (indent defun))
   (setq record (or record dirvish--delay-timer)
         debounce (or debounce dirvish-input-debounce)
diff --git a/docs/CUSTOMIZING.org b/docs/CUSTOMIZING.org
index 7baae28b57..8635f059d2 100644
--- a/docs/CUSTOMIZING.org
+++ b/docs/CUSTOMIZING.org
@@ -494,26 +494,24 @@ you don't have to require them explicitly if you 
installed dirvish from MELPA or
         '(vc-state nerd-icons collapse file-size))
   :bind ; Bind `dirvish-fd|dirvish-side|dirvish-dwim' as you see fit
   (("C-c f" . dirvish)
-   :map dirvish-mode-map          ; Dirvish inherits `dired-mode-map'
-   ;; (";" . dired-up-directory)  ; So you can adjust dired bindings here
-   ("?"   . dirvish-dispatch)     ; contains most of sub-menus in dirvish 
extensions
-   ("f"   . dirvish-history-go-forward)
-   ("b"   . dirvish-history-go-backward)
+   :map dirvish-mode-map               ; Dirvish inherits `dired-mode-map'
+   (";"   . dired-up-directory)        ; So you can adjust `dired' bindings 
here
+   ("?"   . dirvish-dispatch)          ; [?] a helpful cheatsheet
+   ("a"   . dirvish-setup-menu)        ; [a]ttributes settings: press `a' + 
`t' toggles mtime, etc.
+   ("f"   . dirvish-file-info-menu)    ; [f]ile info
+   ("o"   . dirvish-quick-access)      ; [o]pen `dirvish-quick-access-entries'
+   ("s"   . dirvish-quicksort)         ; [s]ort flie list
+   ("r"   . dirvish-history-jump)      ; [r]ecent visited
+   ("l"   . dirvish-ls-switches-menu)  ; [l]s command flags
+   ("*"   . dirvish-mark-menu)
    ("y"   . dirvish-yank-menu)
    ("N"   . dirvish-narrow)
    ("^"   . dirvish-history-last)
-   ("s"   . dirvish-setup-menu)   ; `sf' toggles fullframe, `st' toggles 
mtime, etc.
-   ("h"   . dirvish-history-jump) ; remapped `describe-mode'
-   ("r"   . dirvish-quicksort)    ; remapped `dired-sort-toggle-or-edit'
-   ("v"   . dirvish-vc-menu)      ; remapped `dired-view-file'
    ("TAB" . dirvish-subtree-toggle)
-   ("M-a" . dirvish-quick-access)
-   ("M-f" . dirvish-file-info-menu)
-   ("M-l" . dirvish-ls-switches-menu)
-   ("M-m" . dirvish-mark-menu)
+   ("M-f" . dirvish-history-go-forward)
+   ("M-b" . dirvish-history-go-backward)
    ("M-t" . dirvish-layout-toggle)
-   ("M-e" . dirvish-emerge-menu)
-   ("M-j" . dirvish-fd-jump)))
+   ("M-e" . dirvish-emerge-menu)))
 #+end_src
 
 ** Mouse settings
diff --git a/docs/EXTENSIONS.org b/docs/EXTENSIONS.org
index e8ab56331a..b8557144bb 100644
--- a/docs/EXTENSIONS.org
+++ b/docs/EXTENSIONS.org
@@ -117,16 +117,24 @@ a directory, add ~dirvish-emerge-mode~ to 
~dirvish-setup-hook~.
 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.
+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.
 
-The ~dirvish-peek-display-alist~ option allows you to control the window 
placement
-of the peek window.
-
-~dirvish-peek-mode~ currently supports =vertico=, =selectrum=, =ivy= and 
=icomplete[-vertical]=.
+=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)
 
diff --git a/extensions/dirvish-peek.el b/extensions/dirvish-peek.el
index e978b1dbe3..617b5cde6a 100644
--- a/extensions/dirvish-peek.el
+++ b/extensions/dirvish-peek.el
@@ -41,6 +41,18 @@ Notice that the `dirvish-preview-dispatchers' option is 
respected across
 all categories."
   :group 'dirvish :type '(repeat :tag "each item can be 'file 'project-file 
'library" symbol))
 
+;; Credit: copied from `consult-preview-key'
+(defcustom dirvish-peek-key 'any
+  "Preview trigger keys, can be nil, `any', a single key or a list of keys.
+Debouncing can be specified via the `:debounce' attribute.  The
+individual keys must be strings accepted by `key-valid-p'."
+  :group 'dirvish
+  :type '(choice (const :tag "Any key" any)
+                 (list :tag "Debounced" (const :debounce) (float :tag 
"Seconds" 0.1) (const any))
+                 (const :tag "No preview" nil)
+                 (key :tag "Key")
+                 (repeat :tag "List of keys" key)))
+
 (defun dirvish-peek--prepare-cand-fetcher ()
   "Set candidate fetcher according to current completion framework."
   (dirvish-prop :peek-fetcher
@@ -50,6 +62,25 @@ all categories."
           ((bound-and-true-p icomplete-mode)
            (lambda () (car completion-all-sorted-completions))))))
 
+;; Credit: copied from `consult--preview-key-normalize'
+(defun dirvish-peek--normalize-keys (peek-key)
+  "Normalize PEEK-KEY, return alist of keys and debounce times."
+  (let ((keys) (debounce 0))
+    (setq peek-key (ensure-list peek-key))
+    (while peek-key
+      (if (eq (car peek-key) :debounce)
+          (setq debounce (cadr peek-key)
+                peek-key (cddr peek-key))
+        (let ((key (car peek-key)))
+          (cond
+           ((eq key 'any))
+           ((not (key-valid-p key))
+            (error "%S is not a valid key definition; see `key-valid-p'" key))
+           (t (setq key (key-parse key))))
+          (push (cons key debounce) keys))
+        (pop peek-key)))
+    keys))
+
 (dirvish-define-preview peek-exception (file)
   "Handle exceptions when peek files."
   (cond ((string-prefix-p "LIB_EXCEPTION:::" file)
@@ -74,7 +105,14 @@ one of categories in `dirvish-peek-categories'."
          (dv (dirvish--get-session 'curr-layout 'any))
          (win (and dv (dv-preview-window dv))) new-dv)
     (dirvish-prop :peek-category p-category)
-    (when p-category
+    (when (and p-category dirvish-peek-key)
+      (let ((old-map (current-local-map))
+            (map (make-sparse-keymap))
+            (keys (dirvish-peek--normalize-keys dirvish-peek-key)))
+        (pcase-dolist (`(,k . ,_) keys)
+          (unless (or (eq k 'any) (lookup-key old-map k))
+            (define-key map k #'ignore)))
+        (use-local-map (make-composed-keymap map old-map)))
       (dirvish-peek--prepare-cand-fetcher)
       (add-hook 'post-command-hook #'dirvish-peek-update-h 90 t)
       (add-hook 'minibuffer-exit-hook #'dirvish-peek-exit-h nil t)
@@ -89,11 +127,15 @@ one of categories in `dirvish-peek-categories'."
                do (dirvish-prop k (and (functionp v) (funcall v))))
       (dirvish-prop :dv (dv-id new-dv))
       (dirvish-prop :preview-dps
-        (append '(dirvish-peek-exception-dp) (dv-preview-dispatchers 
new-dv))))))
+        (append '(dirvish-peek-exception-dp)
+                (dv-preview-dispatchers new-dv))))))
 
 (defun dirvish-peek-update-h ()
   "Hook for `post-command-hook' to update peek window."
   (when-let* ((category (dirvish-prop :peek-category))
+              (key (this-single-command-keys))
+              (peek-keys (dirvish-peek--normalize-keys dirvish-peek-key))
+              (peek-key (or (assq 'any peek-keys) (assoc key peek-keys)))
               (cand-fetcher (dirvish-prop :peek-fetcher))
               (cand (funcall cand-fetcher))
               (dv (dirvish-curr)))
@@ -112,7 +154,7 @@ one of categories in `dirvish-peek-categories'."
                                    (error-message-string err)))))))
     (dirvish-prop :index cand)
     (dirvish-run-with-delay cand
-      (lambda (action) (dirvish--preview-update dv action)))))
+      (lambda (action) (dirvish--preview-update dv action)) (cdr peek-key))))
 
 (defun dirvish-peek-exit-h ()
   "Hook for `minibuffer-exit-hook' to destroy peek session."
diff --git a/extensions/dirvish-side.el b/extensions/dirvish-side.el
index 0b6e65c33d..87c5eb29f8 100644
--- a/extensions/dirvish-side.el
+++ b/extensions/dirvish-side.el
@@ -171,7 +171,7 @@ after switching to a new project."
 - If the current window is a side session window, hide it.
 - If a side session is visible, select it.
 - If a side session exists but is not visible, show it.
-- If there is no side session exists,create a new one with PATH.
+- If there is no side session exists, create a new one with PATH.
 
 If called with \\[universal-arguments], prompt for PATH,
 otherwise it defaults to `project-current'."

Reply via email to