diff options
author | Omar Antolín <omar.antolin@gmail.com> | 2023-12-06 10:21:14 -0600 |
---|---|---|
committer | Omar Antolín <omar.antolin@gmail.com> | 2023-12-06 10:21:14 -0600 |
commit | 95517246d8ef5cd837cd315f4689e922202d3df5 (patch) | |
tree | 2aa9c6868a8d35559f2f72bafc59e67a68256cc6 | |
parent | b24295ea889420dca1edca10f9c0ab0d293168d3 (diff) | |
parent | a05b77f49069e024cbe3018eade3e8bd0ee4769a (diff) |
Merge branch 'consult-grep-dwim'
-rw-r--r-- | CHANGELOG.org | 10 | ||||
-rw-r--r-- | README.org | 17 | ||||
-rw-r--r-- | embark-consult.el | 53 | ||||
-rw-r--r-- | embark.el | 59 | ||||
-rw-r--r-- | embark.texi | 15 |
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. @@ -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 @@ -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 |