summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorOmar Antolín <omar.antolin@gmail.com>2023-12-06 10:21:14 -0600
committerOmar Antolín <omar.antolin@gmail.com>2023-12-06 10:21:14 -0600
commit95517246d8ef5cd837cd315f4689e922202d3df5 (patch)
tree2aa9c6868a8d35559f2f72bafc59e67a68256cc6
parentb24295ea889420dca1edca10f9c0ab0d293168d3 (diff)
parenta05b77f49069e024cbe3018eade3e8bd0ee4769a (diff)
Merge branch 'consult-grep-dwim'
-rw-r--r--CHANGELOG.org10
-rw-r--r--README.org17
-rw-r--r--embark-consult.el53
-rw-r--r--embark.el59
-rw-r--r--embark.texi15
5 files changed, 84 insertions, 70 deletions
diff --git a/CHANGELOG.org b/CHANGELOG.org
index c5894a3..f3ed5ff 100644
--- a/CHANGELOG.org
+++ b/CHANGELOG.org
@@ -1,6 +1,16 @@
#+title: Embark changelog
* Development version
+- You can now use around action hooks with multitarget actions (that
+ you couldn't previously was an oversight).
+- Users of the =embark-consult= package can now use consult async search
+ commands such as =consult-grep= as multitarget actions (through
+ =embark-act-all=) to search a list of files. For example, you can use
+ =consult-find= to search among file /names/ and once you have the
+ relevant files in the minibuffer, you can use =embark-act-all= to
+ search for some text in those files. When acting on buffers consult
+ async search commands will search the associated file if there is
+ one, or else the =default-directory= of the buffer.
- =embark-bindings= and similar commands now show definition of keyboard
macros.
- =embark-org= now recognizes Org links in non-org buffers.
diff --git a/README.org b/README.org
index 9bf5593..a010932 100644
--- a/README.org
+++ b/README.org
@@ -1094,11 +1094,18 @@ Besides those exporters and candidate collectors, the =embark-consult=
package provides many subtle tweaks and small integrations between
Embark and Consult. Some examples are:
-- The asynchronous search commands will start in the directory
- associated to the Embark target if that target is a file, buffer,
- bookmark or Emacs Lisp library.
-
- - For all other target types, a Consult search command (asynchronous
+- When used as actions, the asynchronous search commands will search
+ only the files associated to the targets: if the targets /are/ files,
+ it searches those files; for buffers it will search either the
+ associated file if there is one, else all files in the buffer's
+ =default-directory=; for bookmarks it will search the file they point
+ to, same for Emacs Lisp libraries. This is particularly powerful
+ when using =embark-act-all= to act on multiple files at once, for
+ example you can use =consult-find= to search among file /names/ and then
+ =embark-act-all= and =consult-grep= to search within the matching files.
+
+ - For all other target types, those that do not have a sensible
+ notion of associated file, a Consult search command (asynchronous
or not) will search for the text of the target but leave the
minibuffer open so you can interact with the Consult command.
diff --git a/embark-consult.el b/embark-consult.el
index f92c1cb..c89b178 100644
--- a/embark-consult.el
+++ b/embark-consult.el
@@ -362,47 +362,26 @@ This is intended to be used in `embark-target-injection-hooks'."
(cl-pushnew #'embark-consult--unique-match
(alist-get cmd embark-target-injection-hooks)))
-(cl-defun embark-consult--prep-async (&key type target &allow-other-keys)
- "Either add Consult's async separator or ignore the TARGET depending on TYPE.
-If the TARGET of the given TYPE has an associated notion of
-directory, we don't want to search for the text of target, but
-rather just start a search in the associated directory.
-
-This is intended to be used in `embark-target-injection-hooks'
-for any action that is a Consult async command."
- (let* ((style (alist-get consult-async-split-style
- consult-async-split-styles-alist))
- (initial (plist-get style :initial))
- (separator (plist-get style :separator))
- (directory (embark--associated-directory target type)))
- (when directory
- (delete-minibuffer-contents))
- (when initial
- (goto-char (minibuffer-prompt-end))
- (insert initial)
- (goto-char (point-max)))
- (when (and separator (null directory))
- (goto-char (point-max))
- (insert separator))))
-
-(cl-defun embark-consult--projectless
- (&rest rest &key run target type &allow-other-keys)
- "Run action with nil `consult-project-function', if TARGET has an directory.
-The values of TYPE which are considered to have an associated
-directory are: file, buffer, bookmark and library. The REST of
-the arguments are also passed to RUN."
- (if (embark--associated-directory target type)
+(cl-defun embark-consult--async-search-dwim
+ (&key action type target candidates &allow-other-keys)
+ "DWIM when using a Consult async search command as an ACTION.
+If the TYPE of the target(s) has a notion of associated
+file (files, buffers, libraries and some bookmarks do), then run
+the ACTION with `consult-project-function' set to nil, and search
+only the files associated to the TARGET or CANDIDATES. For other
+types, run the ACTION with TARGET or CANDIDATES as initial input."
+ (if-let ((file-fn (cdr (assq type embark--associated-file-fn-alist))))
(let (consult-project-function)
- (apply run :target target :type type rest))
- (apply run :target target :type type rest)))
+ (funcall action
+ (delq nil (mapcar file-fn (or candidates (list target))))))
+ (funcall action nil (or target (string-join candidates " ")))))
(map-keymap
(lambda (_key cmd)
- (cl-pushnew #'embark--cd (alist-get cmd embark-around-action-hooks))
- (cl-pushnew #'embark-consult--projectless
- (alist-get cmd embark-around-action-hooks))
- (cl-pushnew #'embark-consult--prep-async
- (alist-get cmd embark-target-injection-hooks)))
+ (unless (eq cmd #'consult-locate)
+ (cl-pushnew cmd embark-multitarget-actions)
+ (cl-pushnew #'embark-consult--async-search-dwim
+ (alist-get cmd embark-around-action-hooks))))
embark-consult-async-search-map)
;;; Tables of contents for buffers: imenu and outline candidate collectors
diff --git a/embark.el b/embark.el
index acaeb9e..bc35629 100644
--- a/embark.el
+++ b/embark.el
@@ -1983,7 +1983,8 @@ arguments are passed to the hooks as keyword arguments."
(mapc (lambda (h) (apply h :action action :quit quit target))
(alist-get :always hooks)))
-(defun embark--run-around-action-hooks (action target quit)
+(defun embark--run-around-action-hooks
+ (action target quit &optional non-interactive)
"Run the `embark-around-action-hooks' for ACTION.
All the applicable around hooks are composed in the order they
are present in `embark-around-action-hooks'. The keys t and
@@ -1991,7 +1992,11 @@ are present in `embark-around-action-hooks'. The keys t and
The :always hooks are executed always (outermost) and the t hooks
are the default hooks, for when there are no command-specific
hooks for ACTION. The QUIT, ACTION and TARGET arguments are
-passed to the hooks as keyword arguments."
+passed to the hooks as keyword arguments.
+
+The optional argument NON-INTERACTIVE controls whether the action
+is run with `command-execute' or with `funcall' passing the
+target as argument."
(apply
(seq-reduce
(lambda (fn hook)
@@ -2000,8 +2005,12 @@ passed to the hooks as keyword arguments."
(reverse
(append (or (alist-get action hooks) (alist-get t hooks))
(alist-get :always hooks))))
- (lambda (&rest args)
- (command-execute (plist-get args :action))))
+ (if non-interactive
+ (lambda (&rest args)
+ (funcall (plist-get args :action)
+ (or (plist-get args :candidates) (plist-get args :target))))
+ (lambda (&rest args)
+ (command-execute (plist-get args :action)))))
:action action :quit quit target))
(defun embark--act (action target &optional quit)
@@ -2076,12 +2085,11 @@ minibuffer before executing the action."
(when dedicate (set-window-dedicated-p dedicate nil)))
(unless (eq final-window action-window)
(select-window final-window))))
- ;; TODO uniformize the command and non-interactive cases?
- (let ((argument
- (if multi
- (or (plist-get target :candidates) ; embark-act-all
- (list (plist-get target :target)))
- (plist-get target :target))))
+ (let ((target
+ (if (and multi (null (plist-get target :candidates)))
+ (plist-put
+ target :candidates (list (plist-get target :target)))
+ target)))
(lambda ()
(with-selected-window action-window
(embark--run-action-hooks embark-pre-action-hooks
@@ -2089,7 +2097,8 @@ minibuffer before executing the action."
(unwind-protect
(let ((current-prefix-arg prefix)
(default-directory directory))
- (funcall action argument))
+ (embark--run-around-action-hooks
+ action target quit :non-interactive))
(embark--run-action-hooks embark-post-action-hooks
action target quit))))))))
(setq prefix-arg nil)
@@ -4089,23 +4098,25 @@ the REST of the arguments."
(unless (y-or-n-p (format "Run %s on %s? " action target))
(user-error "Canceled")))
+(defconst embark--associated-file-fn-alist
+ `((file . identity)
+ (buffer . ,(lambda (target)
+ (let ((buffer (get-buffer target)))
+ (or (buffer-file-name buffer)
+ (buffer-local-value 'default-directory buffer)))))
+ (bookmark . bookmark-location)
+ (library . locate-library))
+ "Alist of functions that extract a file path from targets of a given type.")
+
(defun embark--associated-directory (target type)
"Return directory associated to TARGET of given TYPE.
The supported values of TYPE are file, buffer, bookmark and
library, which have an obvious notion of associated directory."
- (setq target (pcase type
- ('file
- target)
- ('buffer
- (buffer-local-value 'default-directory (get-buffer target)))
- ('bookmark
- (bookmark-prop-get target 'filename))
- ('library
- (locate-library target))))
- (when target
- (if (file-directory-p target)
- (file-name-as-directory target)
- (file-name-directory target))))
+ (when-let ((file-fn (alist-get type embark--associated-file-fn-alist))
+ (file (funcall file-fn target)))
+ (if (file-directory-p file)
+ (file-name-as-directory file)
+ (file-name-directory file))))
(cl-defun embark--cd (&rest rest &key run target type &allow-other-keys)
"Run action with `default-directory' set to the directory of TARGET.
diff --git a/embark.texi b/embark.texi
index d512cf5..cc41bf4 100644
--- a/embark.texi
+++ b/embark.texi
@@ -1312,13 +1312,20 @@ Embark and Consult. Some examples are:
@itemize
@item
-The asynchronous search commands will start in the directory
-associated to the Embark target if that target is a file, buffer,
-bookmark or Emacs Lisp library.
+When used as actions, the asynchronous search commands will search
+only the files associated to the targets: if the targets @emph{are} files,
+it searches those files; for buffers it will search either the
+associated file if there is one, else all files in the buffer's
+@samp{default-directory}; for bookmarks it will search the file they point
+to, same for Emacs Lisp libraries. This is particularly powerful
+when using @samp{embark-act-all} to act on multiple files at once, for
+example you can use @samp{consult-find} to search among file @emph{names} and then
+@samp{embark-act-all} and @samp{consult-grep} to search within the matching files.
@itemize
@item
-For all other target types, a Consult search command (asynchronous
+For all other target types, those that do not have a sensible
+notion of associated file, a Consult search command (asynchronous
or not) will search for the text of the target but leave the
minibuffer open so you can interact with the Consult command.
@end itemize