embark.el (181024B)
1 ;;; embark.el --- Conveniently act on minibuffer completions -*- lexical-binding: t; -*- 2 3 ;; Copyright (C) 2021, 2022 Free Software Foundation, Inc. 4 5 ;; Author: Omar Antolín Camarena <omar@matem.unam.mx> 6 ;; Maintainer: Omar Antolín Camarena <omar@matem.unam.mx> 7 ;; Keywords: convenience 8 ;; Version: 0.22.1 9 ;; Homepage: https://github.com/oantolin/embark 10 ;; Package-Requires: ((emacs "27.1") (compat "29.1.4.0")) 11 12 ;; This file is part of GNU Emacs. 13 14 ;; This program is free software; you can redistribute it and/or modify 15 ;; it under the terms of the GNU General Public License as published by 16 ;; the Free Software Foundation, either version 3 of the License, or 17 ;; (at your option) any later version. 18 19 ;; This program is distributed in the hope that it will be useful, 20 ;; but WITHOUT ANY WARRANTY; without even the implied warranty of 21 ;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 22 ;; GNU General Public License for more details. 23 24 ;; You should have received a copy of the GNU General Public License 25 ;; along with this program. If not, see <https://www.gnu.org/licenses/>. 26 27 ;;; Commentary: 28 29 ;; This package provides a sort of right-click contextual menu for 30 ;; Emacs, accessed through the `embark-act' command (which you should 31 ;; bind to a convenient key), offering you relevant actions to use on 32 ;; a target determined by the context: 33 34 ;; - In the minibuffer, the target is the current best completion 35 ;; candidate. 36 ;; - In the `*Completions*' buffer the target is the completion at point. 37 ;; - In a regular buffer, the target is the region if active, or else the 38 ;; file, symbol or url at point. 39 40 ;; The type of actions offered depend on the type of the target: 41 42 ;; - For files you get offered actions like deleting, copying, 43 ;; renaming, visiting in another window, running a shell command on the 44 ;; file, etc. 45 ;; - For buffers the actions include switching to or killing the buffer. 46 ;; - For package names the actions include installing, removing or 47 ;; visiting the homepage. 48 49 ;; Everything is easily configurable: determining the current target, 50 ;; classifying it, and deciding with actions are offered for each type 51 ;; in the classification. The above introduction just mentions part of 52 ;; the default configuration. 53 54 ;; Configuring which actions are offered for a type is particularly 55 ;; easy and requires no programming: the `embark-keymap-alist' 56 ;; variable associates target types with variable containing keymaps, 57 ;; and those keymaps containing binds for the actions. For example, 58 ;; in the default configuration the type `file' is associated with the 59 ;; symbol `embark-file-keymap'. That symbol names a keymap with 60 ;; single-letter key bindings for common Emacs file commands, for 61 ;; instance `c' is bound to `copy-file'. This means that if while you 62 ;; are in the minibuffer after running a command that prompts for a 63 ;; file, such as `find-file' or `rename-file', you can copy a file by 64 ;; running `embark-act' and then pressing `c'. 65 66 ;; These action keymaps are very convenient but not strictly necessary 67 ;; when using `embark-act': you can use any command that reads from the 68 ;; minibuffer as an action and the target of the action will be inserted 69 ;; at the first minibuffer prompt. After running `embark-act' all of your 70 ;; key bindings and even `execute-extended-command' can be used to run a 71 ;; command. The action keymaps are normal Emacs keymaps and you should 72 ;; feel free to bind in them whatever commands you find useful as actions. 73 74 ;; The actions in `embark-general-map' are available no matter what 75 ;; type of completion you are in the middle of. By default this 76 ;; includes bindings to save the current candidate in the kill ring 77 ;; and to insert the current candidate in the previously selected 78 ;; buffer (the buffer that was current when you executed a command 79 ;; that opened up the minibuffer). 80 81 ;; You can read about the Embark GitHub project wiki: 82 ;; https://github.com/oantolin/embark/wiki/Default-Actions 83 84 ;; Besides acting individually on targets, Embark lets you work 85 ;; collectively on a set of target candidates. For example, while 86 ;; you are in the minibuffer the candidates are simply the possible 87 ;; completions of your input. Embark provides three commands to work 88 ;; on candidate sets: 89 90 ;; - The `embark-act-all' command runs the same action on each of the 91 ;; current candidates. It is just like using `embark-act' on each 92 ;; candidate in turn. 93 94 ;; - The `embark-collect' command produces a buffer listing all 95 ;; candidates, for you to peruse and run actions on at your leisure. 96 ;; The candidates are displayed as a list showing additional 97 ;; annotations. 98 99 ;; - The `embark-export' command tries to open a buffer in an 100 ;; appropriate major mode for the set of candidates. If the 101 ;; candidates are files export produces a Dired buffer; if they are 102 ;; buffers, you get an Ibuffer buffer; and if they are packages you 103 ;; get a buffer in package menu mode. 104 105 ;; These are always available as "actions" (although they do not act 106 ;; on just the current target but on all candidates) for embark-act 107 ;; and are bound to A, S (for "snapshot") and E, respectively, in 108 ;; embark-general-map. This means that you do not have to bind your 109 ;; own key bindings for these (although you can, of course), just a 110 ;; key binding for `embark-act'. 111 112 ;;; Code: 113 114 115 (require 'compat) 116 (eval-when-compile (require 'subr-x)) 117 118 (require 'ffap) ; used to recognize file and url targets 119 120 ;;; User facing options 121 122 (defgroup embark nil 123 "Emacs Mini-Buffer Actions Rooted in Keymaps." 124 :link '(info-link :tag "Info Manual" "(embark)") 125 :link '(url-link :tag "Homepage" "https://github.com/oantolin/embark") 126 :link '(emacs-library-link :tag "Library Source" "embark.el") 127 :group 'minibuffer 128 :prefix "embark-") 129 130 (defcustom embark-keymap-alist 131 '((file embark-file-map) 132 (library embark-library-map) 133 (environment-variables embark-file-map) ; they come up in file completion 134 (url embark-url-map) 135 (email embark-email-map) 136 (buffer embark-buffer-map) 137 (tab embark-tab-map) 138 (expression embark-expression-map) 139 (identifier embark-identifier-map) 140 (defun embark-defun-map) 141 (symbol embark-symbol-map) 142 (face embark-face-map) 143 (command embark-command-map) 144 (variable embark-variable-map) 145 (function embark-function-map) 146 (minor-mode embark-command-map) 147 (unicode-name embark-unicode-name-map) 148 (package embark-package-map) 149 (bookmark embark-bookmark-map) 150 (region embark-region-map) 151 (sentence embark-sentence-map) 152 (paragraph embark-paragraph-map) 153 (kill-ring embark-kill-ring-map) 154 (heading embark-heading-map) 155 (t embark-general-map)) 156 "Alist of action types and corresponding keymaps. 157 The special key t is associated with the default keymap to use. 158 Each value can be either a single symbol whose value is a keymap, 159 or a list of such symbols." 160 :type '(alist :key-type (symbol :tag "Target type") 161 :value-type (choice (variable :tag "Keymap") 162 (repeat :tag "Keymaps" variable)))) 163 164 (defcustom embark-target-finders 165 '(embark-target-top-minibuffer-completion 166 embark-target-active-region 167 embark-target-text-heading-at-point 168 embark-target-collect-candidate 169 embark-target-completion-at-point 170 embark-target-bug-reference-at-point 171 embark-target-package-at-point 172 embark-target-email-at-point 173 embark-target-url-at-point 174 embark-target-file-at-point 175 embark-target-custom-variable-at-point 176 embark-target-identifier-at-point 177 embark-target-library-file-at-point 178 embark-target-expression-at-point 179 embark-target-sentence-at-point 180 embark-target-paragraph-at-point 181 embark-target-defun-at-point 182 embark-target-prog-heading-at-point) 183 "List of functions to determine the target in current context. 184 Each function should take no arguments and return one of: 185 186 1. a cons (TYPE . TARGET) where TARGET is a string and TYPE is a 187 symbol (which is looked up in `embark-keymap-alist' to 188 determine which additional keybindings for actions to setup); 189 190 2. a dotted list of the form (TYPE TARGET START . END), where 191 START and END are the buffer positions bounding TARGET, used 192 for highlighting; or 193 194 3. a possibly empty list of targets, each of type 1 or 2 (in 195 particular if a target finder does not find any targets, it 196 should return nil)." 197 :type 'hook) 198 199 (defcustom embark-transformer-alist 200 '((minor-mode . embark--lookup-lighter-minor-mode) 201 (embark-keybinding . embark--keybinding-command) 202 (project-file . embark--project-file-full-path) 203 (package . embark--remove-package-version) 204 (multi-category . embark--refine-multi-category) 205 (file . embark--simplify-path)) 206 "Alist associating type to functions for transforming targets. 207 Each function should take a type and a target string and return a 208 pair of the form a `cons' of the new type and the new target." 209 :type '(alist :key-type symbol :value-type function)) 210 211 (defcustom embark-become-keymaps 212 '(embark-become-help-map 213 embark-become-file+buffer-map 214 embark-become-shell-command-map 215 embark-become-match-map) 216 "List of keymaps for `embark-become'. 217 Each keymap groups a set of related commands that can 218 conveniently become one another." 219 :type '(repeat variable)) 220 221 (defcustom embark-prompter 'embark-keymap-prompter 222 "Function used to prompt the user for actions. 223 This should be set to a function that prompts the use for an 224 action and returns the symbol naming the action command. The 225 default value, `embark-keymap-prompter' activates the type 226 specific action keymap given in `embark-keymap-alist'. 227 There is also `embark-completing-read-prompter' which 228 prompts for an action with completion." 229 :type '(choice (const :tag "Use action keymaps" embark-keymap-prompter) 230 (const :tag "Read action with completion" 231 embark-completing-read-prompter) 232 (function :tag "Other"))) 233 234 (defcustom embark-keymap-prompter-key "@" 235 "Key to switch to the keymap prompter from `embark-completing-read-prompter'. 236 237 The key must be either nil or a string. The 238 string must be accepted by `key-valid-p'." 239 :type '(choice key (const :tag "None" nil))) 240 241 (defcustom embark-cycle-key nil 242 "Key used for `embark-cycle'. 243 244 If the key is set to nil it defaults to the global binding of 245 `embark-act'. The key must be a string which is accepted by 246 `key-valid-p'." 247 :type '(choice key (const :tag "Use embark-act key" nil))) 248 249 (defcustom embark-help-key "C-h" 250 "Key used for help. 251 252 The key must be either nil or a string. The 253 string must be accepted by `key-valid-p'." 254 :type '(choice (const "C-h") 255 (const "?") 256 (const :tag "None" nil) 257 key)) 258 259 (defcustom embark-keybinding-repeat 260 (propertize "*" 'face 'embark-keybinding-repeat) 261 "Indicator string for repeatable keybindings. 262 Keybindings are formatted by the `completing-read' prompter and 263 the verbose indicator." 264 :type 'string) 265 266 (defface embark-keybinding-repeat 267 '((t :inherit font-lock-builtin-face)) 268 "Face used to indicate keybindings as repeatable.") 269 270 (defface embark-keybinding '((t :inherit success)) 271 "Face used to display key bindings. 272 Used by `embark-completing-read-prompter' and `embark-keymap-help'.") 273 274 (defface embark-keymap '((t :slant italic)) 275 "Face used to display keymaps. 276 Used by `embark-completing-read-prompter' and `embark-keymap-help'.") 277 278 (defface embark-target '((t :inherit highlight)) 279 "Face used to highlight the target at point during `embark-act'.") 280 281 (defcustom embark-quit-after-action t 282 "Should `embark-act' quit the minibuffer? 283 This controls whether calling `embark-act' without a prefix 284 argument quits the minibuffer or not. You can always get the 285 opposite behavior to that indicated by this variable by calling 286 `embark-act' with \\[universal-argument]. 287 288 Note that `embark-act' can also be called from outside the 289 minibuffer and this variable is irrelevant in that case. 290 291 In addition to t or nil this variable can also be set to an 292 alist to specify the minibuffer quitting behavior per command. 293 In the alist case one can additionally use the key t to 294 prescribe a default for commands not used as alist keys." 295 :type '(choice (const :tag "Always quit" t) 296 (const :tag "Never quit" nil) 297 (alist :tag "Configure per action" 298 :key-type (choice (function :tag "Action") 299 (const :tag "All other actions" t)) 300 :value-type (choice (const :tag "Quit") 301 (const :tag "Do not quit"))))) 302 303 (defcustom embark-confirm-act-all t 304 "Should `embark-act-all' prompt the user for confirmation? 305 Even if this variable is nil you may still be prompted to confirm 306 some uses of `embark-act-all', namely, for those actions whose 307 entry in `embark-pre-action-hooks' includes `embark--confirm'." 308 :type 'boolean) 309 310 (defcustom embark-default-action-overrides nil 311 "Alist associating target types with overriding default actions. 312 When the source of a target is minibuffer completion, the default 313 action for it is usually the command that opened the minibuffer 314 in the first place but this can be overridden for a given type by 315 an entry in this list. 316 317 For example, if you run `delete-file' the default action for its 318 completion candidates is `delete-file' itself. You may prefer to 319 make `find-file' the default action for all files, even if they 320 were obtained from a `delete-file' prompt. In that case you can 321 configure that by adding an entry to this variable pairing `file' 322 with `find-file'. 323 324 In addition to target types, you can also use as keys in this alist, 325 pairs of a target type and a command name. Such a pair indicates that 326 the override only applies if the target was obtained from minibuffer 327 completion from that command. For example adding an 328 entry (cons (cons \\='file \\='delete-file) \\='find-file) to this alist would 329 indicate that for files at the prompt of the `delete-file' command, 330 `find-file' should be used as the default action." 331 :type '(alist :key-type (choice (symbol :tag "Type") 332 (cons (symbol :tag "Type") 333 (symbol :tag "Command"))) 334 :value-type (function :tag "Default action"))) 335 336 (defcustom embark-target-injection-hooks 337 '((async-shell-command embark--allow-edit embark--shell-prep) 338 (shell-command embark--allow-edit embark--shell-prep) 339 (pp-eval-expression embark--eval-prep) 340 (eval-expression embark--eval-prep) 341 (package-delete embark--force-complete) 342 ;; commands evaluating code found in the buffer, which may in turn prompt 343 (embark-pp-eval-defun embark--ignore-target) 344 (eval-defun embark--ignore-target) 345 (eval-last-sexp embark--ignore-target) 346 (embark-eval-replace embark--ignore-target) 347 ;; commands which prompt for something that is *not* the target 348 (write-region embark--ignore-target) 349 (append-to-file embark--ignore-target) 350 (shell-command-on-region embark--ignore-target) 351 (format-encode-region embark--ignore-target) 352 (format-decode-region embark--ignore-target) 353 (xref-find-definitions embark--ignore-target) 354 (xref-find-references embark--ignore-target) 355 (sort-regexp-fields embark--ignore-target) 356 (align-regexp embark--ignore-target)) 357 "Alist associating commands with post-injection setup hooks. 358 For commands appearing as keys in this alist, run the 359 corresponding value as a setup hook after injecting the target 360 into in the minibuffer and before acting on it. The hooks must 361 accept arbitrary keyword arguments. The :action command, the 362 :target string and target :type are always present. For actions 363 at point the target :bounds are passed too. The default pre-action 364 hook is specified by the entry with key t. Furthermore, hooks with 365 the key :always are executed always." 366 :type '(alist :key-type 367 (choice symbol 368 (const :tag "Default" t) 369 (const :tag "Always" :always)) 370 :value-type hook)) 371 372 (defcustom embark-pre-action-hooks 373 `(;; commands that need to position point at the beginning or end 374 (eval-last-sexp embark--end-of-target) 375 (indent-pp-sexp embark--beginning-of-target) 376 (backward-up-list embark--beginning-of-target) 377 (backward-list embark--beginning-of-target) 378 (forward-list embark--end-of-target) 379 (forward-sexp embark--end-of-target) 380 (backward-sexp embark--beginning-of-target) 381 (raise-sexp embark--beginning-of-target) 382 (kill-sexp embark--beginning-of-target) 383 (mark-sexp embark--beginning-of-target) 384 (transpose-sexps embark--end-of-target) 385 (transpose-sentences embark--end-of-target) 386 (transpose-paragraphs embark--end-of-target) 387 (forward-sentence embark--end-of-target) 388 (backward-sentence embark--beginning-of-target) 389 (backward-paragraph embark--beginning-of-target) 390 (embark-insert embark--end-of-target) 391 ;; commands we want to be able to jump back from 392 ;; (embark-find-definition achieves this by calling 393 ;; xref-find-definitions which pushes the markers itself) 394 (find-library embark--xref-push-marker) 395 ;; commands which prompt the user for confirmation before running 396 (delete-file embark--confirm) 397 (delete-directory embark--confirm) 398 (kill-buffer embark--confirm) 399 (embark-kill-buffer-and-window embark--confirm) 400 (bookmark-delete embark--confirm) 401 (package-delete embark--confirm) 402 (,'tab-bar-close-tab-by-name embark--confirm) ;; Avoid package-lint warning 403 ;; search for region contents outside said region 404 (embark-isearch embark--unmark-target) 405 (occur embark--unmark-target) 406 (query-replace embark--beginning-of-target embark--unmark-target) 407 (query-replace-regexp embark--beginning-of-target embark--unmark-target) 408 ;; mark pseudo-action 409 (mark embark--mark-target) 410 ;; shells in new buffers 411 (shell embark--universal-argument) 412 (eshell embark--universal-argument) 413 ;; do the actual work of selecting & deselecting targets 414 (embark-select embark--select)) 415 "Alist associating commands with pre-action hooks. 416 The hooks are run right before an action is embarked upon. See 417 `embark-target-injection-hooks' for information about the hook 418 arguments and more details." 419 :type '(alist :key-type 420 (choice symbol 421 (const :tag "Default" t) 422 (const :tag "Always" :always)) 423 :value-type hook)) 424 425 (defcustom embark-post-action-hooks 426 `((bookmark-delete embark--restart) 427 (bookmark-rename embark--restart) 428 (delete-file embark--restart) 429 (embark-kill-ring-remove embark--restart) 430 (embark-recentf-remove embark--restart) 431 (embark-history-remove embark--restart) 432 (rename-file embark--restart) 433 (copy-file embark--restart) 434 (delete-directory embark--restart) 435 (make-directory embark--restart) 436 (kill-buffer embark--restart) 437 (embark-rename-buffer embark--restart) 438 (,'tab-bar-rename-tab-by-name embark--restart) ;; Avoid package-lint warning 439 (,'tab-bar-close-tab-by-name embark--restart) 440 (package-delete embark--restart)) 441 "Alist associating commands with post-action hooks. 442 The hooks are run after an embarked upon action concludes. See 443 `embark-target-injection-hooks' for information about the hook 444 arguments and more details." 445 :type '(alist :key-type 446 (choice symbol 447 (const :tag "Default" t) 448 (const :tag "Always" :always)) 449 :value-type hook)) 450 451 (defcustom embark-around-action-hooks 452 '(;; use directory of target as default-directory 453 (shell embark--cd) 454 (eshell embark--cd) 455 ;; narrow to target for duration of action 456 (repunctuate-sentences embark--narrow-to-target) 457 ;; mark the target preserving point and previous mark 458 (kill-region embark--mark-target) 459 (kill-ring-save embark--mark-target) 460 (indent-region embark--mark-target) 461 (ispell-region embark--mark-target) 462 (fill-region embark--mark-target) 463 (upcase-region embark--mark-target) 464 (downcase-region embark--mark-target) 465 (capitalize-region embark--mark-target) 466 (count-words-region embark--mark-target) 467 (count-words embark--mark-target) 468 (shell-command-on-region embark--mark-target) 469 (delete-region embark--mark-target) 470 (format-encode-region embark--mark-target) 471 (format-decode-region embark--mark-target) 472 (write-region embark--mark-target) 473 (append-to-file embark--mark-target) 474 (shell-command-on-region embark--mark-target) 475 (embark-eval-replace embark--mark-target)) 476 "Alist associating commands with post-action hooks. 477 The hooks are run instead of the embarked upon action. The hook 478 can decide whether or not to run the action or it can run it 479 in some special environment, like inside a let-binding or inside 480 `save-excursion'. Each hook is called with keyword argument :run 481 providing a function encapsulating the following around hooks and 482 the action; the hook additionally receives the keyword arguments 483 used for other types of action hooks, for more details see 484 `embark-target-injection-hooks'." 485 :type '(alist :key-type 486 (choice symbol 487 (const :tag "Default" t) 488 (const :tag "Always" :always)) 489 :value-type hook)) 490 491 (defcustom embark-multitarget-actions '(embark-insert embark-copy-as-kill) 492 "Commands for which `embark-act-all' should pass a list of targets. 493 Normally `embark-act-all' runs the same action on each candidate 494 separately, but when a command included in this variable's value 495 is used as an action, `embark-act-all' will instead call it 496 non-interactively with a single argument: the list of all 497 candidates. For commands on this list `embark-act' behaves 498 similarly: it calls them non-interactively with a single 499 argument: a one element list containing the target." 500 :type '(repeat function)) 501 502 (defcustom embark-repeat-actions 503 '((mark . region) 504 ;; outline commands 505 outline-next-visible-heading outline-previous-visible-heading 506 outline-forward-same-level outline-backward-same-level 507 outline-demote outline-promote 508 outline-show-subtree (outline-mark-subtree . region) 509 outline-move-subtree-up outline-move-subtree-down 510 outline-up-heading outline-hide-subtree outline-cycle 511 ;; org commands (remapped outline commands) 512 org-forward-heading-same-level org-backward-heading-same-level 513 org-next-visible-heading org-previous-visible-heading 514 org-demote-subtree org-promote-subtree 515 org-show-subtree (org-mark-subtree . region) 516 org-move-subtree-up org-move-subtree-down 517 ;; transpose commands 518 transpose-sexps transpose-sentences transpose-paragraphs 519 ;; movement 520 embark-next-symbol embark-previous-symbol 521 backward-up-list backward-list forward-list forward-sexp 522 backward-sexp forward-sentence backward-sentence 523 forward-paragraph backward-paragraph) 524 "List of repeatable actions. 525 When you use a command on this list as an Embark action from 526 outside the minibuffer, `embark-act' does not exit but instead 527 lets you act again on the possibly new target you reach. 528 529 By default, after using one of these actions, when `embark-act' 530 looks for targets again, it will start the target cycle at the 531 same type as the previously acted upon target; that is, you 532 \"don't loose your place in the target cycle\". 533 534 Sometimes, however, you'll want to prioritize a different type of 535 target to continue acting on. The main example of this that if 536 you use a marking command as an action, you almost always want to 537 act on the region next. For those cases, in addition to 538 commands, you can also place on this list a pair of a command and 539 the desired starting type for the target cycle for the next 540 action." 541 :type '(repeat (choice function 542 (cons function 543 (symbol :tag "Next target type"))))) 544 545 ;;; Stashing information for actions in buffer local variables 546 547 (defvar-local embark--type nil 548 "Cache for the completion type, meant to be set buffer-locally.") 549 550 (defvar-local embark--target-buffer nil 551 "Cache for the previous buffer, meant to be set buffer-locally.") 552 553 (defvar-local embark--target-window nil 554 "Cache for the previous window, meant to be set buffer-locally. 555 Since windows can be reused to display different buffers, this 556 window should only be used if it displays the buffer stored in 557 the variable `embark--target-buffer'.") 558 559 (defvar-local embark--command nil 560 "Command that started the completion session.") 561 562 (defvar-local embark--toggle-quit nil 563 "Should we toggle the default quitting behavior for the next action?") 564 565 (defun embark--minibuffer-point () 566 "Return length of minibuffer contents." 567 (max 0 (- (point) (minibuffer-prompt-end)))) 568 569 (defun embark--default-directory () 570 "Guess a reasonable default directory for the current candidates." 571 (if (and (minibufferp) minibuffer-completing-file-name) 572 (let ((end (minibuffer-prompt-end)) 573 (contents (minibuffer-contents))) 574 (expand-file-name 575 (substitute-in-file-name 576 (buffer-substring 577 end 578 (+ end 579 (or (cdr 580 (last 581 (completion-all-completions 582 contents 583 minibuffer-completion-table 584 minibuffer-completion-predicate 585 (embark--minibuffer-point)))) 586 (cl-position ?/ contents :from-end t) 587 0)))))) 588 default-directory)) 589 590 (defun embark--target-buffer () 591 "Return buffer that should be targeted by Embark actions." 592 (cond 593 ((and (minibufferp) (minibuffer-selected-window)) 594 (window-buffer (minibuffer-selected-window))) 595 ((and embark--target-buffer (buffer-live-p embark--target-buffer)) 596 embark--target-buffer) 597 (t (current-buffer)))) 598 599 (defun embark--target-window (&optional display) 600 "Return window which should be selected when Embark actions run. 601 If DISPLAY is non-nil, call `display-buffer' to produce the 602 window if necessary." 603 (cond 604 ((and (minibufferp) (minibuffer-selected-window)) 605 (minibuffer-selected-window)) 606 ((and embark--target-window 607 (window-live-p embark--target-window) 608 (or (not (buffer-live-p embark--target-buffer)) 609 (eq (window-buffer embark--target-window) embark--target-buffer))) 610 embark--target-window) 611 ((and embark--target-buffer (buffer-live-p embark--target-buffer)) 612 (or (get-buffer-window embark--target-buffer) 613 (when display (display-buffer embark--target-buffer)))) 614 (display (selected-window)))) 615 616 (defun embark--cache-info (buffer) 617 "Cache information needed for actions in variables local to BUFFER. 618 BUFFER defaults to the current buffer." 619 (let ((cmd embark--command) 620 (dir (embark--default-directory)) 621 (target-buffer (embark--target-buffer)) 622 (target-window (embark--target-window))) 623 (with-current-buffer buffer 624 (setq embark--command cmd 625 default-directory dir 626 embark--target-buffer target-buffer 627 embark--target-window target-window)))) 628 629 (defun embark--cache-info--completion-list () 630 "Cache information needed for actions in a *Completions* buffer. 631 Meant to be be added to `completion-setup-hook'." 632 ;; when completion-setup-hook hook runs, the *Completions* buffer is 633 ;; available in the variable standard-output 634 (embark--cache-info standard-output) 635 (with-current-buffer standard-output 636 (when (minibufferp completion-reference-buffer) 637 (setq embark--type 638 (completion-metadata-get 639 (with-current-buffer completion-reference-buffer 640 (embark--metadata)) 641 'category))))) 642 643 ;; We have to add this *after* completion-setup-function because that's 644 ;; when the buffer is put in completion-list-mode and turning the mode 645 ;; on kills all local variables! So we use a depth of 5. 646 (add-hook 'completion-setup-hook #'embark--cache-info--completion-list 5) 647 648 ;;;###autoload 649 (progn 650 (defun embark--record-this-command () 651 "Record command which opened the minibuffer. 652 We record this because it will be the default action. 653 This function is meant to be added to `minibuffer-setup-hook'." 654 (setq-local embark--command this-command)) 655 (add-hook 'minibuffer-setup-hook #'embark--record-this-command)) 656 657 ;;; Internal variables 658 659 (defvar embark--prompter-history nil 660 "History used by the `embark-completing-read-prompter'.") 661 662 ;;; Core functionality 663 664 (defconst embark--verbose-indicator-buffer " *Embark Actions*") 665 666 (defvar embark--minimal-indicator-overlay nil) 667 668 (defun embark--metadata () 669 "Return current minibuffer completion metadata." 670 (completion-metadata 671 (buffer-substring-no-properties 672 (minibuffer-prompt-end) 673 (max (minibuffer-prompt-end) (point))) 674 minibuffer-completion-table 675 minibuffer-completion-predicate)) 676 677 (defun embark-target-active-region () 678 "Target the region if active." 679 (when (use-region-p) 680 (let ((start (region-beginning)) 681 (end (region-end))) 682 `(region ,(buffer-substring start end) . (,start . ,end))))) 683 684 (autoload 'dired-get-filename "dired") 685 (declare-function image-dired-original-file-name "image-dired") 686 687 (defun embark-target-file-at-point () 688 "Target file at point. 689 This function mostly relies on `ffap-file-at-point', with the 690 following exceptions: 691 692 - In `dired-mode', it uses `dired-get-filename' instead. 693 694 - In `imaged-dired-thumbnail-mode', it uses 695 `image-dired-original-file-name' instead." 696 (if-let (file (or (and (derived-mode-p 'dired-mode) 697 (dired-get-filename t 'no-error-if-not-filep)) 698 (and (derived-mode-p 'image-dired-thumbnail-mode) 699 (image-dired-original-file-name)))) 700 (save-excursion 701 (end-of-line) 702 `(file ,(abbreviate-file-name (expand-file-name file)) 703 ,(save-excursion 704 (re-search-backward " " (line-beginning-position) 'noerror) 705 (1+ (point))) 706 . ,(point))) 707 (when-let* ((ffap-file (ffap-file-at-point)) 708 (tap-file (thing-at-point 'filename)) 709 ((not (or (ffap-url-p tap-file) (ffap-el-mode tap-file))))) 710 `(file ,(abbreviate-file-name (expand-file-name ffap-file)) 711 ;; TODO the boundaries may be wrong, this should be generalized. 712 ;; Unfortunately ffap does not make the bounds available. 713 . ,(bounds-of-thing-at-point 'filename))))) 714 715 (defun embark-target-library-file-at-point () 716 "Target the file of the Emacs Lisp library at point. 717 The function `embark-target-file-at-point' could also easily 718 target Emacs Lisp library files, the only reason it doesn't is so 719 that library files and other types of file targets can be given 720 different priorities in `embark-target-finders'." 721 (when-let* ((name (thing-at-point 'filename)) 722 (lib (ffap-el-mode name))) 723 `(file ,lib . ,(bounds-of-thing-at-point 'filename)))) 724 725 (defun embark-target-bug-reference-at-point () 726 "Target a bug reference at point." 727 (when-let ((ov (seq-find (lambda (ov) (overlay-get ov 'bug-reference-url)) 728 (overlays-at (point))))) 729 `(url ,(overlay-get ov 'bug-reference-url) 730 ,(overlay-start ov) . ,(overlay-end ov)))) 731 732 (defun embark-target-package-at-point () 733 "Target the package on the current line in a packages buffer." 734 (when (derived-mode-p 'package-menu-mode) 735 (when-let ((pkg (get-text-property (point) 'tabulated-list-id))) 736 `(package ,(symbol-name (package-desc-name pkg)) 737 ,(line-beginning-position) . ,(line-end-position))))) 738 739 (defun embark-target-email-at-point () 740 "Target the email address at point." 741 (when-let ((email (thing-at-point 'email))) 742 (when (string-prefix-p "mailto:" email) 743 (setq email (string-remove-prefix "mailto:" email))) 744 `(email ,email . ,(bounds-of-thing-at-point 'email)))) 745 746 (defun embark-target-url-at-point () 747 "Target the URL at point." 748 (if-let ((url (or (get-text-property (point) 'shr-url) 749 (get-text-property (point) 'image-url)))) 750 `(url ,url 751 ,(previous-single-property-change 752 (min (1+ (point)) (point-max)) 'mouse-face nil (point-min)) 753 . ,(next-single-property-change 754 (point) 'mouse-face nil (point-max))) 755 (when-let ((url (thing-at-point 'url))) 756 `(url ,url . ,(thing-at-point-bounds-of-url-at-point t))))) 757 758 (declare-function widget-at "wid-edit") 759 760 (defun embark-target-custom-variable-at-point () 761 "Target the variable corresponding to the customize widget at point." 762 (when (derived-mode-p 'Custom-mode) 763 (save-excursion 764 (beginning-of-line) 765 (when-let* ((widget (widget-at (point))) 766 (var (and (eq (car widget) 'custom-visibility) 767 (plist-get (cdr widget) :parent))) 768 (sym (and (eq (car var) 'custom-variable) 769 (plist-get (cdr var) :value)))) 770 `(variable 771 ,(symbol-name sym) 772 ,(point) 773 . ,(progn 774 (re-search-forward ":" (line-end-position) 'noerror) 775 (point))))))) 776 777 ;; NOTE: There is also (thing-at-point 'list), however it does 778 ;; not work on strings and requires the point to be inside the 779 ;; parentheses. This version here is slightly more general. 780 (defun embark-target-expression-at-point () 781 "Target expression at point." 782 (cl-flet ((syntax-p (class &optional (delta 0)) 783 (and (<= (point-min) (+ (point) delta) (point-max)) 784 (eq (pcase class 785 ('open 4) ('close 5) ('prefix 6) ('string 7)) 786 (syntax-class (syntax-after (+ (point) delta))))))) 787 (when-let 788 ((start 789 (pcase-let ((`(_ ,open _ ,string _ _ _ _ ,start _ _) (syntax-ppss))) 790 (ignore-errors ; set start=nil if delimiters are unbalanced 791 (cond 792 (string start) 793 ((or (syntax-p 'open) (syntax-p 'prefix)) 794 (save-excursion (backward-prefix-chars) (point))) 795 ((syntax-p 'close -1) 796 (save-excursion 797 (backward-sexp) (backward-prefix-chars) (point))) 798 ((syntax-p 'string) (point)) 799 ((syntax-p 'string -1) (scan-sexps (point) -1)) 800 (t open))))) 801 (end (ignore-errors (scan-sexps start 1)))) 802 (unless (eq start (car (bounds-of-thing-at-point 'defun))) 803 `(expression ,(buffer-substring start end) ,start . ,end))))) 804 805 (defmacro embark-define-thingatpt-target (thing &rest modes) 806 "Define a target finder for THING using the thingatpt library. 807 If any MODES are given, the target finder only applies to buffers 808 in one of those major modes." 809 (declare (indent 1)) 810 `(defun ,(intern (format "embark-target-%s-at-point" thing)) () 811 ,(format "Target %s at point." thing) 812 (when ,(if modes `(derived-mode-p ,@(mapcar (lambda (m) `',m) modes)) t) 813 (when-let (bounds (bounds-of-thing-at-point ',thing)) 814 (cons ',thing (cons 815 (buffer-substring (car bounds) (cdr bounds)) 816 bounds)))))) 817 818 (embark-define-thingatpt-target defun) 819 (embark-define-thingatpt-target sentence 820 text-mode help-mode Info-mode man-common) 821 (embark-define-thingatpt-target paragraph 822 text-mode help-mode Info-mode man-common) 823 824 (defun embark--identifier-types (identifier) 825 "Return list of target types appropriate for IDENTIFIER." 826 (let ((symbol (intern-soft identifier))) 827 (if (not 828 (or (derived-mode-p 'emacs-lisp-mode 'inferior-emacs-lisp-mode) 829 (and (not (derived-mode-p 'prog-mode)) 830 symbol 831 (or (boundp symbol) (fboundp symbol) (symbol-plist symbol))))) 832 '(identifier) 833 (let* ((library (ffap-el-mode identifier)) 834 (types 835 (append 836 (and (commandp symbol) '(command)) 837 (and symbol (boundp symbol) (not (keywordp symbol)) '(variable)) 838 (and (fboundp symbol) (not (commandp symbol)) '(function)) 839 (and (facep symbol) '(face)) 840 (and library '(library)) 841 (and (featurep 'package) (embark--package-desc symbol) 842 '(package))))) 843 (when (and library 844 (looking-back "\\(?:require\\|use-package\\).*" 845 (line-beginning-position))) 846 (setq types (embark--rotate types (cl-position 'library types)))) 847 (or types '(symbol)))))) 848 849 (defun embark-target-identifier-at-point () 850 "Target identifier at point. 851 852 In Emacs Lisp and IELM buffers the identifier is promoted to a 853 symbol, for which more actions are available. Identifiers are 854 also promoted to symbols if they are interned Emacs Lisp symbols 855 and found in a buffer in a major mode that is not derived from 856 `prog-mode' (this is intended for when you might be reading or 857 writing about Emacs). 858 859 As a convenience, in Org Mode an initial ' or surrounding == or 860 ~~ are removed." 861 (when-let (bounds (bounds-of-thing-at-point 'symbol)) 862 (let ((name (buffer-substring (car bounds) (cdr bounds)))) 863 (when (derived-mode-p 'org-mode) 864 (cond ((string-prefix-p "'" name) 865 (setq name (substring name 1)) 866 (cl-incf (car bounds))) 867 ((string-match-p "^\\([=~]\\).*\\1$" name) 868 (setq name (substring name 1 -1)) 869 (cl-incf (car bounds)) 870 (cl-decf (cdr bounds))))) 871 (mapcar (lambda (type) `(,type ,name . ,bounds)) 872 (embark--identifier-types name))))) 873 874 (defun embark-target-heading-at-point () 875 "Target the outline heading at point." 876 (let ((beg (line-beginning-position)) 877 (end (line-end-position))) 878 (when (save-excursion 879 (goto-char beg) 880 (and (bolp) 881 (looking-at 882 ;; default definition from outline.el 883 (or (bound-and-true-p outline-regexp) "[*\^L]+")))) 884 (require 'outline) ;; Ensure that outline commands are available 885 `(heading ,(buffer-substring beg end) ,beg . ,end)))) 886 887 (defun embark-target-text-heading-at-point () 888 "Target the outline heading at point in text modes." 889 (when (derived-mode-p 'text-mode) 890 (embark-target-heading-at-point))) 891 892 (defun embark-target-prog-heading-at-point () 893 "Target the outline heading at point in programming modes." 894 (when (derived-mode-p 'prog-mode) 895 (embark-target-heading-at-point))) 896 897 (defun embark-target-top-minibuffer-completion () 898 "Target the top completion candidate in the minibuffer. 899 Return the category metadatum as the type of the target. 900 901 This target finder is meant for the default completion UI and 902 completion UI highly compatible with it, like Icomplete. 903 Many completion UIs can still work with Embark but will need 904 their own target finder. See for example 905 `embark--vertico-selected'." 906 (when (and (minibufferp) minibuffer-completion-table) 907 (pcase-let* ((`(,category . ,candidates) (embark-minibuffer-candidates)) 908 (contents (minibuffer-contents)) 909 (top (if (test-completion contents 910 minibuffer-completion-table 911 minibuffer-completion-predicate) 912 contents 913 (let ((completions (completion-all-sorted-completions))) 914 (if (null completions) 915 contents 916 (concat 917 (substring contents 918 0 (or (cdr (last completions)) 0)) 919 (car completions))))))) 920 (cons category (or (car (member top candidates)) top))))) 921 922 (defun embark-target-collect-candidate () 923 "Target the collect candidate at point." 924 (when (derived-mode-p 'embark-collect-mode) 925 (when-let ((button 926 (pcase (get-text-property (point) 'tabulated-list-column-name) 927 ("Candidate" (button-at (point))) 928 ("Annotation" (previous-button (point))))) 929 (start (button-start button)) 930 (end (button-end button)) 931 (candidate (tabulated-list-get-id))) 932 `(,embark--type 933 ,(if (eq embark--type 'file) 934 (abbreviate-file-name (expand-file-name candidate)) 935 candidate) 936 ,start . ,end)))) 937 938 (defun embark-target-completion-at-point () 939 "Return the completion candidate at point in a completions buffer." 940 (when (derived-mode-p 'completion-list-mode) 941 (if (not (get-text-property (point) 'mouse-face)) 942 (user-error "No completion here") 943 ;; this fairly delicate logic is taken from `choose-completion' 944 (let (beg end) 945 (cond 946 ((and (not (eobp)) (get-text-property (point) 'mouse-face)) 947 (setq end (point) beg (1+ (point)))) 948 ((and (not (bobp)) 949 (get-text-property (1- (point)) 'mouse-face)) 950 (setq end (1- (point)) beg (point))) 951 (t (user-error "No completion here"))) 952 (setq beg (previous-single-property-change beg 'mouse-face)) 953 (setq end (or (next-single-property-change end 'mouse-face) 954 (point-max))) 955 (let ((raw (or (get-text-property beg 'completion--string) 956 (buffer-substring beg end)))) 957 `(,embark--type 958 ,(if (eq embark--type 'file) 959 (abbreviate-file-name (expand-file-name raw)) 960 raw) 961 ,beg . ,end)))))) 962 963 (defun embark--cycle-key () 964 "Return the key to use for `embark-cycle'." 965 (if embark-cycle-key 966 (if (key-valid-p embark-cycle-key) 967 (key-parse embark-cycle-key) 968 (error "`embark-cycle-key' is invalid")) 969 (car (where-is-internal #'embark-act)))) 970 971 (defun embark--raw-action-keymap (type) 972 "Return raw action map for targets of given TYPE. 973 This does not take into account the default action, help key or 974 cycling bindings, just what's registered in 975 `embark-keymap-alist'." 976 (make-composed-keymap 977 (mapcar #'symbol-value 978 (let ((actions (or (alist-get type embark-keymap-alist) 979 (alist-get t embark-keymap-alist)))) 980 (ensure-list actions))))) 981 982 (defun embark--action-keymap (type cycle) 983 "Return action keymap for targets of given TYPE. 984 If CYCLE is non-nil bind `embark-cycle'." 985 (make-composed-keymap 986 (let ((map (make-sparse-keymap)) 987 (default-action (embark--default-action type))) 988 (define-key map [13] default-action) 989 (when-let ((cycle-key (and cycle (embark--cycle-key)))) 990 (define-key map cycle-key #'embark-cycle)) 991 (when embark-help-key 992 (keymap-set map embark-help-key #'embark-keymap-help)) 993 map) 994 (embark--raw-action-keymap type))) 995 996 (defun embark--truncate-target (target) 997 "Truncate TARGET string." 998 (unless (stringp target) 999 (setq target (format "%s" target))) 1000 (if-let (pos (string-match-p "\n" target)) 1001 (concat (car (split-string target "\n" 'omit-nulls "\\s-*")) "…") 1002 target)) 1003 1004 ;;;###autoload 1005 (defun embark-eldoc-first-target (report &rest _) 1006 "Eldoc function reporting the first Embark target at point. 1007 This function uses the eldoc REPORT callback and is meant to be 1008 added to `eldoc-documentation-functions'." 1009 (when-let (((not (minibufferp))) 1010 (target (car (embark--targets)))) 1011 (funcall report 1012 (format "Embark on %s ‘%s’" 1013 (plist-get target :type) 1014 (embark--truncate-target (plist-get target :target)))))) 1015 1016 ;;;###autoload 1017 (defun embark-eldoc-target-types (report &rest _) 1018 "Eldoc function reporting the types of all Embark targets at point. 1019 This function uses the eldoc REPORT callback and is meant to be 1020 added to `eldoc-documentation-functions'." 1021 (when-let (((not (minibufferp))) 1022 (targets (embark--targets))) 1023 (funcall report 1024 (format "Embark target types: %s" 1025 (mapconcat 1026 (lambda (target) (symbol-name (plist-get target :type))) 1027 targets 1028 ", "))))) 1029 1030 (defun embark--format-targets (target shadowed-targets rep) 1031 "Return a formatted string indicating the TARGET of an action. 1032 1033 This is used internally by the minimal indicator and for the 1034 targets section of the verbose indicator. The string will also 1035 mention any SHADOWED-TARGETS. A non-nil REP indicates we are in 1036 a repeating sequence of actions." 1037 (let ((act (propertize 1038 (cond 1039 ((plist-get target :multi) "∀ct") 1040 (rep "Rep") 1041 (t "Act")) 1042 'face 'highlight))) 1043 (cond 1044 ((eq (plist-get target :type) 'embark-become) 1045 (propertize "Become" 'face 'highlight)) 1046 ((and (minibufferp) 1047 (not (eq 'embark-keybinding 1048 (completion-metadata-get 1049 (embark--metadata) 1050 'category)))) 1051 ;; we are in a minibuffer but not from the 1052 ;; completing-read prompter, use just "Act" 1053 act) 1054 ((plist-get target :multi) 1055 (format "%s on %s %ss" 1056 act 1057 (plist-get target :multi) 1058 (plist-get target :type))) 1059 (t (format 1060 "%s on %s%s ‘%s’" 1061 act 1062 (plist-get target :type) 1063 (if shadowed-targets 1064 (format (propertize "(%s)" 'face 'shadow) 1065 (mapconcat 1066 (lambda (target) (symbol-name (plist-get target :type))) 1067 shadowed-targets 1068 ", ")) 1069 "") 1070 (embark--truncate-target (plist-get target :target))))))) 1071 1072 (defun embark-minimal-indicator () 1073 "Minimal indicator, appearing in the minibuffer prompt or echo area. 1074 This indicator displays a message showing the types of all 1075 targets, starting with the current target, and the value of the 1076 current target. The message is displayed in the echo area, or if 1077 the minibuffer is open, the message is added to the prompt." 1078 (lambda (&optional keymap targets _prefix) 1079 (if (null keymap) 1080 (when embark--minimal-indicator-overlay 1081 (delete-overlay embark--minimal-indicator-overlay) 1082 (setq-local embark--minimal-indicator-overlay nil)) 1083 (let ((indicator (embark--format-targets 1084 (car targets) (cdr targets) 1085 (eq (lookup-key keymap [13]) #'embark-done)))) 1086 (if (not (minibufferp)) 1087 (message "%s" indicator) 1088 (unless embark--minimal-indicator-overlay 1089 (setq-local embark--minimal-indicator-overlay 1090 (make-overlay (point-min) (point-min) 1091 (current-buffer) t t))) 1092 (overlay-put embark--minimal-indicator-overlay 1093 'before-string (concat indicator 1094 (if (<= (length indicator) 1095 (* 0.4 (frame-width))) 1096 " " 1097 "\n")))))))) 1098 1099 (defun embark--read-key-sequence (update) 1100 "Read key sequence, call UPDATE function with prefix keys." 1101 (let (timer prefix) 1102 (unwind-protect 1103 (progn 1104 (when (functionp update) 1105 (setq timer (run-at-time 1106 0.05 0.05 1107 (lambda () 1108 (let ((new-prefix (this-single-command-keys))) 1109 (unless (equal prefix new-prefix) 1110 (setq prefix new-prefix) 1111 (when (/= (length prefix) 0) 1112 (funcall update prefix)))))))) 1113 (read-key-sequence-vector nil nil nil t 'cmd-loop)) 1114 (when timer 1115 (cancel-timer timer))))) 1116 1117 (defvar embark-indicators) ; forward declaration 1118 1119 (defun embark-keymap-prompter (keymap update) 1120 "Let the user choose an action using the bindings in KEYMAP. 1121 Besides the bindings in KEYMAP, the user is free to use all their 1122 key bindings and even \\[execute-extended-command] to select a command. 1123 UPDATE is the indicator update function." 1124 (let* ((keys (let ((overriding-terminal-local-map keymap)) 1125 (embark--read-key-sequence update))) 1126 (cmd (let ((overriding-terminal-local-map keymap)) 1127 (key-binding keys 'accept-default)))) 1128 ;; Set last-command-event as it would be from the command loop. 1129 ;; Previously we only set it locally for digit-argument and for 1130 ;; the mouse scroll commands handled in this function. But other 1131 ;; commands can need it too! For example, electric-pair-mode users 1132 ;; may wish to bind ( to self-insert-command in embark-region-map. 1133 ;; Also, as described in issue #402, there are circumstances where 1134 ;; you might run consult-narrow through the embark-keymap-prompter. 1135 (setq last-command-event (aref keys (1- (length keys)))) 1136 (pcase cmd 1137 ((or 'embark-keymap-help 1138 (and 'nil ; cmd is nil but last key is help-char 1139 (guard (eq help-char (aref keys (1- (length keys))))))) 1140 (let ((embark-indicators 1141 (cl-set-difference embark-indicators 1142 '(embark-verbose-indicator 1143 embark-mixed-indicator))) 1144 (prefix-map 1145 (if (eq cmd 'embark-keymap-help) 1146 keymap 1147 (let ((overriding-terminal-local-map keymap)) 1148 (key-binding (seq-take keys (1- (length keys))) 1149 'accept-default))))) 1150 (when-let ((win (get-buffer-window embark--verbose-indicator-buffer 1151 'visible))) 1152 (quit-window 'kill-buffer win)) 1153 (embark-completing-read-prompter prefix-map update))) 1154 ((or 'universal-argument 'universal-argument-more 1155 'negative-argument 'digit-argument 'embark-toggle-quit) 1156 ;; prevent `digit-argument' from modifying the overriding map 1157 (let ((overriding-terminal-local-map overriding-terminal-local-map)) 1158 (command-execute cmd)) 1159 (embark-keymap-prompter 1160 (make-composed-keymap universal-argument-map keymap) 1161 update)) 1162 ((or 'minibuffer-keyboard-quit 'abort-recursive-edit 'abort-minibuffers) 1163 nil) 1164 ((guard (let ((def (lookup-key keymap keys))) ; if directly 1165 ; bound, then obey 1166 (and def (not (numberp def))))) ; number means "invalid prefix" 1167 cmd) 1168 ('self-insert-command 1169 (minibuffer-message "Not an action") 1170 (embark-keymap-prompter keymap update)) 1171 ((or 'scroll-other-window 'scroll-other-window-down) 1172 (let ((minibuffer-scroll-window 1173 ;; NOTE: Here we special case the verbose indicator! 1174 (or (get-buffer-window embark--verbose-indicator-buffer 'visible) 1175 minibuffer-scroll-window))) 1176 (ignore-errors (command-execute cmd))) 1177 (embark-keymap-prompter keymap update)) 1178 ((or 'scroll-bar-toolkit-scroll 'mwheel-scroll 'mac-mwheel-scroll) 1179 (funcall cmd last-command-event) 1180 (embark-keymap-prompter keymap update)) 1181 ('execute-extended-command 1182 (intern-soft (read-extended-command))) 1183 ((or 'keyboard-quit 'keyboard-escape-quit) 1184 nil) 1185 (_ cmd)))) 1186 1187 (defun embark--command-name (cmd) 1188 "Return an appropriate name for CMD. 1189 If CMD is a symbol, use its symbol name; for lambdas, use the 1190 first line of the documentation string; otherwise use the word 1191 \"unnamed\"." 1192 (concat ; fresh copy, so we can freely add text properties 1193 (cond 1194 ((stringp (car-safe cmd)) (car cmd)) 1195 ((eq (car-safe cmd) 'menu-item) (cadr cmd)) 1196 ((keymapp cmd) 1197 (propertize (if (symbolp cmd) (format "+%s" cmd) "<keymap>") 1198 'face 'embark-keymap)) 1199 ((symbolp cmd) 1200 (let ((name (symbol-name cmd))) 1201 (if (string-prefix-p "embark-action--" name) ; direct action mode 1202 (format "(%s)" (string-remove-prefix "embark-action--" name)) 1203 name))) 1204 ((when-let (doc (and (functionp cmd) (ignore-errors (documentation cmd)))) 1205 (save-match-data 1206 (when (string-match "^\\(.*\\)$" doc) 1207 (match-string 1 doc))))) 1208 (t "<unnamed>")))) 1209 1210 ;; Taken from Marginalia, needed by the verbose indicator. 1211 ;; We cannot use the completion annotators in this case. 1212 (defconst embark--advice-regexp 1213 (rx bos 1214 (1+ (seq (? "This function has ") 1215 (or ":before" ":after" ":around" ":override" 1216 ":before-while" ":before-until" ":after-while" 1217 ":after-until" ":filter-args" ":filter-return") 1218 " advice: " (0+ nonl) "\n")) 1219 "\n") 1220 "Regexp to match lines about advice in function documentation strings.") 1221 1222 ;; Taken from Marginalia, needed by the verbose indicator. 1223 ;; We cannot use the completion annotators in this case. 1224 (defun embark--function-doc (sym) 1225 "Documentation string of function SYM." 1226 (let ((vstr (and (symbolp sym) (keymapp sym) (boundp sym) 1227 (eq (symbol-function sym) (symbol-value sym)) 1228 (documentation-property sym 'variable-documentation)))) 1229 (when-let (str (or (ignore-errors (documentation sym)) vstr)) 1230 ;; Replace standard description with variable documentation 1231 (when (and vstr (string-match-p "\\`Prefix command" str)) 1232 (setq str vstr)) 1233 (save-match-data 1234 (if (string-match embark--advice-regexp str) 1235 (substring str (match-end 0)) 1236 str))))) 1237 1238 (defun embark--action-repeatable-p (action) 1239 "Is ACTION repeatable? 1240 When the return value is non-nil it will be the desired starting 1241 point of the next target cycle or t to indicate the default, 1242 namely that the target cycle for the next action should begin at 1243 the type of the current target." 1244 (or (cdr (assq action embark-repeat-actions)) 1245 (and (memq action embark-repeat-actions) t))) 1246 1247 (defun embark--formatted-bindings (keymap &optional nested) 1248 "Return the formatted keybinding of KEYMAP. 1249 The keybindings are returned in their order of appearance. 1250 If NESTED is non-nil subkeymaps are not flattened." 1251 (let* ((commands 1252 (cl-loop for (key . def) in (embark--all-bindings keymap nested) 1253 for name = (embark--command-name def) 1254 for cmd = (keymap--menu-item-binding def) 1255 unless (memq cmd '(nil embark-keymap-help 1256 negative-argument digit-argument)) 1257 collect (list name cmd key 1258 (concat 1259 (if (eq (car-safe def) 'menu-item) 1260 "menu-item" 1261 (key-description key)))))) 1262 (width (cl-loop for (_name _cmd _key desc) in commands 1263 maximize (length desc))) 1264 (default) 1265 (candidates 1266 (cl-loop for item in commands 1267 for (name cmd key desc) = item 1268 for desc-rep = 1269 (concat 1270 (propertize desc 'face 'embark-keybinding) 1271 (and (embark--action-repeatable-p cmd) 1272 embark-keybinding-repeat)) 1273 for formatted = 1274 (propertize 1275 (concat desc-rep 1276 (make-string (- width (length desc-rep) -1) ?\s) 1277 name) 1278 'embark-command cmd) 1279 when (equal key [13]) 1280 do (setq default formatted) 1281 collect (cons formatted item)))) 1282 (cons candidates default))) 1283 1284 (defun embark--with-category (category candidates) 1285 "Return completion table for CANDIDATES of CATEGORY with sorting disabled." 1286 (lambda (string predicate action) 1287 (if (eq action 'metadata) 1288 `(metadata (display-sort-function . identity) 1289 (cycle-sort-function . identity) 1290 (category . ,category)) 1291 (complete-with-action 1292 action candidates string predicate)))) 1293 1294 (defun embark-completing-read-prompter (keymap update &optional no-default) 1295 "Prompt via completion for a command bound in KEYMAP. 1296 If NO-DEFAULT is t, no default value is passed to`completing-read'. 1297 1298 UPDATE is the indicator update function. It is not used directly 1299 here, but if the user switches to `embark-keymap-prompter', the 1300 UPDATE function is passed to it." 1301 (let* ((candidates+def (embark--formatted-bindings keymap)) 1302 (candidates (car candidates+def)) 1303 (def (and (not no-default) (cdr candidates+def))) 1304 (buf (current-buffer)) 1305 (choice 1306 (catch 'choice 1307 (minibuffer-with-setup-hook 1308 (lambda () 1309 (let ((map (make-sparse-keymap))) 1310 (define-key map "\M-q" 1311 (lambda () 1312 (interactive) 1313 (with-current-buffer buf 1314 (embark-toggle-quit)))) 1315 (when-let (cycle (embark--cycle-key)) 1316 ;; Rebind `embark-cycle' in order allow cycling 1317 ;; from the `completing-read' prompter. Additionally 1318 ;; `embark-cycle' can be selected via 1319 ;; `completing-read'. The downside is that this breaks 1320 ;; recursively acting on the candidates of type 1321 ;; embark-keybinding in the `completing-read' prompter. 1322 (define-key map cycle 1323 (cond 1324 ((eq (lookup-key keymap cycle) 'embark-cycle) 1325 (lambda () 1326 (interactive) 1327 (throw 'choice 'embark-cycle))) 1328 ((null embark-cycle-key) 1329 (lambda () 1330 (interactive) 1331 (minibuffer-message 1332 "No cycling possible; press `%s' again to act." 1333 (key-description cycle)) 1334 (define-key map cycle #'embark-act)))))) 1335 (when embark-keymap-prompter-key 1336 (keymap-set map embark-keymap-prompter-key 1337 (lambda () 1338 (interactive) 1339 (message "Press key binding") 1340 (let ((cmd (embark-keymap-prompter keymap update))) 1341 (if (null cmd) 1342 (user-error "Unknown key") 1343 (throw 'choice cmd)))))) 1344 (use-local-map 1345 (make-composed-keymap map (current-local-map))))) 1346 (completing-read 1347 "Command: " 1348 (embark--with-category 'embark-keybinding candidates) 1349 nil nil nil 'embark--prompter-history def))))) 1350 (pcase (assoc choice candidates) 1351 (`(,_formatted ,_name ,cmd ,key ,_desc) 1352 ;; Set last-command-event as it would be from the command loop. 1353 (setq last-command-event (aref key (1- (length key)))) 1354 cmd) 1355 ('nil (intern-soft choice))))) 1356 1357 ;;; Verbose action indicator 1358 1359 (defgroup embark-indicators nil 1360 "Indicators display information about actions and targets." 1361 :group 'embark) 1362 1363 (defcustom embark-indicators 1364 '(embark-mixed-indicator 1365 embark-highlight-indicator 1366 embark-isearch-highlight-indicator) 1367 "Indicator functions to use when acting or becoming. 1368 The indicator functions are called from both `embark-act' and 1369 from `embark-become' and should display information about this to 1370 the user, such as: which of those two commands is running; a 1371 description of the key bindings that are available for actions or 1372 commands to become; and, in the case of `embark-act', the type 1373 and value of the targets, and whether other targets are available 1374 via `embark-cycle'. The indicator function is free to display as 1375 much or as little of this information as desired and can use any 1376 Emacs interface elements to do so. 1377 1378 Embark comes with five such indicators: 1379 1380 - `embark-minimal-indicator', which does not display any 1381 information about keybindings, but does display types and 1382 values of action targets in the echo area or minibuffer prompt, 1383 1384 - `embark-verbose-indicator', which pops up a buffer containing 1385 detailed information including key bindings and the first line 1386 of the docstring of the commands they run, and 1387 1388 - `embark-mixed-indicator', which combines the minimal and the 1389 verbose indicator: the minimal indicator is shown first and the 1390 verbose popup is shown after `embark-mixed-indicator-delay' 1391 seconds. 1392 1393 - `embark-highlight-indicator', which highlights the target 1394 at point. 1395 1396 - `embark-isearch-highlight-indicator', which when the target at 1397 point is an identifier or symbol, lazily highlights all 1398 occurrences of it. 1399 1400 The protocol for indicator functions is as follows: 1401 1402 When called from `embark-act', an indicator function is called 1403 without arguments. The indicator function should then return a 1404 closure, which captures the indicator state. The returned 1405 closure must accept up to three optional arguments, the action 1406 keymap, the targets (plists as returned by `embark--targets') and 1407 the prefix keys typed by the user so far. The keymap, targets 1408 and prefix keys may be updated when cycling targets at point 1409 resulting in multiple calls to the closure. When called from 1410 `embark-become', the indicator closure will be called with the 1411 keymap of commands to become, a fake target list containing a 1412 single target of type `embark-become' and whose value is the 1413 minibuffer input, and the prefix set to nil. Note, in 1414 particular, that if an indicator function wishes to distinguish 1415 between `embark-act' and `embark-become' it should check whether 1416 the `car' of the first target is `embark-become'. 1417 1418 After the action has been performed the indicator closure is 1419 called without arguments, such that the indicator can perform the 1420 necessary cleanup work. For example, if the indicator adds 1421 overlays, it should remove these overlays. The indicator should 1422 be written in a way that it is safe to call it for cleanup more 1423 than once, in fact, it should be able to handle any sequence of 1424 update and cleanup calls ending in a call for cleanup. 1425 1426 NOTE: Experience shows that the indicator calling convention may 1427 change again in order to support more action features. The 1428 calling convention should currently be considered unstable. 1429 Please keep this in mind when writing a custom indicator 1430 function, or when using the `which-key' indicator function from 1431 the wiki." 1432 :type '(repeat 1433 (choice 1434 (const :tag "Verbose indicator" embark-verbose-indicator) 1435 (const :tag "Minimal indicator" embark-minimal-indicator) 1436 (const :tag "Mixed indicator" embark-mixed-indicator) 1437 (const :tag "Highlight target" embark-highlight-indicator) 1438 (const :tag "Highlight all occurrences" 1439 embark-isearch-highlight-indicator) 1440 (function :tag "Other")))) 1441 1442 (defface embark-verbose-indicator-documentation 1443 '((t :inherit completions-annotations)) 1444 "Face used by the verbose action indicator to display binding descriptions. 1445 Used by `embark-verbose-indicator'.") 1446 1447 (defface embark-verbose-indicator-title '((t :height 1.1 :weight bold)) 1448 "Face used by the verbose action indicator for the title. 1449 Used by `embark-verbose-indicator'.") 1450 1451 (defface embark-verbose-indicator-shadowed '((t :inherit shadow)) 1452 "Face used by the verbose action indicator for the shadowed targets. 1453 Used by `embark-verbose-indicator'.") 1454 1455 (defcustom embark-verbose-indicator-display-action 1456 '(display-buffer-reuse-window) 1457 "Parameters added to `display-buffer-alist' to show the actions buffer. 1458 See the docstring of `display-buffer' for information on what 1459 display actions and parameters are available." 1460 :type `(choice 1461 (const :tag "Reuse some window" 1462 (display-buffer-reuse-window)) 1463 (const :tag "Below target buffer" 1464 (display-buffer-below-selected 1465 (window-height . fit-window-to-buffer))) 1466 (const :tag "Bottom of frame (fixed-size)" 1467 (display-buffer-at-bottom)) 1468 (const :tag "Bottom of frame (resizes during cycling)" 1469 (display-buffer-at-bottom 1470 (window-height . fit-window-to-buffer))) 1471 (const :tag "Side window on the right" 1472 (display-buffer-in-side-window (side . right))) 1473 (const :tag "Side window on the left" 1474 (display-buffer-in-side-window (side . left))) 1475 (sexp :tag "Other"))) 1476 1477 (defcustom embark-verbose-indicator-excluded-actions nil 1478 "Commands not displayed by `embark-verbose-indicator'. 1479 This variable should be set to a list of symbols and regexps. 1480 The verbose indicator will exclude from its listing any commands 1481 matching an element of this list." 1482 :type '(choice 1483 (const :tag "Exclude nothing" nil) 1484 (const :tag "Exclude Embark general actions" 1485 (embark-collect embark-live embark-export 1486 embark-cycle embark-act-all embark-keymap-help 1487 embark-become embark-isearch)) 1488 (repeat :tag "Other" (choice regexp symbol)))) 1489 1490 (defcustom embark-verbose-indicator-buffer-sections 1491 `(target "\n" shadowed-targets " " cycle "\n" bindings) 1492 "List of sections to display in the verbose indicator buffer, in order. 1493 You can use either a symbol designating a concrete section (one 1494 of the keywords below, but without the colon), a string literal 1495 or a function returning a string or list of strings to insert and 1496 that accepts the following keyword arguments: 1497 1498 - `:target', the target as a cons of type and value, 1499 - `:shadowed-targets', a list of conses for the other targets, 1500 - `:bindings' a list returned by `embark--formatted-bindings', and 1501 - `:cycle', a string describing the key binding of `embark-cycle'." 1502 :type '(repeat 1503 (choice (const :tag "Current target name" target) 1504 (const :tag "List of other shadowed targets" shadowed-targets) 1505 (const :tag "Key bindings" bindings) 1506 (const :tag "Cycle indicator" cycle) 1507 (string :tag "Literal string") 1508 (function :tag "Custom function")))) 1509 1510 (defcustom embark-verbose-indicator-nested t 1511 "Whether the verbose indicator should use nested keymap navigation. 1512 When this variable is non-nil the actions buffer displayed by 1513 `embark-verbose-indicator' will include any prefix keys found in 1514 the keymap it is displaying, and will update to show what is 1515 bound under the prefix if the prefix is pressed. If this 1516 variable is nil, then the actions buffer will contain a flat list 1517 of all full key sequences bound in the keymap." 1518 :type 'boolean) 1519 1520 (defun embark--verbose-indicator-excluded-p (cmd) 1521 "Return non-nil if CMD should be excluded from the verbose indicator." 1522 (seq-find (lambda (x) 1523 (if (symbolp x) 1524 (eq cmd x) 1525 (string-match-p x (symbol-name cmd)))) 1526 embark-verbose-indicator-excluded-actions)) 1527 1528 (cl-defun embark--verbose-indicator-section-target 1529 (&key targets bindings &allow-other-keys) 1530 "Format the TARGETS section for the indicator buffer. 1531 BINDINGS is the formatted list of keybindings." 1532 (let ((result (embark--format-targets 1533 (car targets) 1534 nil ; the shadowed targets section deals with these 1535 (cl-find 'embark-done bindings :key #'caddr :test #'eq)))) 1536 (add-face-text-property 0 (length result) 1537 'embark-verbose-indicator-title 1538 'append 1539 result) 1540 result)) 1541 1542 (cl-defun embark--verbose-indicator-section-cycle 1543 (&key cycle shadowed-targets &allow-other-keys) 1544 "Format the CYCLE key section for the indicator buffer. 1545 SHADOWED-TARGETS is the list of other targets." 1546 (concat 1547 (and cycle (propertize (format "(%s to cycle)" cycle) 1548 'face 'embark-verbose-indicator-shadowed)) 1549 (and shadowed-targets "\n"))) 1550 1551 (cl-defun embark--verbose-indicator-section-shadowed-targets 1552 (&key shadowed-targets &allow-other-keys) 1553 "Format the SHADOWED-TARGETS section for the indicator buffer." 1554 (when shadowed-targets 1555 (propertize (format "Shadowed targets at point: %s" 1556 (string-join shadowed-targets ", ")) 1557 'face 'embark-verbose-indicator-shadowed))) 1558 1559 (cl-defun embark--verbose-indicator-section-bindings 1560 (&key bindings &allow-other-keys) 1561 "Format the BINDINGS section for the indicator buffer." 1562 (let* ((max-width (apply #'max (cons 0 (mapcar (lambda (x) 1563 (string-width (car x))) 1564 bindings)))) 1565 (fmt (format "%%-%ds" (1+ max-width))) 1566 (result nil)) 1567 (dolist (binding bindings (string-join (nreverse result))) 1568 (let ((cmd (caddr binding))) 1569 (unless (embark--verbose-indicator-excluded-p cmd) 1570 (let ((keys (format fmt (car binding))) 1571 (doc (embark--function-doc cmd))) 1572 (push (format "%s%s\n" keys 1573 (propertize 1574 (car (split-string (or doc "") "\n")) 1575 'face 'embark-verbose-indicator-documentation)) 1576 result))))))) 1577 1578 (defun embark--verbose-indicator-update (keymap targets) 1579 "Update verbose indicator buffer. 1580 The arguments are the new KEYMAP and TARGETS." 1581 (with-current-buffer (get-buffer-create embark--verbose-indicator-buffer) 1582 (let* ((inhibit-read-only t) 1583 (bindings 1584 (embark--formatted-bindings keymap embark-verbose-indicator-nested)) 1585 (bindings (car bindings)) 1586 (shadowed-targets (mapcar 1587 (lambda (x) (symbol-name (plist-get x :type))) 1588 (cdr targets))) 1589 (cycle (let ((ck (where-is-internal #'embark-cycle keymap))) 1590 (and ck (key-description (car ck)))))) 1591 (setq-local cursor-type nil) 1592 (setq-local truncate-lines t) 1593 (setq-local buffer-read-only t) 1594 (erase-buffer) 1595 (dolist (section embark-verbose-indicator-buffer-sections) 1596 (insert 1597 (if (stringp section) 1598 section 1599 (or (funcall 1600 (let ((prefixed (intern (format 1601 "embark--verbose-indicator-section-%s" 1602 section)))) 1603 (cond 1604 ((fboundp prefixed) prefixed) 1605 ((fboundp section) section) 1606 (t (error "Undefined verbose indicator section `%s'" 1607 section)))) 1608 :targets targets :shadowed-targets shadowed-targets 1609 :bindings bindings :cycle cycle) 1610 "")))) 1611 (goto-char (point-min))))) 1612 1613 (defun embark-verbose-indicator () 1614 "Indicator that displays a table of key bindings in a buffer. 1615 The default display includes the type and value of the current 1616 target, the list of other target types, and a table of key 1617 bindings, actions and the first line of their docstrings. 1618 1619 The order and formatting of these items is completely 1620 configurable through the variable 1621 `embark-verbose-indicator-buffer-sections'. 1622 1623 If the keymap being shown contains prefix keys, the table of key 1624 bindings can either show just the prefixes and update once the 1625 prefix is pressed, or it can contain a flat list of all full key 1626 sequences bound in the keymap. This is controlled by the 1627 variable `embark-verbose-indicator-nested'. 1628 1629 To reduce clutter in the key binding table, one can set the 1630 variable `embark-verbose-indicator-excluded-actions' to a list 1631 of symbols and regexps matching commands to exclude from the 1632 table. 1633 1634 To configure how a window is chosen to display this buffer, see 1635 the variable `embark-verbose-indicator-display-action'." 1636 (lambda (&optional keymap targets prefix) 1637 (if (not keymap) 1638 (when-let ((win (get-buffer-window embark--verbose-indicator-buffer 1639 'visible))) 1640 (quit-window 'kill-buffer win)) 1641 (embark--verbose-indicator-update 1642 (if (and prefix embark-verbose-indicator-nested) 1643 ;; Lookup prefix keymap globally if not found in action keymap 1644 (let ((overriding-terminal-local-map keymap)) 1645 (key-binding prefix 'accept-default)) 1646 keymap) 1647 targets) 1648 (let ((display-buffer-alist 1649 `(,@display-buffer-alist 1650 (,(regexp-quote embark--verbose-indicator-buffer) 1651 ,@embark-verbose-indicator-display-action)))) 1652 (display-buffer embark--verbose-indicator-buffer))))) 1653 1654 (defcustom embark-mixed-indicator-delay 0.5 1655 "Time in seconds after which the verbose indicator is shown. 1656 The mixed indicator starts by showing the minimal indicator and 1657 after this delay shows the verbose indicator." 1658 :type '(choice (const :tag "No delay" 0) 1659 (number :tag "Delay in seconds"))) 1660 1661 (defcustom embark-mixed-indicator-both nil 1662 "Show both indicators, even after the verbose indicator appeared." 1663 :type 'boolean) 1664 1665 (defun embark-mixed-indicator () 1666 "Mixed indicator showing keymap and targets. 1667 The indicator shows the `embark-minimal-indicator' by default. 1668 After `embark-mixed-indicator-delay' seconds, the 1669 `embark-verbose-indicator' is shown. This which-key-like approach 1670 ensures that Embark stays out of the way for quick actions. The 1671 helpful keybinding reminder still pops up automatically without 1672 further user intervention." 1673 (let ((vindicator (embark-verbose-indicator)) 1674 (mindicator (embark-minimal-indicator)) 1675 vindicator-active 1676 vtimer) 1677 (lambda (&optional keymap targets prefix) 1678 ;; Always cancel the timer. 1679 ;; 1. When updating, cancel timer, since the user has pressed 1680 ;; a key before the timer elapsed. 1681 ;; 2. For cleanup, the timer must also be canceled. 1682 (when vtimer 1683 (cancel-timer vtimer) 1684 (setq vtimer nil)) 1685 (if (not keymap) 1686 (progn 1687 (funcall vindicator) 1688 (when mindicator 1689 (funcall mindicator))) 1690 (when mindicator 1691 (funcall mindicator keymap targets prefix)) 1692 (if vindicator-active 1693 (funcall vindicator keymap targets prefix) 1694 (setq vtimer 1695 (run-at-time 1696 embark-mixed-indicator-delay nil 1697 (lambda () 1698 (when (and (not embark-mixed-indicator-both) mindicator) 1699 (funcall mindicator) 1700 (setq mindicator nil)) 1701 (setq vindicator-active t) 1702 (funcall vindicator keymap targets prefix))))))))) 1703 1704 ;;;###autoload 1705 (defun embark-bindings-in-keymap (keymap) 1706 "Explore command key bindings in KEYMAP with `completing-read'. 1707 The selected command will be executed. Interactively, prompt the 1708 user for a KEYMAP variable." 1709 (interactive 1710 (list 1711 (symbol-value 1712 (intern-soft 1713 (completing-read 1714 "Keymap: " 1715 (embark--with-category 1716 'variable 1717 (cl-loop for x being the symbols 1718 if (and (boundp x) (keymapp (symbol-value x))) 1719 collect (symbol-name x))) 1720 nil t nil 'variable-name-history 1721 (let ((major-mode-map 1722 (concat (symbol-name major-mode) "-map"))) 1723 (when (intern-soft major-mode-map) major-mode-map))))))) 1724 (when-let (command (embark-completing-read-prompter keymap nil 'no-default)) 1725 (call-interactively command))) 1726 1727 ;;;###autoload 1728 (defun embark-bindings (no-global) 1729 "Explore all current command key bindings with `completing-read'. 1730 The selected command will be executed. 1731 1732 If NO-GLOBAL is non-nil (interactively, if called with a prefix 1733 argument) omit global key bindings; this leaves key bindings from 1734 minor mode maps and the local map (usually set by the major 1735 mode), but also less common keymaps such as those from a text 1736 property or overlay, or the overriding maps: 1737 `overriding-terminal-local-map' and `overriding-local-map'." 1738 (interactive "P") 1739 (embark-bindings-in-keymap 1740 (make-composed-keymap 1741 (let ((all-maps (current-active-maps t))) 1742 (if no-global (remq global-map all-maps) all-maps))))) 1743 1744 ;;;###autoload 1745 (defun embark-bindings-at-point () 1746 "Explore all key bindings at point with `completing-read'. 1747 The selected command will be executed. 1748 1749 This command lists key bindings found in keymaps specified by the 1750 text properties `keymap' or `local-map', from either buffer text 1751 or an overlay. These are not widely used in Emacs, and when they 1752 are used can be somewhat hard to discover. Examples of locations 1753 that have such a keymap are links and images in `eww' buffers, 1754 attachment links in `gnus' article buffers, and the 'Stash' line 1755 in a `vc-dir' buffer." 1756 (interactive) 1757 (let ((keymaps (delq nil (list (get-char-property (point) 'keymap) 1758 (get-char-property (point) 'local-map))))) 1759 (unless keymaps 1760 (user-error "No key bindings found at point")) 1761 (embark-bindings-in-keymap (make-composed-keymap keymaps)))) 1762 1763 ;;;###autoload 1764 (defun embark-prefix-help-command () 1765 "Prompt for and run a command bound in the prefix used for this command. 1766 The prefix described consists of all but the last event of the 1767 key sequence that ran this command. This function is intended to 1768 be used as a value for `prefix-help-command'. 1769 1770 In addition to using completion to select a command, you can also 1771 type @ and the key binding (without the prefix)." 1772 (interactive) 1773 (when-let ((keys (this-command-keys-vector)) 1774 (prefix (seq-take keys (1- (length keys)))) 1775 (keymap (key-binding prefix 'accept-default))) 1776 (embark-bindings-in-keymap keymap))) 1777 1778 (defun embark--prompt (indicators keymap targets) 1779 "Call the prompter with KEYMAP and INDICATORS. 1780 The TARGETS are displayed for actions outside the minibuffer." 1781 (mapc (lambda (i) (funcall i keymap targets)) indicators) 1782 (condition-case nil 1783 (minibuffer-with-setup-hook 1784 (lambda () 1785 ;; if the prompter opens its own minibuffer, show 1786 ;; the indicator there too 1787 (let ((inner-indicators (mapcar #'funcall embark-indicators))) 1788 (mapc (lambda (i) (funcall i keymap targets)) inner-indicators) 1789 (add-hook 'minibuffer-exit-hook 1790 (lambda () (mapc #'funcall inner-indicators)) 1791 nil t))) 1792 (let ((enable-recursive-minibuffers t)) 1793 (funcall embark-prompter keymap 1794 (lambda (prefix) 1795 (mapc (lambda (i) (funcall i keymap targets prefix)) 1796 indicators))))) 1797 (quit nil))) 1798 1799 (defvar embark--run-after-command-functions nil 1800 "Abnormal hook, used by `embark--run-after-command'.") 1801 1802 (defun embark--run-after-command (fn &rest args) 1803 "Call FN with ARGS after the current commands finishes. 1804 If multiple functions are queued with this function during the 1805 same command, they will be called in the order from the one 1806 queued most recently to the one queued least recently." 1807 ;; We don't simply add FN to `post-command-hook' because FN may recursively 1808 ;; call this function. In that case, FN would modify `post-command-hook' 1809 ;; from within post-command-hook, which doesn't behave properly in our case. 1810 ;; We use our own abnormal hook and run it from PCH in a way that it is OK to 1811 ;; modify it from within its own functions. 1812 (unless embark--run-after-command-functions 1813 (let (pch timer has-run) 1814 (setq pch 1815 (lambda () 1816 (remove-hook 'post-command-hook pch) 1817 (cancel-timer timer) 1818 (unless has-run 1819 (setq has-run t) 1820 (while embark--run-after-command-functions 1821 ;; The following funcall may recursively call 1822 ;; `embark--run-after-command', modifying 1823 ;; `embark--run-after-command-functions'. This is why this 1824 ;; loop has to be implemented carefully. We have to pop the 1825 ;; function off the hook before calling it. Using `dolist' 1826 ;; on the hook would also be incorrect, because it wouldn't 1827 ;; take modifications of this hook into account. 1828 (with-demoted-errors "embark PCH: %S" 1829 (condition-case nil 1830 (funcall (pop embark--run-after-command-functions)) 1831 (quit (message "Quit")))))))) 1832 (add-hook 'post-command-hook pch 'append) 1833 ;; Generally we prefer `post-command-hook' because it plays well with 1834 ;; keyboard macros. In some cases, `post-command-hook' isn't run after 1835 ;; exiting a recursive edit, so set up the following timer as a backup. 1836 (setq timer (run-at-time 0 nil pch)))) 1837 1838 ;; Keep the default-directory alive, since this is often overwritten, 1839 ;; for example by Consult commands. 1840 ;; TODO it might be necessary to add more dynamically bound variables 1841 ;; here. What we actually want are functions `capture-dynamic-scope' 1842 ;; and `eval-in-dynamic-scope', but this does not exist? 1843 (let ((dir default-directory)) 1844 (push (lambda () 1845 (let ((default-directory dir)) 1846 (apply fn args))) 1847 embark--run-after-command-functions))) 1848 1849 (defun embark--quit-and-run (fn &rest args) 1850 "Quit the minibuffer and then call FN with ARGS. 1851 If called outside the minibuffer, simply apply FN to ARGS." 1852 (if (not (minibufferp)) 1853 (apply fn args) 1854 (apply #'embark--run-after-command fn args) 1855 (embark--run-after-command #'set 'ring-bell-function ring-bell-function) 1856 (setq ring-bell-function #'ignore) 1857 (if (fboundp 'minibuffer-quit-recursive-edit) 1858 (minibuffer-quit-recursive-edit) 1859 (abort-recursive-edit)))) 1860 1861 (defun embark--run-action-hooks (hooks action target quit) 1862 "Run HOOKS for ACTION. 1863 The HOOKS argument must be alist. The keys t and :always are 1864 treated specially. The :always hooks are executed always and the 1865 t hooks are the default hooks, for when there are no 1866 command-specific hooks for ACTION. The QUIT, ACTION and TARGET 1867 arguments are passed to the hooks as keyword arguments." 1868 (mapc (lambda (h) (apply h :action action :quit quit target)) 1869 (or (alist-get action hooks) 1870 (alist-get t hooks))) 1871 (mapc (lambda (h) (apply h :action action :quit quit target)) 1872 (alist-get :always hooks))) 1873 1874 (defun embark--run-around-action-hooks (action target quit) 1875 "Run the `embark-around-action-hooks' for ACTION. 1876 All the applicable around hooks are composed in the order they 1877 are present in `embark-around-action-hooks'. The keys t and 1878 :always in `embark-around-action-hooks' are treated specially. 1879 The :always hooks are executed always (outermost) and the t hooks 1880 are the default hooks, for when there are no command-specific 1881 hooks for ACTION. The QUIT, ACTION and TARGET arguments are 1882 passed to the hooks as keyword arguments." 1883 (apply 1884 (seq-reduce 1885 (lambda (fn hook) 1886 (lambda (&rest args) (apply hook (plist-put args :run fn)))) 1887 (let ((hooks embark-around-action-hooks)) 1888 (reverse 1889 (append (or (alist-get action hooks) (alist-get t hooks)) 1890 (alist-get :always hooks)))) 1891 (lambda (&rest args) 1892 (command-execute (plist-get args :action)))) 1893 :action action :quit quit target)) 1894 1895 (defun embark--act (action target &optional quit) 1896 "Perform ACTION injecting the TARGET. 1897 If called from a minibuffer with non-nil QUIT, quit the 1898 minibuffer before executing the action." 1899 (if (memq action '(embark-become ; these actions should run in 1900 embark-collect ; the current buffer, not the 1901 embark-live ; target buffer 1902 embark-export 1903 embark-select 1904 embark-act-all)) 1905 (progn 1906 (embark--run-action-hooks embark-pre-action-hooks action target quit) 1907 (unwind-protect (embark--run-around-action-hooks action target quit) 1908 (embark--run-action-hooks embark-post-action-hooks 1909 action target quit))) 1910 (let* ((command embark--command) 1911 (prefix prefix-arg) 1912 (action-window (embark--target-window t)) 1913 (directory default-directory) 1914 (inject 1915 (lambda () 1916 (let ((contents (minibuffer-contents))) 1917 (delete-minibuffer-contents) 1918 (insert 1919 (propertize 1920 (substring-no-properties (plist-get target :target)) 1921 'embark--initial-input contents))) 1922 (if (memq 'ivy--queue-exhibit post-command-hook) 1923 ;; Ivy has special needs: (1) for file names 1924 ;; ivy-immediate-done is not equivalent to 1925 ;; exit-minibuffer, (2) it needs a chance to run 1926 ;; its post command hook first, so use depth 10 1927 (add-hook 'post-command-hook 'ivy-immediate-done 10 t) 1928 (add-hook 'post-command-hook #'exit-minibuffer nil t)) 1929 (embark--run-action-hooks embark-target-injection-hooks 1930 action target quit))) 1931 (dedicate (and (derived-mode-p 'embark-collect-mode) 1932 (not (window-dedicated-p)) 1933 (selected-window))) 1934 (multi (memq action embark-multitarget-actions)) 1935 (run-action 1936 (if (and (commandp action) (not multi)) 1937 (lambda () 1938 (let (final-window) 1939 (when dedicate (set-window-dedicated-p dedicate t)) 1940 (unwind-protect 1941 (with-selected-window action-window 1942 (let ((enable-recursive-minibuffers t) 1943 (embark--command command) 1944 (prefix-arg prefix) 1945 ;; the next two avoid mouse dialogs 1946 (use-dialog-box nil) 1947 (last-nonmenu-event 13) 1948 (default-directory directory)) 1949 (embark--run-action-hooks embark-pre-action-hooks 1950 action target quit) 1951 (minibuffer-with-setup-hook inject 1952 ;; pacify commands that use (this-command-keys) 1953 (when (= (length (this-command-keys)) 0) 1954 (set--this-command-keys 1955 (if (characterp last-command-event) 1956 (string last-command-event) 1957 "\r"))) 1958 (setq this-command action) 1959 (embark--run-around-action-hooks 1960 action target quit))) 1961 (setq final-window (selected-window))) 1962 (embark--run-action-hooks embark-post-action-hooks 1963 action target quit) 1964 (when dedicate (set-window-dedicated-p dedicate nil))) 1965 (unless (eq final-window action-window) 1966 (select-window final-window)))) 1967 ;; TODO uniformize the command and non-interactive cases? 1968 (let ((argument 1969 (if multi 1970 (or (plist-get target :candidates) ; embark-act-all 1971 (list (plist-get target :target))) 1972 (plist-get target :target)))) 1973 (lambda () 1974 (with-selected-window action-window 1975 (embark--run-action-hooks embark-pre-action-hooks 1976 action target quit) 1977 (unwind-protect 1978 (let ((current-prefix-arg prefix) 1979 (default-directory directory)) 1980 (funcall action argument)) 1981 (embark--run-action-hooks embark-post-action-hooks 1982 action target quit)))))))) 1983 (setq prefix-arg nil) 1984 (if quit (embark--quit-and-run run-action) (funcall run-action))))) 1985 1986 (defun embark--refine-multi-category (_type target) 1987 "Refine `multi-category' TARGET to its actual type." 1988 (or (get-text-property 0 'multi-category target) 1989 (cons 'general target))) 1990 1991 (defun embark--simplify-path (_type target) 1992 "Simplify and '//' or '~/' in the TARGET file path." 1993 (cons 'file (substitute-in-file-name target))) 1994 1995 (defun embark--keybinding-command (_type target) 1996 "Treat an `embark-keybinding' TARGET as a command." 1997 (when-let ((cmd (get-text-property 0 'embark-command target))) 1998 (cons 'command (format "%s" cmd)))) 1999 2000 (defun embark--lookup-lighter-minor-mode (_type target) 2001 "If TARGET is a lighter, look up its minor mode. 2002 2003 The `describe-minor-mode' command has as completion candidates 2004 both minor-modes and their lighters. This function replaces the 2005 lighters by their minor modes, so actions expecting a function 2006 work on them." 2007 (cons 'minor-mode 2008 (let ((symbol (intern-soft target))) 2009 (if (and symbol (boundp symbol)) 2010 target 2011 (symbol-name (lookup-minor-mode-from-indicator target)))))) 2012 2013 (declare-function project-current "project") 2014 (declare-function project-roots "project") 2015 (declare-function project-root "project") 2016 2017 (defun embark--project-file-full-path (_type target) 2018 "Get full path of project file TARGET." 2019 ;; TODO project-find-file can be called from outside all projects in 2020 ;; which case it prompts for a project first; we don't support that 2021 ;; case yet, since there is no current project. 2022 (cons 'file 2023 (if-let ((project (project-current)) 2024 (root (if (fboundp 'project-root) 2025 (project-root project) 2026 (with-no-warnings 2027 (car (project-roots project)))))) 2028 (expand-file-name target root) 2029 target))) 2030 2031 (defun embark--remove-package-version (_type target) 2032 "Remove version number from a versioned package TARGET." 2033 (cons 'package (replace-regexp-in-string "-[0-9.]+$" "" target))) 2034 2035 (defun embark--targets () 2036 "Retrieve current targets. 2037 2038 An initial guess at the current targets and their types is 2039 determined by running the functions in `embark-target-finders'. 2040 Each function should either return nil, a pair of a type symbol 2041 and target string or a triple of a type symbol, target string and 2042 target bounds. 2043 2044 In the minibuffer only the first target finder returning non-nil 2045 is taken into account. When finding targets at point in other 2046 buffers, all target finder function is executed. 2047 2048 For each target, the type is then looked up as a key in the 2049 variable `embark-transformer-alist'. If there is a transformer 2050 for the type, it is called with the type and target, and must 2051 return a `cons' of the transformed type and transformed target. 2052 2053 The return value of `embark--targets' is a list of plists. Each 2054 plist concerns one target, and has keys `:type', `:target', 2055 `:orig-type', `:orig-target' and `:bounds'." 2056 (let (targets) 2057 (run-hook-wrapped 2058 'embark-target-finders 2059 (lambda (fun) 2060 (dolist (found (when-let (result (funcall fun)) 2061 (if (consp (car result)) result (list result)))) 2062 (let* ((type (or (car found) 'general)) 2063 (target+bounds (cdr found)) 2064 (target (if (consp target+bounds) 2065 (car target+bounds) 2066 target+bounds)) 2067 (bounds (and (consp target+bounds) (cdr target+bounds))) 2068 (full-target 2069 (append 2070 (list :orig-type type :orig-target target :bounds bounds) 2071 (if-let (transform (alist-get type embark-transformer-alist)) 2072 (let ((trans (funcall transform type target))) 2073 (list :type (car trans) :target (cdr trans))) 2074 (list :type type :target target))))) 2075 (push full-target targets))) 2076 (and targets (minibufferp)))) 2077 (cl-delete-duplicates 2078 (nreverse targets) 2079 :test (lambda (t1 t2) 2080 (and (equal (plist-get t1 :target) (plist-get t2 :target)) 2081 (eq (plist-get t1 :type) (plist-get t2 :type))))))) 2082 2083 (defun embark--default-action (type) 2084 "Return default action for the given TYPE of target. 2085 The most common case is that the target comes from minibuffer 2086 completion, in which case the default action is the command that 2087 opened the minibuffer in the first place. This can be overridden 2088 by `embark-default-action-overrides'. 2089 2090 For targets that do not come from minibuffer completion 2091 \(typically some thing at point in a regular buffer) and whose 2092 type is not listed in `embark-default-action-overrides', the 2093 default action is given by whatever binding RET has in the action 2094 keymap for the given type." 2095 (or (alist-get (cons type embark--command) embark-default-action-overrides 2096 nil nil #'equal) 2097 (alist-get type embark-default-action-overrides) 2098 (alist-get t embark-default-action-overrides) 2099 embark--command 2100 (lookup-key (embark--raw-action-keymap type) "\r"))) 2101 2102 (defun embark--rotate (list k) 2103 "Rotate LIST by K elements and return the rotated list." 2104 (setq k (mod k (length list))) 2105 (append (seq-drop list k) (seq-take list k))) 2106 2107 (defun embark--orig-target (target) 2108 "Convert TARGET to original target." 2109 (plist-put 2110 (plist-put 2111 (copy-sequence target) 2112 :target (plist-get target :orig-target)) 2113 :type (plist-get target :orig-type))) 2114 2115 (defun embark--quit-p (action) 2116 "Determine whether to quit the minibuffer after ACTION. 2117 This function consults `embark-quit-after-action' to decide 2118 whether or not the user wishes to quit the minibuffer after 2119 performing the ACTION, assuming this is done from a minibuffer." 2120 (let* ((cfg embark-quit-after-action) 2121 (quit (if (consp cfg) (alist-get action cfg (alist-get t cfg)) cfg))) 2122 (when embark--toggle-quit (setq quit (not quit))) 2123 (setq embark--toggle-quit nil) 2124 quit)) 2125 2126 ;;;###autoload 2127 (defun embark-act (&optional arg) 2128 "Prompt the user for an action and perform it. 2129 The targets of the action are chosen by `embark-target-finders'. 2130 By default, if called from a minibuffer the target is the top 2131 completion candidate. When called from a non-minibuffer buffer 2132 there can multiple targets and you can cycle among them by using 2133 `embark-cycle' (which is bound by default to the same key 2134 binding `embark-act' is, but see `embark-cycle-key'). 2135 2136 This command uses `embark-prompter' to ask the user to specify an 2137 action, and calls it injecting the target at the first minibuffer 2138 prompt. 2139 2140 If you call this from the minibuffer, it can optionally quit the 2141 minibuffer. The variable `embark-quit-after-action' controls 2142 whether calling `embark-act' with nil ARG quits the minibuffer, 2143 and if ARG is non-nil it will do the opposite. Interactively, 2144 ARG is the prefix argument. 2145 2146 If instead you call this from outside the minibuffer, the first 2147 ARG targets are skipped over (if ARG is negative the skipping is 2148 done by cycling backwards) and cycling starts from the following 2149 target." 2150 (interactive "P") 2151 (let* ((targets (or (embark--targets) (user-error "No target found"))) 2152 (indicators (mapcar #'funcall embark-indicators)) 2153 (default-done nil)) 2154 (when arg 2155 (if (minibufferp) 2156 (embark-toggle-quit) 2157 (setq targets (embark--rotate targets (prefix-numeric-value arg))))) 2158 (unwind-protect 2159 (while 2160 (let* ((target (car targets)) 2161 (action 2162 (or (embark--prompt 2163 indicators 2164 (let ((embark-default-action-overrides 2165 (if default-done 2166 `((t . ,default-done)) 2167 embark-default-action-overrides))) 2168 (embark--action-keymap (plist-get target :type) 2169 (cdr targets))) 2170 targets) 2171 (user-error "Canceled"))) 2172 (default-action (or default-done 2173 (embark--default-action 2174 (plist-get target :type))))) 2175 (cond 2176 ;; When acting twice in the minibuffer, do not restart 2177 ;; `embark-act'. Otherwise the next `embark-act' will 2178 ;; find a target in the original buffer. 2179 ((eq action #'embark-act) 2180 (message "Press an action key")) 2181 ((eq action #'embark-cycle) 2182 (setq targets (embark--rotate 2183 targets (prefix-numeric-value prefix-arg)))) 2184 (t 2185 ;; if the action is non-repeatable, cleanup indicator now 2186 (let ((repeat (embark--action-repeatable-p action))) 2187 (unless repeat (mapc #'funcall indicators)) 2188 (condition-case err 2189 (embark--act 2190 action 2191 (if (and (eq action default-action) 2192 (eq action embark--command) 2193 (not (memq action embark-multitarget-actions))) 2194 (embark--orig-target target) 2195 target) 2196 (embark--quit-p action)) 2197 (user-error 2198 (funcall (if repeat #'message #'user-error) 2199 "%s" (cadr err)))) 2200 (when-let (new-targets (and repeat (embark--targets))) 2201 ;; Terminate repeated prompter on default action, 2202 ;; when repeating. Jump to the region type if the 2203 ;; region is active after the action, or else to the 2204 ;; current type again. 2205 (setq default-done #'embark-done 2206 targets 2207 (embark--rotate 2208 new-targets 2209 (or (cl-position-if 2210 (let ((desired-type 2211 (if (eq repeat t) 2212 (plist-get (car targets) :type) 2213 repeat))) 2214 (lambda (x) 2215 (eq (plist-get x :type) desired-type))) 2216 new-targets) 2217 0))))))))) 2218 (mapc #'funcall indicators)))) 2219 2220 (defun embark--maybe-transform-candidates () 2221 "Collect candidates and see if they all transform to the same type. 2222 Return a plist with keys `:type', `:orig-type', `:candidates', and 2223 `:orig-candidates'." 2224 (pcase-let* ((`(,type . ,candidates) 2225 (run-hook-with-args-until-success 'embark-candidate-collectors)) 2226 (bounds (mapcar #'cdr-safe candidates))) 2227 (setq candidates 2228 (mapcar (lambda (x) (if (consp x) (car x) x)) candidates)) 2229 (when (eq type 'file) 2230 (let ((dir (embark--default-directory))) 2231 (setq candidates 2232 (mapcar (lambda (cand) 2233 (abbreviate-file-name (expand-file-name cand dir))) 2234 candidates)))) 2235 (append 2236 (list :orig-type type :orig-candidates candidates :bounds bounds) 2237 (or (when candidates 2238 (when-let ((transformer (alist-get type embark-transformer-alist))) 2239 (pcase-let* ((`(,new-type . ,first-cand) 2240 (funcall transformer type (car candidates)))) 2241 (let ((new-candidates (list first-cand))) 2242 (when (cl-every 2243 (lambda (cand) 2244 (pcase-let ((`(,t-type . ,t-cand) 2245 (funcall transformer type cand))) 2246 (when (eq t-type new-type) 2247 (push t-cand new-candidates) 2248 t))) 2249 (cdr candidates)) 2250 (list :type new-type 2251 :candidates (nreverse new-candidates))))))) 2252 (list :type type :candidates candidates))))) 2253 2254 ;;;###autoload 2255 (defun embark-act-all (&optional arg) 2256 "Prompt the user for an action and perform it on each candidate. 2257 The candidates are chosen by `embark-candidate-collectors'. 2258 By default, if called from a minibuffer the candidates are the 2259 completion candidates. 2260 2261 This command uses `embark-prompter' to ask the user to specify an 2262 action, and calls it injecting the target at the first minibuffer 2263 prompt. 2264 2265 If you call this from the minibuffer, it can optionally quit the 2266 minibuffer. The variable `embark-quit-after-action' controls 2267 whether calling `embark-act' with nil ARG quits the minibuffer, 2268 and if ARG is non-nil it will do the opposite. Interactively, 2269 ARG is the prefix argument." 2270 (interactive "P") 2271 (let* ((transformed (embark--maybe-transform-candidates)) 2272 (type (plist-get transformed :type)) 2273 (orig-type (plist-get transformed :orig-type)) 2274 (candidates 2275 (or (cl-mapcar 2276 (lambda (cand orig-cand bounds) 2277 (list :type type :target cand 2278 :bounds (when bounds 2279 (cons (copy-marker (car bounds)) 2280 (copy-marker (cdr bounds)))) 2281 :orig-type orig-type :orig-target orig-cand)) 2282 (plist-get transformed :candidates) 2283 (plist-get transformed :orig-candidates) 2284 (plist-get transformed :bounds)) 2285 (user-error "No candidates to act on"))) 2286 (indicators (mapcar #'funcall embark-indicators))) 2287 (when arg (embark-toggle-quit)) 2288 (unwind-protect 2289 (let* ((action 2290 (or (embark--prompt 2291 indicators (embark--action-keymap type nil) 2292 (list (list :type type :multi (length candidates)))) 2293 (user-error "Canceled"))) 2294 (prefix prefix-arg) 2295 (act (lambda (candidate) 2296 (cl-letf (((symbol-function 'embark--restart) #'ignore) 2297 ((symbol-function 'embark--confirm) #'ignore)) 2298 (let ((prefix-arg prefix)) 2299 (embark--act action candidate))))) 2300 (quit (embark--quit-p action))) 2301 (when (and (eq action (embark--default-action type)) 2302 (eq action embark--command)) 2303 (setq candidates (mapcar #'embark--orig-target candidates))) 2304 (when (or (not (or embark-confirm-act-all 2305 (memq 'embark--confirm 2306 (alist-get action embark-pre-action-hooks)))) 2307 (y-or-n-p (format "Run %s on %d %ss? " 2308 action (length candidates) type))) 2309 (if (memq action embark-multitarget-actions) 2310 (let ((prefix-arg prefix)) 2311 (embark--act action transformed quit)) 2312 (if quit 2313 (embark--quit-and-run #'mapc act candidates) 2314 (mapc act candidates) 2315 (when (memq 'embark--restart 2316 (alist-get action embark-post-action-hooks)) 2317 (embark--restart)))))) 2318 (dolist (cand candidates) 2319 (when-let ((bounds (plist-get cand :bounds))) 2320 (set-marker (car bounds) nil) ; yay, manual memory management! 2321 (set-marker (cdr bounds) nil))) 2322 (setq prefix-arg nil) 2323 (mapc #'funcall indicators)))) 2324 2325 (defun embark-highlight-indicator () 2326 "Action indicator highlighting the target at point." 2327 (let (overlay) 2328 (lambda (&optional keymap targets _prefix) 2329 (let ((bounds (plist-get (car targets) :bounds))) 2330 (when (and overlay (or (not keymap) (not bounds))) 2331 (delete-overlay overlay) 2332 (setq overlay nil)) 2333 (when bounds 2334 (if overlay 2335 (move-overlay overlay (car bounds) (cdr bounds)) 2336 (setq overlay (make-overlay (car bounds) (cdr bounds)))) 2337 (overlay-put overlay 'face 'embark-target) 2338 (overlay-put overlay 'window (selected-window)) 2339 ;; high priority to override both bug reference and the lazy 2340 ;; isearch highlights in embark-isearch-highlight-indicator 2341 (overlay-put overlay 'priority 1001)))))) 2342 2343 (defun embark-isearch-highlight-indicator () 2344 "Action indicator highlighting all occurrences of the identifier at point. 2345 This indicator only does something for targets which are 2346 identifiers or symbols. For those it uses `isearch''s lazy 2347 highlighting feature to highlight all occurrences of the target in 2348 the buffer. This indicator is best used in conjunction with 2349 `embark-highlight-indicator': by using them both you get the 2350 target and the other occurrences of it highlighted in different 2351 colors." 2352 (lambda (&optional _keymap targets _prefix) 2353 (if (and (not (minibufferp)) 2354 (memq (plist-get (car targets) :orig-type) '(symbol identifier))) 2355 (let ((isearch-string (plist-get (car targets) :target)) 2356 (isearch-regexp-function #'isearch-symbol-regexp)) 2357 (isearch-lazy-highlight-new-loop)) 2358 (setq isearch-lazy-highlight-last-string nil) 2359 (lazy-highlight-cleanup t)))) 2360 2361 (defun embark-cycle (_arg) 2362 "Cycle over the next ARG targets at point. 2363 If ARG is negative, cycle backwards." 2364 (interactive "p") 2365 (user-error "Not meant to be called directly")) 2366 2367 (defun embark-done () 2368 "Terminate sequence of repeated actions." 2369 (interactive)) 2370 2371 ;;;###autoload 2372 (defun embark-dwim (&optional arg) 2373 "Run the default action on the current target. 2374 The target of the action is chosen by `embark-target-finders'. 2375 2376 If the target comes from minibuffer completion, then the default 2377 action is the command that opened the minibuffer in the first 2378 place, unless overridden by `embark-default-action-overrides'. 2379 2380 For targets that do not come from minibuffer completion 2381 \(typically some thing at point in a regular buffer) and whose 2382 type is not listed in `embark-default-action-overrides', the 2383 default action is given by whatever binding RET has in the action 2384 keymap for the target's type. 2385 2386 See `embark-act' for the meaning of the prefix ARG." 2387 (interactive "P") 2388 (if-let ((targets (embark--targets))) 2389 (let* ((target 2390 (or (nth 2391 (if (or (null arg) (minibufferp)) 2392 0 2393 (mod (prefix-numeric-value arg) (length targets))) 2394 targets))) 2395 (type (plist-get target :type)) 2396 (default-action (embark--default-action type)) 2397 (action (or (command-remapping default-action) default-action))) 2398 (unless action 2399 (user-error "No default action for %s targets" type)) 2400 (when (and arg (minibufferp)) (setq embark--toggle-quit t)) 2401 (embark--act action 2402 (if (and (eq default-action embark--command) 2403 (not (memq default-action 2404 embark-multitarget-actions))) 2405 (embark--orig-target target) 2406 target) 2407 (embark--quit-p action))) 2408 (user-error "No target found"))) 2409 2410 (defun embark--become-keymap () 2411 "Return keymap of commands to become for current command." 2412 (let ((map (make-composed-keymap 2413 (cl-loop for keymap-name in embark-become-keymaps 2414 for keymap = (symbol-value keymap-name) 2415 when (where-is-internal embark--command (list keymap)) 2416 collect keymap)))) 2417 (when embark-help-key 2418 (keymap-set map embark-help-key #'embark-keymap-help)) 2419 map)) 2420 2421 ;;;###autoload 2422 (defun embark-become (&optional full) 2423 "Make current command become a different command. 2424 Take the current minibuffer input as initial input for new 2425 command. The new command can be run normally using key bindings or 2426 \\[execute-extended-command], but if the current command is found in a keymap in 2427 `embark-become-keymaps', that keymap is activated to provide 2428 convenient access to the other commands in it. 2429 2430 If FULL is non-nil (interactively, if called with a prefix 2431 argument), the entire minibuffer contents are used as the initial 2432 input of the new command. By default only the part of the 2433 minibuffer contents between the current completion boundaries is 2434 taken. What this means is fairly technical, but (1) usually 2435 there is no difference: the completion boundaries include the 2436 entire minibuffer contents, and (2) the most common case where 2437 these notions differ is file completion, in which case the 2438 completion boundaries single out the path component containing 2439 point." 2440 (interactive "P") 2441 (unless (minibufferp) 2442 (user-error "Not in a minibuffer")) 2443 (let* ((target (if full 2444 (minibuffer-contents) 2445 (pcase-let ((`(,beg . ,end) (embark--boundaries))) 2446 (substring (minibuffer-contents) beg 2447 (+ end (embark--minibuffer-point)))))) 2448 (keymap (embark--become-keymap)) 2449 (targets `((:type embark-become :target ,target))) 2450 (indicators (mapcar #'funcall embark-indicators)) 2451 (become (unwind-protect 2452 (embark--prompt indicators keymap targets) 2453 (mapc #'funcall indicators)))) 2454 (unless become 2455 (user-error "Canceled")) 2456 (embark--become-command become target))) 2457 2458 (defun embark--become-command (command input) 2459 "Quit current minibuffer and start COMMAND with INPUT." 2460 (embark--quit-and-run 2461 (lambda () 2462 (minibuffer-with-setup-hook 2463 (lambda () 2464 (delete-minibuffer-contents) 2465 (insert input)) 2466 (let ((use-dialog-box nil) ;; avoid mouse dialogs 2467 (last-nonmenu-event 13)) 2468 (setq this-command command) 2469 (command-execute command)))))) 2470 2471 (defmacro embark-define-keymap (&rest _) 2472 "Obsolete macro, use `defvar-keymap' instead." 2473 (error "`embark-define-keymap' has been deprecated in Embark 0.21. 2474 Use standard methods for defining keymaps, such as `defvar-keymap'. 2475 Remember to make `embark-general-map' the parent if appropriate")) 2476 2477 ;;; Embark collect 2478 2479 (defgroup embark-collect nil 2480 "Buffers for acting on collected Embark targets." 2481 :group 'embark) 2482 2483 (defcustom embark-candidate-collectors 2484 '(embark-selected-candidates 2485 embark-minibuffer-candidates 2486 embark-completions-buffer-candidates 2487 embark-dired-candidates 2488 embark-ibuffer-candidates 2489 embark-embark-collect-candidates 2490 embark-custom-candidates) 2491 "List of functions that collect all candidates in a given context. 2492 These are used to fill an Embark Collect buffer. Each function 2493 should return either nil (to indicate it found no candidates) or 2494 a list whose first element is a symbol indicating the type of 2495 candidates and whose `cdr' is the list of candidates, each of 2496 which should be either a string or a dotted list of the 2497 form (TARGET START . END), where START and END are the buffer 2498 positions bounding the TARGET string." 2499 :type 'hook) 2500 2501 (defcustom embark-exporters-alist 2502 '((buffer . embark-export-ibuffer) 2503 (file . embark-export-dired) 2504 (package . embark-export-list-packages) 2505 (bookmark . embark-export-bookmarks) 2506 (variable . embark-export-customize-variable) 2507 (face . embark-export-customize-face) 2508 (symbol . embark-export-apropos) 2509 (minor-mode . embark-export-apropos) 2510 (function . embark-export-apropos) 2511 (command . embark-export-apropos) 2512 (t . embark-collect)) 2513 "Alist associating completion types to export functions. 2514 Each function should take a list of strings which are candidates 2515 for actions and make a buffer appropriate to manage them. For 2516 example, the default is to make a Dired buffer for files, and an 2517 ibuffer for buffers. 2518 2519 The key t is also allowed in the alist, and the corresponding 2520 value indicates the default function to use for other types. The 2521 default is `embark-collect'" 2522 :type '(alist :key-type symbol :value-type function)) 2523 2524 (defcustom embark-after-export-hook nil 2525 "Hook run after `embark-export' in the newly created buffer." 2526 :type 'hook) 2527 2528 (defface embark-collect-candidate '((t :inherit default)) 2529 "Face for candidates in Embark Collect buffers.") 2530 2531 (defface embark-collect-group-title 2532 '((t :inherit shadow :slant italic)) 2533 "Face for group titles in Embark Collect buffers.") 2534 2535 (defface embark-collect-group-separator 2536 '((t :inherit shadow :strike-through t italic)) 2537 "Face for group titles in Embark Collect buffers.") 2538 2539 (defcustom embark-collect-group-format 2540 (concat 2541 (propertize " " 'face 'embark-collect-group-separator) 2542 (propertize " %s " 'face 'embark-collect-group-title) 2543 (propertize " " 'face 'completions-group-separator 2544 'display '(space :align-to right))) 2545 "Format string used for the group title in Embark Collect buffers." 2546 :type 'string) 2547 2548 (defface embark-collect-annotation '((t :inherit completions-annotations)) 2549 "Face for annotations in Embark Collect. 2550 This is only used for annotation that are not already fontified.") 2551 2552 (defvar-local embark--rerun-function nil 2553 "Function to rerun the collect or export that made the current buffer.") 2554 2555 (autoload 'package-delete "package") 2556 (declare-function package--from-builtin "package") 2557 (declare-function package-desc-extras "package") 2558 (declare-function package-desc-name "package") 2559 (defvar package--builtins) 2560 (defvar package-alist) 2561 (defvar package-archive-contents) 2562 (defvar package--initialized) 2563 2564 (defun embark--package-desc (pkg) 2565 "Return the description structure for package PKG." 2566 (or ; found this in `describe-package-1' 2567 (car (alist-get pkg package-alist)) 2568 (if-let ((built-in (assq pkg package--builtins))) 2569 (package--from-builtin built-in) 2570 (car (alist-get pkg package-archive-contents))))) 2571 2572 (defun embark-minibuffer-candidates () 2573 "Return all current completion candidates from the minibuffer." 2574 (when (minibufferp) 2575 (let* ((all (completion-all-completions 2576 (minibuffer-contents) 2577 minibuffer-completion-table 2578 minibuffer-completion-predicate 2579 (embark--minibuffer-point))) 2580 (last (last all))) 2581 (when last (setcdr last nil)) 2582 (cons 2583 (completion-metadata-get (embark--metadata) 'category) 2584 all)))) 2585 2586 (defun embark-sorted-minibuffer-candidates () 2587 "Return a sorted list of current minibuffer completion candidates. 2588 This using the same sort order that `icomplete' and 2589 `minibuffer-force-complete' use. The intended usage is that you 2590 replace `embark-minibuffer-candidates' with this function in the 2591 list `embark-candidate-collectors'." 2592 (when (minibufferp) 2593 (cons 2594 (completion-metadata-get (embark--metadata) 'category) 2595 (nconc (cl-copy-list (completion-all-sorted-completions)) nil)))) 2596 2597 (declare-function dired-get-marked-files "dired") 2598 (declare-function dired-move-to-filename "dired") 2599 (declare-function dired-move-to-end-of-filename "dired") 2600 2601 (defun embark-dired-candidates () 2602 "Return marked or all files shown in Dired buffer. 2603 If any buffer is marked, return marked buffers; otherwise, return 2604 all buffers." 2605 (when (derived-mode-p 'dired-mode) 2606 (cons 'file 2607 (or 2608 ;; dired-get-marked-files returns the file on the current 2609 ;; line if no marked files are found; and when the fourth 2610 ;; argument is non-nil, the "no marked files" case is 2611 ;; distinguished from the "single marked file" case by 2612 ;; returning (list t marked-file) in the latter 2613 (let ((marked (dired-get-marked-files t nil nil t))) 2614 (and (cdr marked) 2615 (if (eq (car marked) t) (cdr marked) marked))) 2616 (save-excursion 2617 (goto-char (point-min)) 2618 (let (files) 2619 (while (not (eobp)) 2620 (when-let (file (dired-get-filename t t)) 2621 (push `(,file 2622 ,(progn (dired-move-to-filename) (point)) 2623 . ,(progn (dired-move-to-end-of-filename t) (point))) 2624 files)) 2625 (forward-line)) 2626 (nreverse files))))))) 2627 2628 (autoload 'ibuffer-marked-buffer-names "ibuffer") 2629 (declare-function ibuffer-map-lines-nomodify "ibuffer") 2630 2631 (defun embark-ibuffer-candidates () 2632 "Return marked or all buffers listed in ibuffer buffer. 2633 If any buffer is marked, return marked buffers; otherwise, return 2634 all buffers." 2635 (when (derived-mode-p 'ibuffer-mode) 2636 (cons 'buffer 2637 (or (ibuffer-marked-buffer-names) 2638 (let (buffers) 2639 (ibuffer-map-lines-nomodify 2640 (lambda (buffer _mark) 2641 (push (buffer-name buffer) buffers))) 2642 (nreverse buffers)))))) 2643 2644 (defun embark-embark-collect-candidates () 2645 "Return candidates in Embark Collect buffer. 2646 This makes `embark-export' work in Embark Collect buffers." 2647 (when (derived-mode-p 'embark-collect-mode) 2648 (cons embark--type 2649 (save-excursion 2650 (goto-char (point-min)) 2651 (let (all) 2652 (push (cdr (embark-target-collect-candidate)) all) 2653 (while (forward-button 1 nil nil t) 2654 (push (cdr (embark-target-collect-candidate)) all)) 2655 (nreverse all)))))) 2656 2657 (defun embark-completions-buffer-candidates () 2658 "Return all candidates in a completions buffer." 2659 (when (derived-mode-p 'completion-list-mode) 2660 (cons 2661 embark--type 2662 (save-excursion 2663 (goto-char (point-min)) 2664 (next-completion 1) 2665 (let (all) 2666 (while (not (eobp)) 2667 (push (cdr (embark-target-completion-at-point)) all) 2668 (next-completion 1)) 2669 (nreverse all)))))) 2670 2671 (defun embark-custom-candidates () 2672 "Return all variables and faces listed in this `Custom-mode' buffer." 2673 (when (derived-mode-p 'Custom-mode) 2674 (cons 'symbol ; gets refined to variable or face when acted upon 2675 (save-excursion 2676 (goto-char (point-min)) 2677 (let (symbols) 2678 (while (not (eobp)) 2679 (when-let (widget (widget-at (point))) 2680 (when (eq (car widget) 'custom-visibility) 2681 (push 2682 `(,(symbol-name 2683 (plist-get (cdr (plist-get (cdr widget) :parent)) 2684 :value)) 2685 ,(point) 2686 . ,(progn 2687 (re-search-forward ":" (line-end-position) 'noerror) 2688 (point))) 2689 symbols))) 2690 (forward-line)) 2691 (nreverse symbols)))))) 2692 2693 2694 (defun embark-collect--target () 2695 "Return the Embark Collect candidate at point. 2696 This takes into account `embark-transformer-alist'." 2697 (let ((embark-target-finders '(embark-target-collect-candidate))) 2698 (car (embark--targets)))) 2699 2700 (defun embark--action-command (action) 2701 "Turn an ACTION into a command to perform the action. 2702 Returns the name of the command." 2703 (let ((name (intern (format "embark-action--%s" 2704 (embark--command-name action))))) 2705 (fset name (lambda (arg) 2706 (interactive "P") 2707 (when-let (target (embark-collect--target)) 2708 (let ((prefix-arg arg)) 2709 (embark--act action target))))) 2710 (when (fboundp action) 2711 (put name 'function-documentation (documentation action))) 2712 name)) 2713 2714 (defun embark--all-bindings (keymap &optional nested) 2715 "Return an alist of all bindings in KEYMAP. 2716 If NESTED is non-nil subkeymaps are not flattened." 2717 (let (bindings maps) 2718 (map-keymap 2719 (lambda (key def) 2720 (cond 2721 ((keymapp def) 2722 (if nested 2723 (push (cons (vector key) def) maps) 2724 (dolist (bind (embark--all-bindings def)) 2725 (push (cons (vconcat (vector key) (car bind)) (cdr bind)) 2726 maps)))) 2727 (def (push (cons (vector key) def) bindings)))) 2728 (keymap-canonicalize keymap)) 2729 (nconc (nreverse bindings) (nreverse maps)))) 2730 2731 (defun embark-collect--direct-action-map (type) 2732 "Return a direct action keymap for targets of given TYPE." 2733 (let* ((actions (embark--action-keymap type nil)) 2734 (map (make-sparse-keymap))) 2735 (set-keymap-parent map button-map) 2736 (pcase-dolist (`(,key . ,cmd) (embark--all-bindings actions)) 2737 (unless (or (equal key [13]) 2738 (memq cmd '(digit-argument negative-argument))) 2739 (define-key map key (if (eq cmd 'embark-keymap-help) 2740 #'embark-bindings-at-point 2741 (embark--action-command cmd))))) 2742 map)) 2743 2744 (define-minor-mode embark-collect-direct-action-minor-mode 2745 "Bind type-specific actions directly (without need for `embark-act')." 2746 :init-value nil 2747 :lighter " Act" 2748 (unless (derived-mode-p 'embark-collect-mode) 2749 (user-error "Not in an Embark Collect buffer")) 2750 (save-excursion 2751 (goto-char (point-min)) 2752 (let ((inhibit-read-only t) maps) 2753 (while (progn 2754 (when (tabulated-list-get-id) 2755 (put-text-property 2756 (point) (button-end (point)) 'keymap 2757 (if embark-collect-direct-action-minor-mode 2758 (when-let ((target (embark-collect--target)) 2759 (type (plist-get target :type))) 2760 (or (alist-get type maps) 2761 (setf (alist-get type maps) 2762 (embark-collect--direct-action-map type))))))) 2763 (forward-button 1 nil nil t)))))) 2764 2765 (define-button-type 'embark-collect-entry 2766 'face 'embark-collect-candidate 2767 'action 'embark-collect-choose) 2768 2769 (declare-function outline-toggle-children "outline") 2770 (define-button-type 'embark-collect-group 2771 'face 'embark-collect-group-title 2772 'action (lambda (_) (outline-toggle-children))) 2773 2774 (defun embark--boundaries () 2775 "Get current minibuffer completion boundaries." 2776 (let ((contents (minibuffer-contents)) 2777 (pt (embark--minibuffer-point))) 2778 (completion-boundaries 2779 (substring contents 0 pt) 2780 minibuffer-completion-table 2781 minibuffer-completion-predicate 2782 (substring contents pt)))) 2783 2784 (defun embark-collect-choose (entry) 2785 "Run default action on Embark Collect ENTRY." 2786 (pcase-let ((`(,type ,text ,start . ,end) 2787 (save-excursion 2788 (goto-char entry) 2789 (embark-target-collect-candidate)))) 2790 (embark--act (embark--default-action type) 2791 (list :target text 2792 :type type 2793 :bounds (cons start end))))) 2794 2795 (defvar-keymap embark-collect-mode-map 2796 :doc "Keymap for Embark collect mode." 2797 :parent tabulated-list-mode-map 2798 "a" #'embark-act 2799 "A" #'embark-act-all 2800 "M-a" #'embark-collect-direct-action-minor-mode 2801 "E" #'embark-export 2802 "s" #'isearch-forward 2803 "n" #'forward-button 2804 "p" #'backward-button 2805 "}" 'outline-next-heading 2806 "{" 'outline-previous-heading 2807 "<remap> <forward-paragraph>" 'outline-next-heading 2808 "<remap> <backward-paragraph>" 'outline-previous-heading 2809 "<remap> <revert-buffer>" #'embark-rerun-collect-or-export) 2810 2811 (defconst embark-collect--outline-string (string #x210000) 2812 "Special string used for outline headings in Embark Collect buffers. 2813 Chosen to be extremely unlikely to appear in a candidate.") 2814 2815 (define-derived-mode embark-collect-mode tabulated-list-mode "Embark Collect" 2816 "List of candidates to be acted on. 2817 The command `embark-act' is bound `embark-collect-mode-map', but 2818 you might prefer to change the key binding to match your other 2819 key binding for it. Or alternatively you might want to enable the 2820 embark collect direct action minor mode by adding the function 2821 `embark-collect-direct-action-minor-mode' to 2822 `embark-collect-mode-hook'. 2823 2824 Reverting an Embark Collect buffer has slightly unusual behavior 2825 if the buffer was obtained by running `embark-collect' from 2826 within a minibuffer completion session. In that case reverting 2827 just restarts the completion session, that is, the command that 2828 opened the minibuffer is run again and the minibuffer contents 2829 restored. You can then interact normally with the command, 2830 perhaps editing the minibuffer contents, and, if you wish, you 2831 can rerun `embark-collect' to get an updated buffer." 2832 :interactive nil :abbrev-table nil :syntax-table nil) 2833 2834 (defun embark-collect--metadatum (type metadatum) 2835 "Get METADATUM for current buffer's candidates. 2836 For non-minibuffers, assume candidates are of given TYPE." 2837 (if (minibufferp) 2838 (or (completion-metadata-get (embark--metadata) metadatum) 2839 (plist-get completion-extra-properties 2840 (intern (format ":%s" metadatum)))) 2841 ;; otherwise fake some metadata for Marginalia users's benefit 2842 (completion-metadata-get `((category . ,type)) metadatum))) 2843 2844 (defun embark-collect--affixator (type) 2845 "Get affixation function for current buffer's candidates. 2846 For non-minibuffers, assume candidates are of given TYPE." 2847 (or (embark-collect--metadatum type 'affixation-function) 2848 (let ((annotator 2849 (or (embark-collect--metadatum type 'annotation-function) 2850 (lambda (_) "")))) 2851 (lambda (candidates) 2852 (mapcar (lambda (c) 2853 (if-let (a (funcall annotator c)) (list c "" a) c)) 2854 candidates))))) 2855 2856 (defun embark--for-display (string) 2857 "Return visibly equivalent STRING without display and invisible properties." 2858 (let ((len (length string)) (pos 0) chunks) 2859 (while (/= pos len) 2860 (let ((dis (next-single-property-change pos 'display string len)) 2861 (display (get-text-property pos 'display string))) 2862 (if (stringp display) 2863 (progn (push display chunks) (setq pos dis)) 2864 (while (/= pos dis) 2865 (let ((inv (next-single-property-change pos 'invisible string dis))) 2866 (unless (get-text-property pos 'invisible string) 2867 (unless (and (= pos 0) (= inv len)) 2868 ;; avoid allocation for full string 2869 (push (substring string pos inv) chunks))) 2870 (setq pos inv)))))) 2871 (if chunks (apply #'concat (nreverse chunks)) string))) 2872 2873 (defun embark-collect--format-entries (candidates grouper) 2874 "Format CANDIDATES for `tabulated-list-mode' grouped by GROUPER. 2875 The GROUPER is either nil or a function like the `group-function' 2876 completion metadatum, that is, a function of two arguments, the 2877 first of which is a candidate and the second controls what is 2878 computed: if nil, the title of the group the candidate belongs 2879 to, and if non-nil, a rewriting of the candidate (useful to 2880 simplify the candidate so it doesn't repeat the group title, for 2881 example)." 2882 (let ((max-width 0) 2883 (transform 2884 (if grouper (lambda (cand) (funcall grouper cand t)) #'identity))) 2885 (setq tabulated-list-entries 2886 (mapcan 2887 (lambda (group) 2888 (cons 2889 `(nil [(,(concat (propertize embark-collect--outline-string 2890 'invisible t) 2891 (format embark-collect-group-format (car group))) 2892 type embark-collect-group) 2893 ("" skip t)]) 2894 (mapcar 2895 (pcase-lambda (`(,cand ,prefix ,annotation)) 2896 (let* ((display (embark--for-display (funcall transform cand))) 2897 (length (length annotation)) 2898 (faces (text-property-not-all 2899 0 length 'face nil annotation))) 2900 (setq max-width (max max-width (+ (string-width prefix) 2901 (string-width display)))) 2902 (when faces 2903 (add-face-text-property 0 length 'default t annotation)) 2904 `(,cand 2905 [(,(propertize display 'line-prefix prefix) 2906 type embark-collect-entry) 2907 (,annotation 2908 skip t 2909 ,@(unless faces 2910 '(face embark-collect-annotation)))]))) 2911 (cdr group)))) 2912 (if grouper 2913 (seq-group-by (lambda (item) (funcall grouper (car item) nil)) 2914 candidates) 2915 (list (cons "" candidates))))) 2916 (if (null grouper) 2917 (pop tabulated-list-entries) 2918 (setq-local outline-regexp embark-collect--outline-string) 2919 (outline-minor-mode)) 2920 (setq tabulated-list-format 2921 `[("Candidate" ,max-width t) ("Annotation" 0 t)]))) 2922 2923 (defun embark-collect--update-candidates (buffer) 2924 "Update candidates for Embark Collect BUFFER." 2925 (let* ((transformed (embark--maybe-transform-candidates)) 2926 (type (plist-get transformed :orig-type)) ; we need the originals for 2927 (candidates (plist-get transformed :orig-candidates)) ; default action 2928 (affixator (embark-collect--affixator type)) 2929 (grouper (embark-collect--metadatum type 'group-function))) 2930 (when (eq type 'file) 2931 (let ((dir (buffer-local-value 'default-directory buffer))) 2932 (setq candidates 2933 (mapcar (lambda (cand) 2934 (let ((rel (file-relative-name cand dir))) 2935 (if (string-prefix-p "../" rel) cand rel))) 2936 candidates)))) 2937 (setq candidates (funcall affixator candidates)) 2938 (with-current-buffer buffer 2939 (setq embark--type type) 2940 (embark-collect--format-entries candidates grouper)) 2941 candidates)) 2942 2943 (defun embark--collect (buffer-name) 2944 "Create an Embark Collect buffer named BUFFER-NAME. 2945 2946 The function `generate-new-buffer-name' is used to ensure the 2947 buffer has a unique name." 2948 (let ((buffer (generate-new-buffer buffer-name)) 2949 (rerun (embark--rerun-function #'embark-collect))) 2950 (with-current-buffer buffer 2951 ;; we'll run the mode hooks once the buffer is displayed, so 2952 ;; the hooks can make use of the window 2953 (delay-mode-hooks (embark-collect-mode))) 2954 2955 (embark--cache-info buffer) 2956 (unless (embark-collect--update-candidates buffer) 2957 (user-error "No candidates to collect")) 2958 2959 (with-current-buffer buffer 2960 (setq tabulated-list-use-header-line nil ; default to no header 2961 header-line-format nil 2962 tabulated-list--header-string nil) 2963 (setq embark--rerun-function rerun)) 2964 2965 (let ((window (display-buffer buffer))) 2966 (with-selected-window window 2967 (run-mode-hooks) 2968 (tabulated-list-revert)) 2969 (set-window-dedicated-p window t) 2970 buffer))) 2971 2972 (defun embark--descriptive-buffer-name (type) 2973 "Return a descriptive name for an Embark collect or export buffer. 2974 TYPE should be either `collect' or `export'." 2975 (format "*Embark %s: %s*" 2976 (capitalize (symbol-name type)) 2977 (if (minibufferp) 2978 (format "%s - %s" embark--command 2979 (minibuffer-contents-no-properties)) 2980 (buffer-name)))) 2981 2982 ;;;###autoload 2983 (defun embark-collect () 2984 "Create an Embark Collect buffer. 2985 2986 To control the display, add an entry to `display-buffer-alist' 2987 with key \"Embark Collect\". 2988 2989 In Embark Collect buffers `revert-buffer' is remapped to 2990 `embark-rerun-collect-or-export', which has slightly unusual 2991 behavior if the buffer was obtained by running `embark-collect' 2992 from within a minibuffer completion session. In that case 2993 rerunning just restarts the completion session, that is, the 2994 command that opened the minibuffer is run again and the 2995 minibuffer contents restored. You can then interact normally with 2996 the command, perhaps editing the minibuffer contents, and, if you 2997 wish, you can rerun `embark-collect' to get an updated buffer." 2998 (interactive) 2999 (let ((buffer (embark--collect (embark--descriptive-buffer-name 'collect)))) 3000 (when (minibufferp) 3001 (embark--run-after-command #'pop-to-buffer buffer) 3002 (embark--quit-and-run #'message nil)))) 3003 3004 ;;;###autoload 3005 (defun embark-live () 3006 "Create a live-updating Embark Collect buffer. 3007 3008 To control the display, add an entry to `display-buffer-alist' 3009 with key \"Embark Live\"." 3010 (interactive) 3011 (let ((live-buffer (embark--collect 3012 (format "*Embark Live: %s*" 3013 (if (minibufferp) 3014 (format "M-x %s" embark--command) 3015 (buffer-name))))) 3016 (run-collect (make-symbol "run-collect")) 3017 (stop-collect (make-symbol "stop-collect")) 3018 timer) 3019 (setf (symbol-function stop-collect) 3020 (lambda () 3021 (remove-hook 'change-major-mode-hook stop-collect t) 3022 (remove-hook 'after-change-functions run-collect t))) 3023 (setf (symbol-function run-collect) 3024 (lambda (_1 _2 _3) 3025 (unless timer 3026 (setq timer 3027 (run-with-idle-timer 3028 0.05 nil 3029 (lambda () 3030 (if (not (buffer-live-p live-buffer)) 3031 (funcall stop-collect) 3032 (embark-collect--update-candidates live-buffer) 3033 (with-current-buffer live-buffer 3034 ;; TODO figure out why I can't restore point 3035 (tabulated-list-print t t)) 3036 (setq timer nil)))))))) 3037 (add-hook 'after-change-functions run-collect nil t) 3038 (when (minibufferp) 3039 (add-hook 'change-major-mode-hook stop-collect nil t)))) 3040 3041 (defun embark--rerun-function (kind) 3042 "Return a rerun function for an export or collect buffer in this context. 3043 The parameter KIND should be either `embark-export' or `embark-collect'." 3044 (let ((buffer (or embark--target-buffer (embark--target-buffer))) 3045 (command embark--command)) 3046 (cl-flet ((rerunner (action) 3047 (lambda (&rest _) 3048 (quit-window 'kill-buffer) 3049 (with-current-buffer 3050 (if (buffer-live-p buffer) buffer (current-buffer)) 3051 (let ((embark--command command)) 3052 (funcall action)))))) 3053 (if (minibufferp) 3054 (rerunner 3055 (let ((input (minibuffer-contents-no-properties))) 3056 (lambda () 3057 (minibuffer-with-setup-hook 3058 (lambda () 3059 (delete-minibuffer-contents) 3060 (insert input)) 3061 (setq this-command embark--command) 3062 (command-execute embark--command))))) 3063 (rerunner kind))))) 3064 3065 (defun embark-rerun-collect-or-export () 3066 "Rerun the `embark-collect' or `embark-export' that created this buffer." 3067 (interactive) 3068 (if embark--rerun-function 3069 (funcall embark--rerun-function) 3070 (user-error "No function to rerun collect or export found"))) 3071 3072 ;;;###autoload 3073 (defun embark-export () 3074 "Create a type-specific buffer to manage current candidates. 3075 The variable `embark-exporters-alist' controls how to make the 3076 buffer for each type of completion. 3077 3078 In Embark Export buffers `revert-buffer' is remapped to 3079 `embark-rerun-collect-or-export', which has slightly unusual 3080 behavior if the buffer was obtained by running `embark-export' 3081 from within a minibuffer completion session. In that case 3082 reverting just restarts the completion session, that is, the 3083 command that opened the minibuffer is run again and the 3084 minibuffer contents restored. You can then interact normally 3085 with the command, perhaps editing the minibuffer contents, and, 3086 if you wish, you can rerun `embark-export' to get an updated 3087 buffer." 3088 (interactive) 3089 (let* ((transformed (embark--maybe-transform-candidates)) 3090 (candidates (or (plist-get transformed :candidates) 3091 (user-error "No candidates for export"))) 3092 (type (plist-get transformed :type))) 3093 (let ((exporter (or (alist-get type embark-exporters-alist) 3094 (alist-get t embark-exporters-alist)))) 3095 (if (eq exporter 'embark-collect) 3096 (embark-collect) 3097 (let* ((after embark-after-export-hook) 3098 (cmd embark--command) 3099 (name (embark--descriptive-buffer-name 'export)) 3100 (rerun (embark--rerun-function #'embark-export)) 3101 (buffer (save-excursion 3102 (funcall exporter candidates) 3103 (rename-buffer name t) 3104 (current-buffer)))) 3105 (embark--quit-and-run 3106 (lambda () 3107 (pop-to-buffer buffer) 3108 (setq embark--rerun-function rerun) 3109 (use-local-map 3110 (make-composed-keymap 3111 '(keymap 3112 (remap keymap 3113 (revert-buffer . embark-rerun-collect-or-export))) 3114 (current-local-map))) 3115 (let ((embark-after-export-hook after) 3116 (embark--command cmd)) 3117 (run-hooks 'embark-after-export-hook))))))))) 3118 3119 (defmacro embark--export-rename (buffer title &rest body) 3120 "Run BODY and rename BUFFER to Embark export buffer with TITLE." 3121 (declare (indent 2)) 3122 (let ((saved (make-symbol "saved"))) 3123 `(let ((,saved (embark-rename-buffer 3124 ,buffer " *Embark Saved*" t))) 3125 ,@body 3126 (set-buffer (embark-rename-buffer 3127 ,buffer ,(format "*Embark Export %s*" title) t)) 3128 (when ,saved (embark-rename-buffer ,saved ,buffer))))) 3129 3130 (defun embark--export-customize (items type pred) 3131 "Create a customization buffer listing ITEMS. 3132 TYPE is the items type. 3133 PRED is a predicate function used to filter the items." 3134 (custom-buffer-create 3135 (cl-loop for item in items 3136 for sym = (intern-soft item) 3137 when (and sym (funcall pred sym)) collect `(,sym ,type)))) 3138 3139 (autoload 'apropos-parse-pattern "apropos") 3140 (autoload 'apropos-symbols-internal "apropos") 3141 (defun embark-export-apropos (symbols) 3142 "Create apropos buffer listing SYMBOLS." 3143 (embark--export-rename "*Apropos*" "Apropos" 3144 (apropos-parse-pattern "") ;; Initialize apropos pattern 3145 ;; HACK: Ensure that order of exported symbols is kept. 3146 (cl-letf (((symbol-function #'sort) (lambda (list _pred) (nreverse list)))) 3147 (apropos-symbols-internal 3148 (delq nil (mapcar #'intern-soft symbols)) 3149 (bound-and-true-p apropos-do-all))))) 3150 3151 (defun embark-export-customize-face (faces) 3152 "Create a customization buffer listing FACES." 3153 (embark--export-customize faces 'custom-face #'facep)) 3154 3155 (defun embark-export-customize-variable (variables) 3156 "Create a customization buffer listing VARIABLES." 3157 ;; The widget library serializes/deserializes the values. We advise 3158 ;; the serialization in order to avoid errors for nonserializable 3159 ;; variables. 3160 (cl-letf* ((ht (make-hash-table :test #'equal)) 3161 (orig-read (symbol-function #'read)) 3162 (orig-write (symbol-function 'widget-sexp-value-to-internal)) 3163 ((symbol-function #'read) 3164 (lambda (&optional str) 3165 (condition-case nil 3166 (funcall orig-read str) 3167 (error (gethash str ht))))) 3168 ((symbol-function 'widget-sexp-value-to-internal) 3169 (lambda (widget val) 3170 (let ((str (funcall orig-write widget val))) 3171 (puthash str val ht) 3172 str)))) 3173 (embark--export-customize variables 'custom-variable #'boundp))) 3174 3175 (defun embark-export-ibuffer (buffers) 3176 "Create an ibuffer buffer listing BUFFERS." 3177 (ibuffer t "*Embark Export Ibuffer*" 3178 `((predicate . (member (buffer-name) ',buffers))))) 3179 3180 (autoload 'dired-check-switches "dired") 3181 (declare-function dired-unadvertise "dired") 3182 (defvar dired-directory) 3183 3184 (defun embark-export-dired (files) 3185 "Create a Dired buffer listing FILES." 3186 (setq files (mapcar #'directory-file-name 3187 (cl-remove-if-not #'file-exists-p files))) 3188 (when (dired-check-switches dired-listing-switches "A" "almost-all") 3189 (setq files (cl-remove-if 3190 (lambda (path) 3191 (let ((file (file-name-nondirectory path))) 3192 (or (string= file ".") (string= file "..")))) 3193 files))) 3194 (let* ((dir (or (file-name-directory (try-completion "" files)) "")) 3195 (buf (dired-noselect 3196 (cons (expand-file-name dir) 3197 (mapcar (lambda (file) (string-remove-prefix dir file)) 3198 files))))) 3199 ;; unadvertise this buffer to avoid reuse 3200 (with-current-buffer buf 3201 (dired-unadvertise (car dired-directory)) ; avoid reuse of this buffer 3202 (rename-buffer (format "*Embark Export Dired %s*" default-directory))) 3203 (pop-to-buffer buf))) 3204 3205 (autoload 'package-menu-mode "package") 3206 (autoload 'package-menu--generate "package") 3207 3208 (defun embark-export-list-packages (packages) 3209 "Create a package menu mode buffer listing PACKAGES." 3210 (let ((buf (generate-new-buffer "*Embark Export Packages*"))) 3211 (with-current-buffer buf 3212 (package-menu-mode) 3213 (package-menu--generate nil (mapcar #'intern packages))) 3214 (pop-to-buffer buf))) 3215 3216 (defvar bookmark-alist) 3217 3218 (defun embark-export-bookmarks (bookmarks) 3219 "Create a `bookmark-bmenu-mode' buffer listing BOOKMARKS." 3220 (embark--export-rename "*Bookmark List*" "Bookmarks" 3221 (let ((bookmark-alist 3222 (cl-remove-if-not 3223 (lambda (bmark) 3224 (member (car bmark) bookmarks)) 3225 bookmark-alist))) 3226 (bookmark-bmenu-list)))) 3227 3228 ;;; Multiple target selection 3229 3230 (defface embark-selected '((t (:inherit match))) 3231 "Face for selected candidates.") 3232 3233 (defvar-local embark--selection nil 3234 "Buffer local list of selected targets. 3235 Add or remove elements to this list using the `embark-select' 3236 action.") 3237 3238 (cl-defun embark--select 3239 (&key orig-target orig-type bounds &allow-other-keys) 3240 "Add or remove ORIG-TARGET of given ORIG-TYPE to the selection. 3241 If BOUNDS are given, also highlight the target when selecting it." 3242 (cl-flet ((multi-type (x) (car (get-text-property 0 'multi-category x)))) 3243 (if-let* ((existing (seq-find 3244 (pcase-lambda (`(,cand . ,ov)) 3245 (and 3246 (equal cand orig-target) 3247 (if (and bounds ov) 3248 (and (= (car bounds) (overlay-start ov)) 3249 (= (cdr bounds) (overlay-end ov))) 3250 (let ((cand-type (multi-type cand))) 3251 (or (eq cand-type orig-type) 3252 (eq cand-type (multi-type orig-target))))))) 3253 embark--selection))) 3254 (progn 3255 (when (cdr existing) (delete-overlay (cdr existing))) 3256 (setq embark--selection (delq existing embark--selection))) 3257 (let ((target (copy-sequence orig-target)) overlay) 3258 (when bounds 3259 (setq overlay (make-overlay (car bounds) (cdr bounds))) 3260 (overlay-put overlay 'face 'embark-selected) 3261 (overlay-put overlay 'priority 1001)) 3262 (add-text-properties 0 (length orig-target) 3263 `(multi-category ,(cons orig-type orig-target)) 3264 target) 3265 (push (cons target overlay) embark--selection))))) 3266 3267 (defalias 'embark-select #'ignore 3268 "Add or remove the target from the current buffer's selection. 3269 You can act on all selected targets at once with `embark-act-all'.") 3270 3271 (defun embark-selected-candidates () 3272 "Return currently selected candidates in the buffer." 3273 (when embark--selection 3274 (cl-flet ((unwrap (x) (get-text-property 0 'multi-category x))) 3275 (let* ((first-type (car (unwrap (caar embark--selection)))) 3276 (same (cl-every (lambda (item) 3277 (eq (car (unwrap (car item))) first-type)) 3278 embark--selection)) 3279 (extract (if same 3280 (pcase-lambda (`(,cand . ,overlay)) 3281 (cons (cdr (unwrap cand)) overlay)) 3282 #'identity))) 3283 (cons 3284 (if same first-type 'multi-category) 3285 (nreverse 3286 (mapcar 3287 (lambda (item) 3288 (pcase-let ((`(,cand . ,ov) (funcall extract item))) 3289 (if ov `(,cand ,(overlay-start ov) . ,(overlay-end ov)) cand))) 3290 embark--selection))))))) 3291 3292 ;;; Integration with external packages, mostly completion UIs 3293 3294 ;; marginalia 3295 3296 ;; Ensure that the Marginalia cache is reset, such that 3297 ;; `embark-toggle-variable-value' updates the display (See #540). 3298 (with-eval-after-load 'marginalia 3299 (push 'marginalia--cache-reset (alist-get :always embark-post-action-hooks))) 3300 3301 ;; vertico 3302 3303 (declare-function vertico--candidate "ext:vertico") 3304 (declare-function vertico--update "ext:vertico") 3305 (declare-function vertico--remove-face "ext:vertico") 3306 (defvar vertico--input) 3307 (defvar vertico--candidates) 3308 (defvar vertico--base) 3309 3310 (defun embark--vertico-selected () 3311 "Target the currently selected item in Vertico. 3312 Return the category metadatum as the type of the target." 3313 (when vertico--input 3314 ;; Force candidate computation, if candidates are not yet available. 3315 (vertico--update) 3316 (cons (completion-metadata-get (embark--metadata) 'category) 3317 (vertico--candidate)))) 3318 3319 (defun embark--vertico-candidates () 3320 "Collect the current Vertico candidates. 3321 Return the category metadatum as the type of the candidates." 3322 (when vertico--input 3323 ;; Force candidate computation, if candidates are not yet available. 3324 (vertico--update) 3325 (cons (completion-metadata-get (embark--metadata) 'category) 3326 vertico--candidates))) 3327 3328 (defun embark--vertico-indicator () 3329 "Embark indicator highlighting the current Vertico candidate." 3330 (let ((fr face-remapping-alist)) 3331 (lambda (&optional keymap _targets _prefix) 3332 (when vertico--input 3333 (setq-local face-remapping-alist 3334 (if keymap 3335 (cons '(vertico-current . embark-target) fr) 3336 fr)))))) 3337 3338 (with-eval-after-load 'vertico 3339 (cl-defmethod vertico--format-candidate 3340 :around (cand prefix suffix index start &context (embark--selection cons)) 3341 (when (cl-find (concat vertico--base (nth index vertico--candidates)) 3342 embark--selection 3343 :test #'equal :key #'car) 3344 (setq cand (copy-sequence cand)) 3345 (add-face-text-property 0 (length cand) 'embark-selected t cand)) 3346 (cl-call-next-method cand prefix suffix index start)) 3347 (add-hook 'embark-indicators #'embark--vertico-indicator) 3348 (add-hook 'embark-target-finders #'embark--vertico-selected) 3349 (add-hook 'embark-candidate-collectors #'embark--vertico-candidates) 3350 (remove-hook 'embark-candidate-collectors #'embark-selected-candidates) 3351 (add-hook 'embark-candidate-collectors #'embark-selected-candidates)) 3352 3353 ;; ivy 3354 3355 (declare-function ivy--expand-file-name "ext:ivy") 3356 (declare-function ivy-state-current "ext:ivy") 3357 (defvar ivy-text) 3358 (defvar ivy-last) 3359 (defvar ivy--old-cands) ; this stores the current candidates :) 3360 (defvar ivy--length) 3361 3362 (defun embark--ivy-selected () 3363 "Target the currently selected item in Ivy. 3364 Return the category metadatum as the type of the target." 3365 ;; my favorite way of detecting Ivy 3366 (when (memq 'ivy--queue-exhibit post-command-hook) 3367 (cons 3368 (completion-metadata-get (embark--metadata) 'category) 3369 (ivy--expand-file-name 3370 (if (and (> ivy--length 0) 3371 (stringp (ivy-state-current ivy-last))) 3372 (ivy-state-current ivy-last) 3373 ivy-text))))) 3374 3375 (defun embark--ivy-candidates () 3376 "Return all current Ivy candidates." 3377 ;; my favorite way of detecting Ivy 3378 (when (memq 'ivy--queue-exhibit post-command-hook) 3379 (cons 3380 ;; swiper-isearch uses swiper-isearch-function as a completion 3381 ;; table, but it doesn't understand metadata queries 3382 (ignore-errors 3383 (completion-metadata-get (embark--metadata) 'category)) 3384 ivy--old-cands))) 3385 3386 (with-eval-after-load 'ivy 3387 (add-hook 'embark-target-finders #'embark--ivy-selected) 3388 (add-hook 'embark-candidate-collectors #'embark--ivy-candidates) 3389 (remove-hook 'embark-candidate-collectors #'embark-selected-candidates) 3390 (add-hook 'embark-candidate-collectors #'embark-selected-candidates)) 3391 3392 ;;; Custom actions 3393 3394 (defvar embark-separator-history nil 3395 "Input history for the separators used by some embark commands. 3396 The commands that prompt for a string separator are 3397 `embark-insert' and `embark-copy-as-kill'.") 3398 3399 (defun embark-keymap-help () 3400 "Prompt for an action to perform or command to become and run it." 3401 (interactive) 3402 (user-error "Not meant to be called directly")) 3403 3404 (defun embark-toggle-quit () 3405 "Toggle whether the following action quits the minibuffer." 3406 (interactive) 3407 (when (minibufferp) 3408 (setq embark--toggle-quit (not embark--toggle-quit)) 3409 (if (consp embark-quit-after-action) 3410 (message "Will %sobey embark-quit-after-action." 3411 (if embark--toggle-quit "dis" "")) 3412 (message 3413 "Will %squit minibuffer after action" 3414 (if (eq embark--toggle-quit embark-quit-after-action) "not " ""))))) 3415 3416 (defun embark--separator (strings) 3417 "Return a separator to join the STRINGS together. 3418 With a prefix argument, prompt the user (unless STRINGS has 0 or 3419 1 elements, in which case a separator is not needed)." 3420 (if (and current-prefix-arg (cdr strings)) 3421 (read-string "Separator: " nil 'embark-separator-history) 3422 "\n")) 3423 3424 (defun embark-copy-as-kill (strings) 3425 "Join STRINGS and save on the `kill-ring'. 3426 With a prefix argument, prompt for the separator to join the 3427 STRINGS, which defaults to a newline." 3428 (kill-new (string-join strings (embark--separator strings)))) 3429 3430 (defun embark-insert (strings) 3431 "Join STRINGS and insert the result at point. 3432 With a prefix argument, prompt for the separator to join the 3433 STRINGS, which defaults to a newline. 3434 3435 Some whitespace is also inserted if necessary to avoid having the 3436 inserted string blend into the existing buffer text. More 3437 precisely: 3438 3439 1. If the inserted string does not contain newlines, a space may 3440 be added before or after it as needed to avoid inserting a word 3441 constituent character next to an existing word constituent. 3442 3443 2. For a multiline inserted string, newlines may be added before 3444 or after as needed to ensure the inserted string is on lines of 3445 its own." 3446 (let ((multiline (seq-some (lambda (s) (string-match-p "\n" s)) strings)) 3447 (separator (embark--separator strings))) 3448 (cl-labels ((maybe-space () 3449 (and (looking-at "\\w") (looking-back "\\w" 1) 3450 (insert " "))) 3451 (maybe-newline () 3452 (or (looking-back "^[ \t]*" 40) (looking-at "\n\n") 3453 (newline-and-indent))) 3454 (maybe-whitespace () 3455 (if multiline (maybe-newline) (maybe-space))) 3456 (ins-string () 3457 (let ((start (point))) 3458 (insert (string-join strings separator)) 3459 (save-excursion (goto-char start) (maybe-whitespace)) 3460 (when (looking-back "\n" 1) (delete-char -1)) 3461 (save-excursion (maybe-whitespace))))) 3462 (if buffer-read-only 3463 (with-selected-window (other-window-for-scrolling) 3464 (ins-string)) 3465 (ins-string))))) 3466 3467 ;; For Emacs 28 dired-jump will be moved to dired.el, but it seems 3468 ;; that since it already has an autoload in Emacs 28, this next 3469 ;; autoload is ignored. 3470 (autoload 'dired-jump "dired-x" nil t) 3471 3472 (defun embark-dired-jump (file &optional other-window) 3473 "Open Dired buffer in directory containing FILE and move to its line. 3474 When called with a prefix argument OTHER-WINDOW, open Dired in other window." 3475 (interactive "fJump to Dired file: \nP") 3476 (dired-jump other-window file)) 3477 3478 (defun embark--read-from-history (prompt candidates &optional category) 3479 "Read with completion from list of history CANDIDATES of CATEGORY. 3480 Sorting and history are disabled. PROMPT is the prompt message." 3481 (completing-read prompt 3482 (embark--with-category category candidates) 3483 nil t nil t)) 3484 3485 (defun embark-kill-ring-remove (text) 3486 "Remove TEXT from `kill-ring'." 3487 (interactive (list (embark--read-from-history 3488 "Remove from kill-ring: " kill-ring 'kill-ring))) 3489 (embark-history-remove text) 3490 (setq kill-ring (delete text kill-ring))) 3491 3492 (defvar recentf-list) 3493 (defun embark-recentf-remove (file) 3494 "Remove FILE from the list of recent files." 3495 (interactive (list (embark--read-from-history 3496 "Remove recent file: " recentf-list 'file))) 3497 (embark-history-remove (expand-file-name file)) 3498 (embark-history-remove (abbreviate-file-name file)) 3499 (when (and (boundp 'recentf-list) (fboundp 'recentf-expand-file-name)) 3500 (setq recentf-list (delete (recentf-expand-file-name file) recentf-list)))) 3501 3502 (defun embark-history-remove (str) 3503 "Remove STR from `minibuffer-history-variable'. 3504 Many completion UIs sort by history position. This command can be used 3505 to remove entries from the history, such that they are not sorted closer 3506 to the top." 3507 (interactive (list (embark--read-from-history 3508 "Remove history item: " 3509 (if (eq minibuffer-history-variable t) 3510 (user-error "No minibuffer history") 3511 (symbol-value minibuffer-history-variable))))) 3512 (unless (eq minibuffer-history-variable t) 3513 (set minibuffer-history-variable 3514 (delete str (symbol-value minibuffer-history-variable))))) 3515 3516 (defvar xref-backend-functions) 3517 3518 (defun embark-find-definition (symbol) 3519 "Find definition of Emacs Lisp SYMBOL." 3520 (interactive "sSymbol: ") 3521 (let ((xref-backend-functions (lambda () 'elisp))) 3522 (xref-find-definitions symbol))) 3523 3524 (defun embark-info-lookup-symbol (symbol) 3525 "Display the definition of SYMBOL, from the Elisp manual." 3526 (interactive "SSymbol: ") 3527 (info-lookup-symbol symbol 'emacs-lisp-mode)) 3528 3529 (defun embark-rename-buffer (buffer newname &optional unique) 3530 "Rename BUFFER to NEWNAME, optionally making it UNIQUE. 3531 Interactively, you can set UNIQUE with a prefix argument. 3532 Returns the new name actually used." 3533 (interactive "bBuffer: \nBRename %s to: \nP") 3534 (when-let ((buf (get-buffer buffer))) 3535 (with-current-buffer buf 3536 (rename-buffer newname unique)))) 3537 3538 (defun embark--package-url (pkg) 3539 "Return homepage for package PKG." 3540 (when-let (desc (embark--package-desc pkg)) 3541 (alist-get :url (package-desc-extras desc)))) 3542 3543 (defun embark--prompt-for-package () 3544 "Prompt user for a package name." 3545 ;; this code is taken from the interactive spec of describe-package 3546 (unless package--initialized 3547 (package-initialize t)) 3548 (intern 3549 (completing-read "Package: " 3550 (append (mapcar #'car package-alist) 3551 (mapcar #'car package-archive-contents) 3552 (mapcar #'car package--builtins))))) 3553 3554 (defun embark-browse-package-url (pkg) 3555 "Open homepage for package PKG with `browse-url'." 3556 (interactive (list (embark--prompt-for-package))) 3557 (if-let ((url (embark--package-url pkg))) 3558 (browse-url url) 3559 (user-error "No homepage found for `%s'" pkg))) 3560 3561 (defun embark-save-package-url (pkg) 3562 "Save URL of homepage for package PKG on the `kill-ring'." 3563 (interactive (list (embark--prompt-for-package))) 3564 (if-let ((url (embark--package-url pkg))) 3565 (kill-new url) 3566 (user-error "No homepage found for `%s'" pkg))) 3567 3568 (defun embark-save-variable-value (var) 3569 "Save value of VAR in the `kill-ring'." 3570 (interactive "SVariable: ") 3571 (kill-new (string-trim (pp-to-string (symbol-value var))))) 3572 3573 (defun embark-insert-variable-value (var) 3574 "Insert value of VAR." 3575 (interactive "SVariable: ") 3576 (insert (string-trim (pp-to-string (symbol-value var))))) 3577 3578 (defun embark-toggle-variable (var &optional local) 3579 "Toggle value of boolean variable VAR. 3580 If prefix LOCAL is non-nil make variable local." 3581 (interactive "SVariable: \nP") 3582 (let ((val (symbol-value var))) 3583 (unless (memq val '(nil t)) 3584 (user-error "Not a boolean variable")) 3585 (when local 3586 (make-local-variable var)) 3587 (funcall (or (get var 'custom-set) 'set) var (not val)))) 3588 3589 (defun embark-insert-relative-path (file) 3590 "Insert relative path to FILE. 3591 The insert path is relative to `default-directory'." 3592 (interactive "FFile: ") 3593 (insert (file-relative-name (substitute-in-file-name file)))) 3594 3595 (defun embark-save-relative-path (file) 3596 "Save the relative path to FILE in the kill ring. 3597 The insert path is relative to `default-directory'." 3598 (interactive "FFile: ") 3599 (kill-new (file-relative-name (substitute-in-file-name file)))) 3600 3601 (defun embark-shell-command-on-buffer (buffer command &optional replace) 3602 "Run shell COMMAND on contents of BUFFER. 3603 Called with \\[universal-argument], replace contents of buffer 3604 with command output. For replacement behavior see 3605 `shell-command-dont-erase-buffer' setting." 3606 (interactive 3607 (list 3608 (read-buffer "Buffer: " nil t) 3609 (read-shell-command "Shell command: ") 3610 current-prefix-arg)) 3611 (with-current-buffer buffer 3612 (shell-command-on-region (point-min) (point-max) 3613 command 3614 (and replace (current-buffer))))) 3615 3616 (defun embark-open-externally (file) 3617 "Open FILE using system's default application." 3618 (interactive "fOpen: ") 3619 (if (and (eq system-type 'windows-nt) 3620 (fboundp 'w32-shell-execute)) 3621 (w32-shell-execute "open" file) 3622 (call-process (pcase system-type 3623 ('darwin "open") 3624 ('cygwin "cygstart") 3625 (_ "xdg-open")) 3626 nil 0 nil 3627 (expand-file-name file)))) 3628 3629 (defun embark-bury-buffer (buf) 3630 "Bury buffer BUF." 3631 (interactive "bBuffer: ") 3632 (if-let (win (get-buffer-window buf)) 3633 (with-selected-window win 3634 (bury-buffer)) 3635 (bury-buffer))) 3636 3637 (defun embark-kill-buffer-and-window (buf) 3638 "Kill buffer BUF and delete its window." 3639 (interactive "bBuffer: ") 3640 (when-let (buf (get-buffer buf)) 3641 (if-let (win (get-buffer-window buf)) 3642 (with-selected-window win 3643 (kill-buffer-and-window)) 3644 (kill-buffer buf)))) 3645 3646 (defun embark-save-unicode-character (char) 3647 "Save Unicode character CHAR to kill ring." 3648 (interactive 3649 (list (read-char-by-name "Insert character (Unicode name or hex): "))) 3650 (kill-new (format "%c" char))) 3651 3652 (defun embark-isearch () 3653 "Prompt for string in the minibuffer and start isearch. 3654 Unlike isearch, this command reads the string from the 3655 minibuffer, which means it can be used as an Embark action." 3656 (interactive) 3657 (isearch-mode t) 3658 (isearch-edit-string)) 3659 3660 (defun embark-toggle-highlight () 3661 "Toggle symbol highlighting using `highlight-symbol-at-point'." 3662 (interactive) 3663 (let ((regexp (find-tag-default-as-symbol-regexp)) 3664 (highlighted (cl-find-if #'boundp 3665 '(hi-lock-interactive-lighters 3666 hi-lock-interactive-patterns)))) 3667 (if (and highlighted (assoc regexp (symbol-value highlighted))) 3668 (unhighlight-regexp regexp) 3669 (highlight-symbol-at-point)))) 3670 3671 (defun embark-next-symbol () 3672 "Jump to next occurrence of symbol at point. 3673 The search respects symbol boundaries." 3674 (interactive) 3675 (if-let ((symbol (thing-at-point 'symbol))) 3676 (let ((regexp (format "\\_<%s\\_>" (regexp-quote symbol)))) 3677 (when (looking-at regexp) 3678 (forward-symbol 1)) 3679 (unless (re-search-forward regexp nil t) 3680 (user-error "Symbol `%s' not found" symbol))) 3681 (user-error "No symbol at point"))) 3682 3683 (defun embark-previous-symbol () 3684 "Jump to previous occurrence of symbol at point. 3685 The search respects symbol boundaries." 3686 (interactive) 3687 (if-let ((symbol (thing-at-point 'symbol))) 3688 (let ((regexp (format "\\_<%s\\_>" (regexp-quote symbol)))) 3689 (when (looking-back regexp (- (point) (length symbol))) 3690 (forward-symbol -1)) 3691 (unless (re-search-backward regexp nil t) 3692 (user-error "Symbol `%s' not found" symbol))) 3693 (user-error "No symbol at point"))) 3694 3695 (defun embark-compose-mail (address) 3696 "Compose email to ADDRESS." 3697 ;; The only reason we cannot use compose-mail directly is its 3698 ;; interactive specification, which just supllies nil for the 3699 ;; address (and several other arguments). 3700 (interactive "sTo: ") 3701 (compose-mail address)) 3702 3703 (autoload 'pp-display-expression "pp") 3704 3705 (defun embark-pp-eval-defun (edebug) 3706 "Run `eval-defun' and pretty print the result. 3707 With a prefix argument EDEBUG, instrument the code for debugging." 3708 (interactive "P") 3709 (cl-letf (((symbol-function #'eval-expression-print-format) 3710 (lambda (result) 3711 (pp-display-expression result "*Pp Eval Output*")))) 3712 (eval-defun edebug))) 3713 3714 (defun embark-eval-replace () 3715 "Evaluate region and replace with evaluated result." 3716 (interactive) 3717 (let ((beg (region-beginning)) 3718 (end (region-end))) 3719 (save-excursion 3720 (goto-char end) 3721 (insert (prin1-to-string 3722 (eval (read (buffer-substring beg end)) lexical-binding))) 3723 (delete-region beg end)))) 3724 3725 (when (< emacs-major-version 29) 3726 (defun embark-elp-restore-package (prefix) 3727 "Remove instrumentation from functions with names starting with PREFIX." 3728 (interactive "SPrefix: ") 3729 (when (fboundp 'elp-restore-list) 3730 (elp-restore-list 3731 (mapcar #'intern 3732 (all-completions (symbol-name prefix) 3733 obarray 'elp-profilable-p)))))) 3734 3735 (defmacro embark--define-hash (algorithm) 3736 "Define command which computes hash from a string. 3737 ALGORITHM is the hash algorithm symbol understood by `secure-hash'." 3738 `(defun ,(intern (format "embark-hash-%s" algorithm)) (str) 3739 ,(format "Compute %s hash of STR and store it in the kill ring." algorithm) 3740 (interactive "sString: ") 3741 (let ((hash (secure-hash ',algorithm str))) 3742 (kill-new hash) 3743 (message "%s: %s" ',algorithm hash)))) 3744 3745 (embark--define-hash md5) 3746 (embark--define-hash sha1) 3747 (embark--define-hash sha224) 3748 (embark--define-hash sha256) 3749 (embark--define-hash sha384) 3750 (embark--define-hash sha512) 3751 3752 (defun embark-encode-url (start end) 3753 "Properly URI-encode the region between START and END in current buffer." 3754 (interactive "r") 3755 (let ((encoded (url-encode-url (buffer-substring-no-properties start end)))) 3756 (delete-region start end) 3757 (insert encoded))) 3758 3759 (defun embark-decode-url (start end) 3760 "Decode the URI-encoded region between START and END in current buffer." 3761 (interactive "r") 3762 (let ((decoded (url-unhex-string (buffer-substring-no-properties start end)))) 3763 (delete-region start end) 3764 (insert decoded))) 3765 3766 (defvar epa-replace-original-text) 3767 (defun embark-epa-decrypt-region (start end) 3768 "Decrypt region between START and END." 3769 (interactive "r") 3770 (let ((epa-replace-original-text t)) 3771 (epa-decrypt-region start end))) 3772 3773 (defvar eww-download-directory) 3774 (autoload 'eww-download-callback "eww") 3775 3776 (defun embark-download-url (url) 3777 "Download URL to `eww-download-directory'." 3778 (interactive "sDownload URL: ") 3779 (let ((dir eww-download-directory)) 3780 (when (functionp dir) (setq dir (funcall dir))) 3781 (access-file dir "Download failed") 3782 (url-retrieve 3783 url #'eww-download-callback 3784 (if (>= emacs-major-version 28) (list url dir) (list url))))) 3785 3786 ;;; Setup and pre-action hooks 3787 3788 (defun embark--restart (&rest _) 3789 "Restart current command with current input. 3790 Use this to refresh the list of candidates for commands that do 3791 not handle that themselves." 3792 (when (minibufferp) 3793 (embark--become-command embark--command (minibuffer-contents)))) 3794 3795 (defun embark--shell-prep (&rest _) 3796 "Prepare target for use as argument for a shell command. 3797 This quotes the spaces, inserts an extra space at the beginning 3798 and leaves the point to the left of it." 3799 (let ((contents (minibuffer-contents))) 3800 (delete-minibuffer-contents) 3801 (insert " " (shell-quote-wildcard-pattern contents)) 3802 (goto-char (minibuffer-prompt-end)))) 3803 3804 (defun embark--force-complete (&rest _) 3805 "Select first minibuffer completion candidate matching target." 3806 (minibuffer-force-complete)) 3807 3808 (cl-defun embark--eval-prep (&key type &allow-other-keys) 3809 "If target's TYPE is: variable, skip edit; function, wrap in parens." 3810 (when (memq type '(command function)) 3811 (embark--allow-edit) 3812 (goto-char (minibuffer-prompt-end)) 3813 (insert "(") 3814 (goto-char (point-max)) 3815 (insert ")") 3816 (backward-char))) 3817 3818 (cl-defun embark--beginning-of-target (&key bounds &allow-other-keys) 3819 "Go to beginning of the target BOUNDS." 3820 (when (number-or-marker-p bounds) 3821 (goto-char (car bounds)))) 3822 3823 (cl-defun embark--end-of-target (&key bounds &allow-other-keys) 3824 "Go to end of the target BOUNDS." 3825 (when (number-or-marker-p bounds) 3826 (goto-char (cdr bounds)))) 3827 3828 (cl-defun embark--mark-target (&rest rest &key run bounds &allow-other-keys) 3829 "Mark the target if its BOUNDS are known. 3830 After marking the target, this calls RUN with the REST of its arguments." 3831 (cond 3832 ((and bounds run) 3833 (save-mark-and-excursion 3834 (set-mark (cdr bounds)) 3835 (goto-char (car bounds)) 3836 (apply run :bounds bounds rest))) 3837 (bounds ;; used as pre- or post-action hook 3838 (set-mark (cdr bounds)) 3839 (goto-char (car bounds))) 3840 (run (apply run rest)))) 3841 3842 (cl-defun embark--unmark-target (&rest _) 3843 "Deactivate the region target." 3844 (deactivate-mark t)) 3845 3846 (cl-defun embark--narrow-to-target 3847 (&rest rest &key run bounds &allow-other-keys) 3848 "Narrow buffer to target if its BOUNDS are known. 3849 Intended for use as an Embark around-action hook. This function 3850 runs RUN with the buffer narrowed to given BOUNDS passing along 3851 the REST of the arguments." 3852 (if bounds 3853 (save-excursion 3854 (save-restriction 3855 (narrow-to-region (car bounds) (cdr bounds)) 3856 (goto-char (car bounds)) 3857 (apply run :bounds bounds rest))) 3858 (apply run rest))) 3859 3860 (defun embark--allow-edit (&rest _) 3861 "Allow editing the target." 3862 (remove-hook 'post-command-hook #'exit-minibuffer t) 3863 (remove-hook 'post-command-hook 'ivy-immediate-done t)) 3864 3865 (defun embark--ignore-target (&rest _) 3866 "Ignore the target." 3867 (let ((contents 3868 (get-text-property (minibuffer-prompt-end) 'embark--initial-input))) 3869 (delete-minibuffer-contents) 3870 (when contents (insert contents))) 3871 (embark--allow-edit)) 3872 3873 (autoload 'xref-push-marker-stack "xref") 3874 (defun embark--xref-push-marker (&rest _) 3875 "Push a marker onto the xref marker stack." 3876 (xref-push-marker-stack)) 3877 3878 (cl-defun embark--confirm (&key action target &allow-other-keys) 3879 "Ask for confirmation before running the ACTION on the TARGET." 3880 (unless (y-or-n-p (format "Run %s on %s? " action target)) 3881 (user-error "Canceled"))) 3882 3883 (defun embark--associated-directory (target type) 3884 "Return directory associated to TARGET of given TYPE. 3885 The supported values of TYPE are file, buffer, bookmark and 3886 library, which have an obvious notion of associated directory." 3887 (pcase type 3888 ('file 3889 (file-name-directory target)) 3890 ('buffer 3891 (buffer-local-value 'default-directory (get-buffer target))) 3892 ('bookmark 3893 (file-name-directory (bookmark-location target))) 3894 ('library 3895 (file-name-directory (locate-library target))))) 3896 3897 (autoload 'bookmark-location "bookmark") 3898 (cl-defun embark--cd (&rest rest &key run target type &allow-other-keys) 3899 "Run action with `default-directory' set to the directory of TARGET. 3900 The supported values of TYPE are file, buffer, bookmark and 3901 library, which have an obvious notion of associated directory. 3902 The REST of the arguments are also passed to RUN." 3903 (let ((default-directory 3904 (or (embark--associated-directory target type) default-directory))) 3905 (apply run :target target :type type rest))) 3906 3907 (cl-defun embark--save-excursion (&rest rest &key run &allow-other-keys) 3908 "Run action without moving point. 3909 This simply calls RUN with the REST of its arguments inside 3910 `save-excursion'." 3911 (save-excursion (apply run rest))) 3912 3913 (defun embark--universal-argument (&rest _) 3914 "Run action with a universal prefix argument." 3915 (setq prefix-arg '(4))) 3916 3917 ;;; keymaps 3918 3919 (defvar-keymap embark-meta-map 3920 :doc "Keymap for non-action Embark functions." 3921 "-" #'negative-argument 3922 "0" #'digit-argument 3923 "1" #'digit-argument 3924 "2" #'digit-argument 3925 "3" #'digit-argument 3926 "4" #'digit-argument 3927 "5" #'digit-argument 3928 "6" #'digit-argument 3929 "7" #'digit-argument 3930 "8" #'digit-argument 3931 "9" #'digit-argument) 3932 3933 (defvar-keymap embark-general-map 3934 :doc "Keymap for Embark general actions." 3935 :parent embark-meta-map 3936 "i" #'embark-insert 3937 "w" #'embark-copy-as-kill 3938 "q" #'embark-toggle-quit 3939 "E" #'embark-export 3940 "S" #'embark-collect 3941 "L" #'embark-live 3942 "B" #'embark-become 3943 "A" #'embark-act-all 3944 "C-s" #'embark-isearch 3945 "C-SPC" #'mark 3946 "DEL" #'delete-region 3947 "SPC" #'embark-select) 3948 3949 (defvar-keymap embark-encode-map 3950 :doc "Keymap for Embark region encoding actions." 3951 "r" #'rot13-region 3952 "." #'morse-region 3953 "-" #'unmorse-region 3954 "s" #'studlify-region 3955 "m" #'embark-hash-md5 3956 "1" #'embark-hash-sha1 3957 "2" #'embark-hash-sha256 3958 "3" #'embark-hash-sha384 3959 "4" #'embark-hash-sha224 3960 "5" #'embark-hash-sha512 3961 "f" #'format-encode-region 3962 "F" #'format-decode-region 3963 "b" #'base64-encode-region 3964 "B" #'base64-decode-region 3965 "u" #'embark-encode-url 3966 "U" #'embark-decode-url 3967 "c" #'epa-encrypt-region 3968 "C" #'embark-epa-decrypt-region) 3969 3970 (fset 'embark-encode-map embark-encode-map) 3971 3972 (defvar-keymap embark-sort-map 3973 :doc "Keymap for Embark actions that sort the region" 3974 "l" #'sort-lines 3975 "P" #'sort-pages 3976 "f" #'sort-fields 3977 "c" #'sort-columns 3978 "p" #'sort-paragraphs 3979 "r" #'sort-regexp-fields 3980 "n" #'sort-numeric-fields) 3981 3982 (fset 'embark-sort-map embark-sort-map) 3983 3984 ;; these will have autoloads in Emacs 28 3985 (autoload 'calc-grab-sum-down "calc" nil t) 3986 (autoload 'calc-grab-sum-across "calc" nil t) 3987 3988 ;; this has had an autoload cookie since at least Emacs 26 3989 ;; but that autoload doesn't seem to work for me 3990 (autoload 'org-table-convert-region "org-table" nil t) 3991 3992 (defvar-keymap embark-region-map 3993 :doc "Keymap for Embark actions on the active region." 3994 :parent embark-general-map 3995 "u" #'upcase-region 3996 "l" #'downcase-region 3997 "c" #'capitalize-region 3998 "|" #'shell-command-on-region 3999 "e" #'eval-region 4000 "<" #'embark-eval-replace 4001 "a" #'align 4002 "A" #'align-regexp 4003 "i" #'indent-rigidly 4004 "I" #'embark-insert 4005 "TAB" #'indent-region 4006 "f" #'fill-region 4007 "p" #'fill-region-as-paragraph 4008 "$" #'ispell-region 4009 "=" #'count-words-region 4010 "F" #'whitespace-cleanup-region 4011 "t" #'transpose-regions 4012 "o" #'org-table-convert-region 4013 ";" #'comment-or-uncomment-region 4014 "W" #'write-region 4015 "+" #'append-to-file 4016 "m" #'apply-macro-to-region-lines 4017 "n" #'narrow-to-region 4018 "*" #'calc-grab-region 4019 ":" #'calc-grab-sum-down 4020 "_" #'calc-grab-sum-across 4021 "r" #'reverse-region 4022 "d" #'delete-duplicate-lines 4023 "b" #'browse-url-of-region 4024 "h" #'shr-render-region 4025 "'" #'expand-region-abbrevs 4026 "v" #'vc-region-history 4027 "R" #'repunctuate-sentences 4028 "s" 'embark-sort-map 4029 ">" 'embark-encode-map) 4030 4031 (defvar-keymap embark-vc-file-map 4032 :doc "Keymap for Embark VC file actions." 4033 "d" #'vc-delete-file 4034 "r" #'vc-rename-file 4035 "i" #'vc-ignore) 4036 4037 (fset 'embark-vc-file-map embark-vc-file-map) 4038 4039 (defvar-keymap embark-file-map 4040 :doc "Keymap for Embark file actions." 4041 :parent embark-general-map 4042 "RET" #'find-file 4043 "f" #'find-file 4044 "F" #'find-file-literally 4045 "o" #'find-file-other-window 4046 "d" #'delete-file 4047 "D" #'delete-directory 4048 "r" #'rename-file 4049 "c" #'copy-file 4050 "j" #'embark-dired-jump 4051 "!" #'shell-command 4052 "&" #'async-shell-command 4053 "$" #'eshell 4054 "<" #'insert-file 4055 "m" #'chmod 4056 "=" #'ediff-files 4057 "+" #'make-directory 4058 "\\" #'embark-recentf-remove 4059 "I" #'embark-insert-relative-path 4060 "W" #'embark-save-relative-path 4061 "x" #'embark-open-externally 4062 "e" #'eww-open-file 4063 "l" #'load-file 4064 "b" #'byte-compile-file 4065 "R" #'byte-recompile-directory 4066 "v" 'embark-vc-file-map) 4067 4068 (defvar-keymap embark-kill-ring-map 4069 :doc "Keymap for `kill-ring' commands." 4070 :parent embark-general-map 4071 "\\" #'embark-kill-ring-remove) 4072 4073 (defvar-keymap embark-url-map 4074 :doc "Keymap for Embark url actions." 4075 :parent embark-general-map 4076 "RET" #'browse-url 4077 "b" #'browse-url 4078 "d" #'embark-download-url 4079 "e" #'eww) 4080 4081 (defvar-keymap embark-email-map 4082 :doc "Keymap for Embark email actions." 4083 :parent embark-general-map 4084 "RET" #'embark-compose-mail 4085 "c" #'embark-compose-mail) 4086 4087 (defvar-keymap embark-library-map 4088 :doc "Keymap for operations on Emacs Lisp libraries." 4089 :parent embark-general-map 4090 "RET" #'find-library 4091 "l" #'load-library 4092 "f" #'find-library 4093 "h" #'finder-commentary 4094 "a" #'apropos-library 4095 "L" #'locate-library 4096 "m" #'info-display-manual 4097 "$" #'eshell) 4098 4099 (defvar-keymap embark-buffer-map 4100 :doc "Keymap for Embark buffer actions." 4101 :parent embark-general-map 4102 "RET" #'switch-to-buffer 4103 "k" #'kill-buffer 4104 "b" #'switch-to-buffer 4105 "o" #'switch-to-buffer-other-window 4106 "z" #'embark-bury-buffer 4107 "K" #'embark-kill-buffer-and-window 4108 "r" #'embark-rename-buffer 4109 "=" #'ediff-buffers 4110 "|" #'embark-shell-command-on-buffer 4111 "<" #'insert-buffer 4112 "$" #'eshell) 4113 4114 (defvar-keymap embark-tab-map 4115 :doc "Keymap for actions for tab-bar tabs." 4116 :parent embark-general-map 4117 "RET" #'tab-bar-select-tab-by-name 4118 "s" #'tab-bar-select-tab-by-name 4119 "r" #'tab-bar-rename-tab-by-name 4120 "k" #'tab-bar-close-tab-by-name) 4121 4122 (defvar-keymap embark-identifier-map 4123 :doc "Keymap for Embark identifier actions." 4124 :parent embark-general-map 4125 "RET" #'xref-find-definitions 4126 "h" #'display-local-help 4127 "H" #'embark-toggle-highlight 4128 "d" #'xref-find-definitions 4129 "r" #'xref-find-references 4130 "a" #'xref-find-apropos 4131 "s" #'info-lookup-symbol 4132 "n" #'embark-next-symbol 4133 "p" #'embark-previous-symbol 4134 "'" #'expand-abbrev 4135 "$" #'ispell-word 4136 "o" #'occur) 4137 4138 (defvar-keymap embark-expression-map 4139 :doc "Keymap for Embark expression actions." 4140 :parent embark-general-map 4141 "RET" #'pp-eval-expression 4142 "e" #'pp-eval-expression 4143 "<" #'embark-eval-replace 4144 "m" #'pp-macroexpand-expression 4145 "TAB" #'indent-region 4146 "r" #'raise-sexp 4147 "t" #'transpose-sexps 4148 "k" #'kill-region 4149 "u" #'backward-up-list 4150 "n" #'forward-list 4151 "p" #'backward-list) 4152 4153 (defvar-keymap embark-defun-map 4154 :doc "Keymap for Embark defun actions." 4155 :parent embark-expression-map 4156 "RET" #'embark-pp-eval-defun 4157 "e" #'embark-pp-eval-defun 4158 "c" #'compile-defun 4159 "l" #'elint-defun 4160 "D" #'edebug-defun 4161 "o" #'checkdoc-defun 4162 "N" #'narrow-to-defun) 4163 4164 ;; Use quoted symbols to avoid byte-compiler warnings. 4165 (defvar-keymap embark-heading-map 4166 :doc "Keymap for Embark heading actions." 4167 :parent embark-general-map 4168 "RET" 'outline-show-subtree 4169 "TAB" 'outline-cycle ;; New in Emacs 28! 4170 "C-SPC" 'outline-mark-subtree 4171 "n" 'outline-next-visible-heading 4172 "p" 'outline-previous-visible-heading 4173 "f" 'outline-forward-same-level 4174 "b" 'outline-backward-same-level 4175 "^" 'outline-move-subtree-up 4176 "v" 'outline-move-subtree-down 4177 "u" 'outline-up-heading 4178 "s" 'outline-show-subtree 4179 "d" 'outline-hide-subtree 4180 ">" 'outline-demote 4181 "<" 'outline-promote) 4182 4183 (defvar-keymap embark-symbol-map 4184 :doc "Keymap for Embark symbol actions." 4185 :parent embark-identifier-map 4186 "RET" #'embark-find-definition 4187 "h" #'describe-symbol 4188 "s" #'embark-info-lookup-symbol 4189 "d" #'embark-find-definition 4190 "e" #'pp-eval-expression 4191 "a" #'apropos 4192 "\\" #'embark-history-remove) 4193 4194 (defvar-keymap embark-face-map 4195 :doc "Keymap for Embark face actions." 4196 :parent embark-symbol-map 4197 "h" #'describe-face 4198 "c" #'customize-face 4199 "+" #'make-face-bold 4200 "-" #'make-face-unbold 4201 "/" #'make-face-italic 4202 "|" #'make-face-unitalic 4203 "!" #'invert-face 4204 "f" #'set-face-foreground 4205 "b" #'set-face-background) 4206 4207 (defvar-keymap embark-variable-map 4208 :doc "Keymap for Embark variable actions." 4209 :parent embark-symbol-map 4210 "=" #'set-variable 4211 "c" #'customize-set-variable 4212 "u" #'customize-variable 4213 "v" #'embark-save-variable-value 4214 "<" #'embark-insert-variable-value 4215 "t" #'embark-toggle-variable) 4216 4217 (defvar-keymap embark-function-map 4218 :doc "Keymap for Embark function actions." 4219 :parent embark-symbol-map 4220 "m" #'elp-instrument-function ;; m=measure 4221 "M" 'elp-restore-function ;; quoted, not autoloaded 4222 "k" #'debug-on-entry ;; breaKpoint (running out of letters, really) 4223 "K" #'cancel-debug-on-entry 4224 "t" #'trace-function 4225 "T" 'untrace-function) ;; quoted, not autoloaded 4226 4227 (defvar-keymap embark-command-map 4228 :doc "Keymap for Embark command actions." 4229 :parent embark-function-map 4230 "x" #'execute-extended-command 4231 "I" #'Info-goto-emacs-command-node 4232 "b" #'where-is 4233 "g" #'global-set-key 4234 "l" #'local-set-key) 4235 4236 (defvar-keymap embark-package-map 4237 :doc "Keymap for Embark package actions." 4238 :parent embark-general-map 4239 "RET" #'describe-package 4240 "h" #'describe-package 4241 "i" #'package-install 4242 "I" #'embark-insert 4243 "d" #'package-delete 4244 "r" #'package-reinstall 4245 "u" #'embark-browse-package-url 4246 "W" #'embark-save-package-url 4247 "a" #'package-autoremove 4248 "g" #'package-refresh-contents 4249 "m" #'elp-instrument-package ;; m=measure 4250 "M" (if (fboundp 'embark-elp-restore-package) 4251 'embark-elp-restore-package 4252 'elp-restore-package)) 4253 4254 (defvar-keymap embark-bookmark-map 4255 :doc "Keymap for Embark bookmark actions." 4256 :parent embark-general-map 4257 "RET" #'bookmark-jump 4258 "s" #'bookmark-set 4259 "d" #'bookmark-delete 4260 "r" #'bookmark-rename 4261 "R" #'bookmark-relocate 4262 "l" #'bookmark-locate 4263 "<" #'bookmark-insert 4264 "j" #'bookmark-jump 4265 "o" #'bookmark-jump-other-window 4266 "f" #'bookmark-jump-other-frame 4267 "a" 'bookmark-show-annotation 4268 "e" 'bookmark-edit-annotation 4269 "$" #'eshell) 4270 4271 (defvar-keymap embark-unicode-name-map 4272 :doc "Keymap for Embark Unicode name actions." 4273 :parent embark-general-map 4274 "RET" #'insert-char 4275 "I" #'insert-char 4276 "W" #'embark-save-unicode-character) 4277 4278 (defvar-keymap embark-prose-map 4279 :doc "Keymap for Embark actions for dealing with prose." 4280 :parent embark-general-map 4281 "$" #'ispell-region 4282 "f" #'fill-region 4283 "u" #'upcase-region 4284 "l" #'downcase-region 4285 "c" #'capitalize-region 4286 "F" #'whitespace-cleanup-region 4287 "=" #'count-words-region) 4288 4289 (defvar-keymap embark-sentence-map 4290 :doc "Keymap for Embark actions for dealing with sentences." 4291 :parent embark-prose-map 4292 "t" #'transpose-sentences 4293 "n" #'forward-sentence 4294 "p" #'backward-sentence) 4295 4296 (defvar-keymap embark-paragraph-map 4297 :doc "Keymap for Embark actions for dealing with paragraphs." 4298 :parent embark-prose-map 4299 "t" #'transpose-paragraphs 4300 "n" #'forward-paragraph 4301 "p" #'backward-paragraph 4302 "R" #'repunctuate-sentences) 4303 4304 (defvar-keymap embark-become-help-map 4305 :doc "Keymap for Embark help actions." 4306 :parent embark-meta-map 4307 "V" #'apropos-variable 4308 "U" #'apropos-user-option 4309 "C" #'apropos-command 4310 "v" #'describe-variable 4311 "f" #'describe-function 4312 "s" #'describe-symbol 4313 "F" #'describe-face 4314 "p" #'describe-package 4315 "i" #'describe-input-method) 4316 4317 (autoload 'recentf-open-files "recentf" nil t) 4318 4319 (defvar-keymap embark-become-file+buffer-map 4320 :doc "Embark become keymap for files and buffers." 4321 :parent embark-meta-map 4322 "f" #'find-file 4323 "4 f" #'find-file-other-window 4324 "." #'find-file-at-point 4325 "p" #'project-find-file 4326 "r" #'recentf-open-files 4327 "b" #'switch-to-buffer 4328 "4 b" #'switch-to-buffer-other-window 4329 "l" #'locate 4330 "L" #'find-library 4331 "v" #'vc-dir) 4332 4333 (defvar-keymap embark-become-shell-command-map 4334 :doc "Embark become keymap for shell commands." 4335 :parent embark-meta-map 4336 "!" #'shell-command 4337 "&" #'async-shell-command 4338 "c" #'comint-run 4339 "t" #'term) 4340 4341 (defvar-keymap embark-become-match-map 4342 :doc "Embark become keymap for search." 4343 :parent embark-meta-map 4344 "o" #'occur 4345 "k" #'keep-lines 4346 "f" #'flush-lines 4347 "c" #'count-matches) 4348 4349 (provide 'embark) 4350 4351 ;; Check that embark-consult is installed. If Embark is used in 4352 ;; combination with Consult, you should install the integration package, 4353 ;; such that features like embark-export from consult-grep work as 4354 ;; expected. 4355 4356 (with-eval-after-load 'consult 4357 (unless (require 'embark-consult nil 'noerror) 4358 (warn "The package embark-consult should be installed if you use both Embark and Consult"))) 4359 4360 (with-eval-after-load 'org 4361 (require 'embark-org)) 4362 4363 ;;; embark.el ends here