branch: master commit 082fbbc71f8bd82e02163550d3b7efa261929169 Author: Oleh Krehel <ohwoeo...@gmail.com> Commit: Oleh Krehel <ohwoeo...@gmail.com>
Add a multi-action interface for counsel-locate * ivy-hydra.el (hydra-ivy): Display the current action and allow to scroll the action list with "w" and "s". * ivy.el (ivy--get-action): New defun, a getter for the action function, since it can also be a list now. (ivy--actionp): New defun, checks for the action list. (ivy-next-action): New command, scrolls to the next action in the list. (ivy-prev-action): New command, scrolls to the previous action in the list. (ivy-action-name): New defun. (ivy-call): Use `ivy--get-action'. (ivy-read): Use `ivy--get-action'. --- counsel.el | 26 +++++++++++++++++++++----- ivy-hydra.el | 10 ++++++---- ivy.el | 47 +++++++++++++++++++++++++++++++++++++++++++---- 3 files changed, 70 insertions(+), 13 deletions(-) diff --git a/counsel.el b/counsel.el index 1652b20..0e9375d 100644 --- a/counsel.el +++ b/counsel.el @@ -432,15 +432,31 @@ Skip some dotfiles unless `ivy-text' requires them." (if (string= event "exited abnormally with code 1\n") (message "Error")))) +(defun counsel-locate-action-extern (x) + "Use xdg-open shell command on X." + (call-process shell-file-name nil + nil nil + shell-command-switch + (format "xdg-open %s" (shell-quote-argument x)))) + +(defun counsel-locate-action-dired (x) + "Use `dired-jump' on X." + (dired-jump nil x)) + ;;;###autoload (defun counsel-locate () - "Call locate." + "Call locate shell command." (interactive) - (ivy-read "pattern: " nil + (ivy-read "Locate: " nil :dynamic-collection #'counsel-locate-function - :action (lambda (val) - (when val - (find-file val))))) + :action + (cons + 1 + '(("default" (lambda (val) + (when val + (find-file val)))) + ("xdg-open" counsel-locate-action-extern) + ("dired" counsel-locate-action-dired))))) (defun counsel--generic (completion-fn) "Complete thing at point with COMPLETION-FN." diff --git a/ivy-hydra.el b/ivy-hydra.el index 03e4d20..030978f 100644 --- a/ivy-hydra.el +++ b/ivy-hydra.el @@ -47,9 +47,9 @@ (defhydra hydra-ivy (:hint nil :color pink) " -^^^^^^ ^Yes^ ^No^ ^Maybe^ -^^^^^^^^^^^^^^--------------------------------------- -^ ^ _k_ ^ ^ _f_ollow _i_nsert _c_: calling %s(if ivy-calling \"on\" \"off\") +^^^^^^ ^Yes^ ^No^ ^Maybe^ ^Action^ +^^^^^^^^^^^^^^--------------------------------------------------- +^ ^ _k_ ^ ^ _f_ollow _i_nsert _c_: calling %s(if ivy-calling \"on\" \"off\") _w_/_s_: %s(ivy-action-name) _h_ ^+^ _l_ _d_one _o_ops _m_: matcher %s(if (eq ivy--regex-function 'ivy--regex-fuzzy) \"fuzzy\" \"ivy\") ^ ^ _j_ ^ ^ ^ ^ ^ ^ _<_/_>_: shrink/grow window " @@ -70,7 +70,9 @@ _h_ ^+^ _l_ _d_one _o_ops _m_: matcher %s(if (eq ivy--regex-function 'i ("c" ivy-toggle-calling) ("m" ivy-toggle-fuzzy) (">" ivy-minibuffer-grow) - ("<" ivy-minibuffer-shrink)) + ("<" ivy-minibuffer-shrink) + ("w" ivy-prev-action) + ("s" ivy-next-action)) (provide 'ivy-hydra) diff --git a/ivy.el b/ivy.el index 6ecfb4b..1c5f5b9 100644 --- a/ivy.el +++ b/ivy.el @@ -491,11 +491,50 @@ If the input is empty, select the previous history element instead." (when (setq ivy-calling (not ivy-calling)) (ivy-call))) +(defun ivy--get-action (state) + "Get the action function from STATE." + (let ((action (ivy-state-action state))) + (when action + (if (functionp action) + action + (cadr (nth (car action) action)))))) + +(defun ivy--actionp (x) + "Return non-nil when X is a list of actions." + (and x (listp x) (not (eq (car x) 'closure)))) + +(defun ivy-next-action () + "When the current action is a list, scroll it forwards." + (interactive) + (let ((action (ivy-state-action ivy-last))) + (when (ivy--actionp action) + (unless (>= (car action) (1- (length action))) + (cl-incf (car action)))))) + +(defun ivy-prev-action () + "When the current action is a list, scroll it backwards." + (interactive) + (let ((action (ivy-state-action ivy-last))) + (when (ivy--actionp action) + (unless (<= (car action) 1) + (cl-decf (car action)))))) + +(defun ivy-action-name () + "Return the name associated with the current action." + (let ((action (ivy-state-action ivy-last))) + (if (ivy--actionp action) + (format "[%d/%d] %s" + (car action) + (1- (length action)) + (car (nth (car action) action))) + "[1/1] default"))) + (defun ivy-call () "Call the current action without exiting completion." - (when (ivy-state-action ivy-last) - (with-selected-window (ivy-state-window ivy-last) - (funcall (ivy-state-action ivy-last) ivy--current)))) + (let ((action (ivy--get-action ivy-last))) + (when action + (with-selected-window (ivy-state-window ivy-last) + (funcall action ivy--current))))) (defun ivy-next-line-and-call (&optional arg) "Move cursor vertically down ARG candidates. @@ -787,7 +826,7 @@ candidates with each input." (remove-hook 'post-command-hook #'ivy--exhibit) (when (setq unwind (ivy-state-unwind ivy-last)) (funcall unwind))) - (when (setq action (ivy-state-action ivy-last)) + (when (setq action (ivy--get-action ivy-last)) (funcall action ivy--current)))) (defun ivy--reset-state (state)