README.org (55096B)
1 #+TITLE: Embark: Emacs Mini-Buffer Actions Rooted in Keymaps 2 #+OPTIONS: d:nil 3 #+EXPORT_FILE_NAME: embark.texi 4 #+TEXINFO_DIR_CATEGORY: Emacs misc features 5 #+TEXINFO_DIR_TITLE: Embark: (embark). 6 #+TEXINFO_DIR_DESC: Emacs Mini-Buffer Actions Rooted in Keymaps 7 8 #+html: <a href="http://elpa.gnu.org/packages/embark.html"><img alt="GNU ELPA" src="https://elpa.gnu.org/packages/embark.svg"/></a> 9 #+html: <a href="http://elpa.gnu.org/devel/embark.html"><img alt="GNU-devel ELPA" src="https://elpa.gnu.org/devel/embark.svg"/></a> 10 #+html: <a href="https://melpa.org/#/embark"><img alt="MELPA" src="https://melpa.org/packages/embark-badge.svg"/></a> 11 #+html: <a href="https://stable.melpa.org/#/embark"><img alt="MELPA Stable" src="https://stable.melpa.org/packages/embark-badge.svg"/></a> 12 13 * Overview 14 15 Embark makes it easy to choose a command to run based on what is near 16 point, both during a minibuffer completion session (in a way familiar 17 to Helm or Counsel users) and in normal buffers. Bind the command 18 =embark-act= to a key and it acts like prefix-key for a keymap of 19 /actions/ (commands) relevant to the /target/ around point. With point on 20 an URL in a buffer you can open the URL in a browser or eww or 21 download the file it points to. If while switching buffers you spot an 22 old one, you can kill it right there and continue to select another. 23 Embark comes preconfigured with over a hundred actions for common 24 types of targets such as files, buffers, identifiers, s-expressions, 25 sentences; and it is easy to add more actions and more target types. 26 Embark can also collect all the candidates in a minibuffer to an 27 occur-like buffer or export them to a buffer in a major-mode specific 28 to the type of candidates, such as dired for a set of files, ibuffer 29 for a set of buffers, or customize for a set of variables. 30 31 ** Acting on targets 32 33 You can think of =embark-act= as a keyboard-based version of a 34 right-click contextual menu. The =embark-act= command (which you should 35 bind to a convenient key), acts as a prefix for a keymap offering you 36 relevant /actions/ to use on a /target/ determined by the context: 37 38 - In the minibuffer, the target is the current top completion 39 candidate. 40 - In the =*Completions*= buffer the target is the completion at point. 41 - In a regular buffer, the target is the region if active, or else the 42 file, symbol, URL, s-expression or defun at point. 43 44 Multiple targets can be present at the same location and you can cycle 45 between them by repeating the =embark-act= key binding. The type of 46 actions offered depend on the type of the target. Here is a sample of 47 a few of the actions offered in the default configuration: 48 49 - For files you get offered actions like deleting, copying, 50 renaming, visiting in another window, running a shell command on the 51 file, etc. 52 - For buffers the actions include switching to or killing the buffer. 53 - For package names the actions include installing, removing or 54 visiting the homepage. 55 - For Emacs Lisp symbols the actions include finding the definition, 56 looking up documentation, evaluating (which for a variable 57 immediately shows the value, but for a function lets you pass it 58 some arguments first). There are some actions specific to variables, 59 such as setting the value directly or though the customize system, 60 and some actions specific to commands, such as binding it to a key. 61 62 By default when you use =embark-act= if you don't immediately select an 63 action, after a short delay Embark will pop up a buffer showing a list 64 of actions and their corresponding key bindings. If you are using 65 =embark-act= outside the minibuffer, Embark will also highlight the 66 current target. These behaviors are configurable via the variable 67 =embark-indicators=. Instead of selecting an action via its key binding, 68 you can select it by name with completion by typing =C-h= after 69 =embark-act=. 70 71 Everything is easily configurable: determining the current target, 72 classifying it, and deciding which actions are offered for each type 73 in the classification. The above introduction just mentions part of 74 the default configuration. 75 76 Configuring which actions are offered for a type is particularly easy 77 and requires no programming: the variable =embark-keymap-alist= 78 associates target types with variables containing keymaps, and those 79 keymaps containing bindings for the actions. (To examine the available 80 categories and their associated keymaps, you can use =C-h v 81 embark-keymap-alist= or customize that variable.) For example, in the 82 default configuration the type =file= is associated with the symbol 83 =embark-file-map=. That symbol names a keymap with single-letter key 84 bindings for common Emacs file commands, for instance =c= is bound to 85 =copy-file=. This means that if you are in the minibuffer after running 86 a command that prompts for a file, such as =find-file= or =rename-file=, 87 you can copy a file by running =embark-act= and then pressing =c=. 88 89 These action keymaps are very convenient but not strictly necessary 90 when using =embark-act=: you can use any command that reads from the 91 minibuffer as an action and the target of the action will be inserted 92 at the first minibuffer prompt. After running =embark-act= all of your 93 key bindings and even =execute-extended-command= can be used to run a 94 command. For example, if you want to replace all occurrences of the 95 symbol at point, just use =M-%= as the action, there is no need to bind 96 =query-replace= in one of Embark's keymaps. Also, those action keymaps 97 are normal Emacs keymaps and you should feel free to bind in them 98 whatever commands you find useful as actions and want to be available 99 through convenient bindings. 100 101 The actions in =embark-general-map= are available no matter what type 102 of completion you are in the middle of. By default this includes 103 bindings to save the current candidate in the kill ring and to insert 104 the current candidate in the previously selected buffer (the buffer 105 that was current when you executed a command that opened up the 106 minibuffer). 107 108 Emacs's minibuffer completion system includes metadata indicating the 109 /category/ of what is being completed. For example, =find-file='s 110 metadata indicates a category of =file= and =switch-to-buffer='s metadata 111 indicates a category of =buffer=. Embark has the related notion of the 112 /type/ of a target for actions, and by default when category metadata 113 is present it is taken to be the type of minibuffer completion 114 candidates when used as targets. Emacs commands often do not set 115 useful category metadata so the [[https://github.com/minad/marginalia][Marginalia]] package, which supplies 116 this missing metadata, is highly recommended for use with Embark. 117 118 Embark's default configuration has actions for the following target 119 types: files, buffers, symbols, packages, URLs, bookmarks, and as a 120 somewhat special case, actions for when the region is active. You can 121 read about the [[https://github.com/oantolin/embark/wiki/Default-Actions][default actions and their key bindings]] on the GitHub 122 project wiki. 123 124 ** The default action on a target 125 126 Embark has a notion of default action for a target: 127 128 - If the target is a minibuffer completion candidate, then the default 129 action is whatever command opened the minibuffer in the first place. 130 For example if you run =kill-buffer=, then the default action will be 131 to kill buffers. 132 - If the target comes from a regular buffer (i.e., not a minibuffer), 133 then the default action is whatever is bound to =RET= in the keymap of 134 actions for that type of target. For example, in Embark's default 135 configuration for a URL found at point the default action is 136 =browse-url=, because =RET= is bound to =browse-url= in the =embark-url-map= 137 keymap. 138 139 To run the default action you can press =RET= after running =embark-act=. 140 Note that if there are several different targets at a given location, 141 each has its own default action, so first cycle to the target you want 142 and then press =RET= to run the corresponding default action. 143 144 There is also =embark-dwim= which runs the default action for the first 145 target found. It's pretty handy in non-minibuffer buffers: with 146 Embark's default configuration it will: 147 148 - Open the file at point. 149 - Open the URL at point in a web browser (using the =browse-url= 150 command). 151 - Compose a new email to the email address at point. 152 - In an Emacs Lisp buffer, if point is on an opening parenthesis or 153 right after a closing one, it will evaluate the corresponding 154 expression. 155 - Go to the definition of an Emacs Lisp function, variable or macro at 156 point. 157 - Find the file corresponding to an Emacs Lisp library at point. 158 159 ** Working with sets of possible targets 160 161 Besides acting individually on targets, Embark lets you work 162 collectively on a set of target /candidates/. For example, while you are 163 in the minibuffer the candidates are simply the possible completions 164 of your input. Embark provides three main commands to work on candidate 165 sets: 166 167 - The =embark-act-all= command runs the same action on each of the 168 current candidates. It is just like using =embark-act= on each 169 candidate in turn. (Because you can easily act on many more 170 candidates than you meant to, by default Embark asks you to confirm 171 uses of =embark-act-all=; you can turn this off by setting the user 172 option =embark-confirm-act-all= to =nil=.) 173 174 - The =embark-collect= command produces a buffer listing all the current 175 candidates, for you to peruse and run actions on at your leisure. 176 The candidates are displayed as a list showing additional annotations. 177 178 The Embark Collect buffer is "dired-like": you can mark and unmark 179 candidates with =m= and =u=, you can unmark all marked candidates with =U= 180 or toggle the marks with =t=. In an Embark Collect buffer 181 =embark-act-all= is bound to =A= and will act on all currently marked 182 candidates if there any, and will act on all candidates if none are 183 marked. 184 185 - The =embark-export= command tries to open a buffer in an appropriate 186 major mode for the set of candidates. If the candidates are files 187 export produces a Dired buffer; if they are buffers, you get an 188 Ibuffer buffer; and if they are packages you get a buffer in 189 package menu mode. 190 191 If you use the grepping commands from the [[https://github.com/minad/consult/][Consult]] package, 192 =consult-grep=, =consult-git-grep= or =consult-ripgrep=, then you should 193 install the =embark-consult= package, which adds support for exporting a 194 list of grep results to an honest grep-mode buffer, on which you can 195 even use [[https://github.com/mhayashi1120/Emacs-wgrep][wgrep]] if you wish. 196 197 When in doubt choosing between exporting and collecting, a good rule 198 of thumb is to always prefer =embark-export= since when an exporter to a 199 special major mode is available for a given type of target, it will be 200 more featureful than an Embark collect buffer, and if no such exporter 201 is configured the =embark-export= command falls back to the generic 202 =embark-collect=. 203 204 These commands are always available as "actions" (although they do not 205 act on just the current target but on all candidates) for =embark-act= 206 and are bound to =A=, =S= (for "snapshot"), and =E=, respectively, in 207 =embark-general-map=. This means that you do not have to bind your own 208 key bindings for these (although you can, of course!), just a key 209 binding for =embark-act=. 210 211 In Embark Collect or Embark Export buffers that were obtained by 212 running =embark-collect= or =embark-export= from within a minibuffer 213 completion session, =g= is bound to a command that restarts the 214 completion session, that is, the command that opened the minibuffer is 215 run again and the minibuffer contents restored. You can then interact 216 normally with the command, perhaps editing the minibuffer contents, 217 and, if you wish, you can rerun =embark-collect= or =embark-export= to get 218 an updated buffer. 219 220 *** =embark-live= a live-updating variant of =embark-collect= 221 222 Finally, there is also an =embark-live= variant of the =embark-collect= 223 command which automatically updates the collection after each change 224 in the source buffer. Users of a completion UI that automatically 225 updates and displays the candidate list (such as Vertico, Icomplete, 226 Selectrum, Fido-mode, or MCT) will probably not want to use 227 =embark-live= from the minibuffer as they will then have two live 228 updating displays of the completion candidates! 229 230 A more likely use of =embark-live= is to be called from a regular buffer 231 to display a sort of live updating "table of contents" for the buffer. 232 This depends on having appropriate candidate collectors configured in 233 =embark-candidate-collectors=. There are not many in Embark's default 234 configuration, but you can try this experiment: open a dired buffer in 235 a directory that has very many files, mark a few, and run =embark-live=. 236 You'll get an Embark Collect buffer containing only the marked files, 237 which updates as you mark or unmark files in dired. To make 238 =embark-live= genuinely useful other candidate collectors are required. 239 The =embark-consult= package (documented near the end of this manual) 240 contains a few: one for imenu items and one for outline headings as 241 used by =outline-minor-mode=. Those collectors really do give 242 =embark-live= a table-of-contents feel. 243 244 ** Switching to a different command without losing what you've typed 245 246 Embark also has the =embark-become= command which is useful for when 247 you run a command, start typing at the minibuffer and realize you 248 meant a different command. The most common case for me is that I run 249 =switch-to-buffer=, start typing a buffer name and realize I haven't 250 opened the file I had in mind yet! I'll use this situation as a 251 running example to illustrate =embark-become=. When this happens I can, 252 of course, press =C-g= and then run =find-file= and open the file, but 253 this requires retyping the portion of the file name you already 254 typed. This process can be streamlined with =embark-become=: while still 255 in the =switch-to-buffer= you can run =embark-become= and effectively 256 make the =switch-to-buffer= command become =find-file= for this run. 257 258 You can bind =embark-become= to a key in =minibuffer-local-map=, but it is 259 also available as an action under the letter =B= (uppercase), so you 260 don't need a binding if you already have one for =embark-act=. So, 261 assuming I have =embark-act= bound to, say, =C-.=, once I realize I 262 haven't open the file I can type =C-. B C-x C-f= to have 263 =switch-to-buffer= become =find-file= without losing what I have already 264 typed in the minibuffer. 265 266 But for even more convenience, =embark-become= offers shorter key 267 bindings for commands you are likely to want the current command to 268 become. When you use =embark-become= it looks for the current command in 269 all keymaps named in the list =embark-become-keymaps= and then activates 270 all keymaps that contain it. For example, the default value of 271 =embark-become-keymaps= contains a keymap =embark-become-file+buffer-map= 272 with bindings for several commands related to files and buffers, in 273 particular, it binds =switch-to-buffer= to =b= and =find-file= to =f=. So when 274 I accidentally try to switch to a buffer for a file I haven't opened 275 yet, =embark-become= finds that the command I ran, =switch-to-buffer=, is 276 in the keymap =embark-become-file+buffer-map=, so it activates that 277 keymap (and any others that also contain a binding for 278 =switch-to-buffer=). The end result is that I can type =C-. B f= to 279 switch to =find-file=. 280 281 * Quick start 282 283 The easiest way to install Embark is from GNU ELPA, just run =M-x 284 package-install RET embark RET=. (It is also available on MELPA.) It is 285 highly recommended to also install [[https://github.com/minad/marginalia][Marginalia]] (also available on GNU 286 ELPA), so that Embark can offer you preconfigured actions in more 287 contexts. For =use-package= users, the following is a very reasonable 288 starting configuration: 289 290 #+begin_src emacs-lisp 291 (use-package marginalia 292 :ensure t 293 :config 294 (marginalia-mode)) 295 296 (use-package embark 297 :ensure t 298 299 :bind 300 (("C-." . embark-act) ;; pick some comfortable binding 301 ("C-;" . embark-dwim) ;; good alternative: M-. 302 ("C-h B" . embark-bindings)) ;; alternative for `describe-bindings' 303 304 :init 305 306 ;; Optionally replace the key help with a completing-read interface 307 (setq prefix-help-command #'embark-prefix-help-command) 308 309 :config 310 311 ;; Hide the mode line of the Embark live/completions buffers 312 (add-to-list 'display-buffer-alist 313 '("\\`\\*Embark Collect \\(Live\\|Completions\\)\\*" 314 nil 315 (window-parameters (mode-line-format . none))))) 316 317 ;; Consult users will also want the embark-consult package. 318 (use-package embark-consult 319 :ensure t ; only need to install it, embark loads it after consult if found 320 :hook 321 (embark-collect-mode . consult-preview-at-point-mode)) 322 #+end_src 323 324 About the suggested key bindings for =embark-act= and =embark-dwim=: 325 - Those key bindings are unlikely to work in the terminal, but 326 terminal users are probably well aware of this and will know to 327 select different bindings. 328 - The suggested =C-.= binding is used by default in (at least some 329 installations of) GNOME to input emojis, and Emacs doesn't even get 330 a chance to respond to the binding. You can select a different key 331 binding for =embark-act= or use =ibus-setup= to change the shortcut for 332 emoji insertion (Emacs 29 will likely use =C-x 8 e e=, in case you 333 want to set the same one system-wide). 334 - The suggested alternative of =M-.= for =embark-dwim= is bound by default 335 to =xref-find-definitions=. That is a very useful command but 336 overwriting it with =embark-dwim= is sensible since in Embark's 337 default configuration, =embark-dwim= will also find the definition of 338 the identifier at point. (Note that =xref-find-definitions= with a 339 prefix argument prompts you for an identifier, =embark-dwim= does not 340 cover this case). 341 342 Other Embark commands such as =embark-act-all=, =embark-become=, 343 =embark-collect=, and =embark-export= can be run through =embark-act= as 344 actions bound to =A=, =B=, =S= (for "snapshot"), and =E= respectively, and 345 thus don't really need a dedicated key binding, but feel free to bind 346 them directly if you so wish. If you do choose to bind them directly, 347 you'll probably want to bind them in =minibuffer-local-map=, since they 348 are most useful in the minibuffer (in fact, =embark-become= only works 349 in the minibuffer). 350 351 The command =embark-dwim= executes the default action at point. Another good 352 keybinding for =embark-dwim= is =M-.= since =embark-dwim= acts like 353 =xref-find-definitions= on the symbol at point. =C-.= can be seen as a 354 right-click context menu at point and =M-.= acts like left-click. The 355 keybindings are mnemonic, both act at the point (=.=). 356 357 Embark needs to know what your minibuffer completion system considers 358 to be the list of candidates and which one is the current candidate. 359 Embark works out of the box if you use Emacs's default tab completion, 360 the built-in =icomplete-mode= or =fido-mode=, or the third-party packages 361 [[https://github.com/minad/vertico][Vertico]], [[https://github.com/raxod502/selectrum/][Selectrum]] or [[https://github.com/abo-abo/swiper][Ivy]]. 362 363 If you are a [[https://emacs-helm.github.io/helm/][Helm]] or [[https://github.com/abo-abo/swiper][Ivy]] user you are unlikely to want Embark since 364 those packages include comprehensive functionality for acting on 365 minibuffer completion candidates. (Embark does come with Ivy 366 integration despite this.) 367 368 * Advanced configuration 369 ** Showing information about available targets and actions 370 371 By default, if you run =embark-act= and do not immediately select an 372 action, after a short delay Embark will pop up a buffer called =*Embark 373 Actions*= containing a list of available actions with their key 374 bindings. You can scroll that buffer with the mouse of with the usual 375 commands =scroll-other-window= and =scroll-other-window-down= (bound by 376 default to =C-M-v= and =C-M-S-v=). 377 378 That functionality is provided by the =embark-mixed-indicator=, but 379 Embark has other indicators that can provide information about the 380 target and its type, what other targets you can cycle to, and which 381 actions have key bindings in the action map for the current type of 382 target. Any number of indicators can be active at once and the user 383 option =embark-indicators= should be set to a list of the desired 384 indicators. 385 386 Embark comes with the following indicators: 387 388 - =embark-minimal-indicator=: shows a messages in the echo area or 389 minibuffer prompt showing the current target and the types of all 390 targets starting with the current one; this one is on by default. 391 392 - =embark-highlight-indicator=: highlights the target at point; 393 also on by default. 394 395 - =embark-verbose-indicator=: displays a table of actions and their key 396 bindings in a buffer; this is not on by default, in favor of the 397 mixed indicator described next. 398 399 - =embark-mixed-indicator=: starts out by behaving as the minimal 400 indicator but after a short delay acts as the verbose indicator; 401 this is on by default. 402 403 - =embark-isearch-highlight-indicator=: this only does something when 404 the current target is the symbol at point, in which case it 405 lazily highlights all occurrences of that symbol in the current 406 buffer, like isearch; also on by default. 407 408 Users of the popular [[https://github.com/justbur/emacs-which-key][which-key]] package may prefer to use the 409 =embark-which-key-indicator= from the [[https://github.com/oantolin/embark/wiki/Additional-Configuration#use-which-key-like-a-key-menu-prompt][Embark wiki]]. Just copy its 410 definition from the wiki into your configuration and customize the 411 =embark-indicators= user option to exclude the mixed and verbose 412 indicators and to include =embark-which-key-indicator=. 413 414 ** Selecting commands via completions instead of key bindings 415 416 As an alternative to reading the list of actions in the verbose or 417 mixed indicators (see the previous section for a description of 418 these), you can press the =embark-help-key=, which is =C-h= by default 419 (but you may prefer =?= to free up =C-h= for use as a prefix) after 420 running =embark-act=. Pressing the help key will prompt you for the name 421 of an action with completion (but feel free to enter a command that is 422 not among the offered candidates!), and will also remind you of the 423 key bindings. You can press =embark-keymap-prompter-key=, which is =@= by 424 default, at the prompt and then one of the key bindings to enter the 425 name of the corresponding action. 426 427 You may think that with the =*Embark Actions*= buffer popping up to 428 remind you of the key bindings you'd never want to use completion to 429 select an action by name, but personally I find that typing a small 430 portion of the action name to narrow down the list of candidates feels 431 significantly faster than visually scanning the entire list of actions. 432 433 If you find you prefer entering actions that way, you can configure 434 embark to always prompt you for actions by setting the variable 435 =embark-prompter= to =embark-completing-read-prompter=. 436 437 ** Quitting the minibuffer after an action 438 439 By default, if you call =embark-act= from the minibuffer it quits the 440 minibuffer after performing the action. You can change this by setting 441 the user option =embark-quit-after-action= to =nil=. Having =embark-act= /not/ 442 quit the minibuffer can be useful to turn commands into little "thing 443 managers". For example, you can use =find-file= as a little file manager 444 or =describe-package= as a little package manager: you can run those 445 commands, perform a series of actions, and then quit the command. 446 447 If you want to control the quitting behavior in a fine-grained manner 448 depending on the action, you can set =embark-quit-after-action= to an 449 alist, associating commands to either =t= for quitting or =nil= for not 450 quitting. When using an alist, you can use the special key =t= to 451 specify the default behavior. For example, to specify that by default 452 actions should not quit the minibuffer but that using =kill-buffer= as 453 an action should quit, you can use the following configuration: 454 455 #+begin_src emacs-lisp 456 (setq embark-quit-after-action '((kill-buffer . t) (t . nil))) 457 #+end_src 458 459 The variable =embark-quit-after-action= only specifies a default, that 460 is, it only controls whether or not =embark-act= quits the minibuffer 461 when you call it without a prefix argument, and you can select the 462 opposite behavior to what the variable says by calling =embark-act= with 463 =C-u=. Also note that both the variable =embark-quit-after-action= and =C-u= 464 have no effect when you call =embark-act= outside the minibuffer. 465 466 If you find yourself using the quitting and non-quitting variants of 467 =embark-act= about equally often, independently of the action, you may 468 prefer to simply have separate commands for them instead of a single 469 command that you call with =C-u= half the time. You could, for example, 470 keep the default exiting behavior of =embark-act= and define a 471 non-quitting version as follows: 472 473 #+begin_src emacs-lisp 474 (defun embark-act-noquit () 475 "Run action but don't quit the minibuffer afterwards." 476 (interactive) 477 (let ((embark-quit-after-action nil)) 478 (embark-act))) 479 #+end_src 480 481 ** Running some setup after injecting the target 482 483 You can customize what happens after the target is inserted at the 484 minibuffer prompt of an action. There are 485 =embark-target-injection-hooks=, that are run by default after injecting 486 the target into the minibuffer. The variable 487 =embark-target-injection-hooks= is an alist associating commands to 488 their setup hooks. There are two special keys: if no setup hook is 489 specified for a given action, the hook associated to =t= is run; and the 490 hook associated to =:always= is run regardless of the action. (This 491 variable used to have the less explicit name of 492 =embark-setup-action-hooks=, so please update your configuration.) 493 494 For example, consider using =shell-command= as an action during file 495 completion. It would be useful to insert a space before the target 496 file name and to leave the point at the beginning, so you can 497 immediately type the shell command to run on that file. That's why in 498 Embark's default configuration there is an entry in 499 =embark-target-injection-hooks= associating =shell-command= to a hook that 500 includes =embark--shell-prep=, a simple helper function that quotes all 501 the spaces in the file name, inserts an extra space at the beginning 502 of the line and leaves point to the left of it. 503 504 Now, the preparation that =embark--shell-prep= does would be useless if 505 Embark did what it normally does after it inserts the target of the 506 action at the minibuffer prompt, which is to "press =RET=" for you, 507 accepting the target as is; if Embark did that for =shell-command= you 508 wouldn't get a chance to type in the command to execute! That is why 509 in Embark's default configuration the entry for =shell-command= in 510 =embark-target-injection-hooks= also contains the function 511 =embark--allow-edit=. 512 513 Embark used to have a dedicated variable =embark-allow-edit-actions= to 514 which you could add commands for which Embark should forgo pressing 515 =RET= for you after inserting the target. Since its effect can also be 516 achieved via the general =embark-target-injection-hooks= mechanism, that 517 variable has been removed to simply Embark. Be sure to update your 518 configuration; if you had something like: 519 520 #+begin_src emacs-lisp 521 (add-to-list 'embark-allow-edit-actions 'my-command) 522 #+end_src 523 524 you should replace it with: 525 526 #+begin_src emacs-lisp 527 (push 'embark--allow-edit 528 (alist-get 'my-command embark-target-injection-hooks)) 529 #+end_src 530 531 532 Also note that while you could abuse =embark--allow-edit= so that you 533 have to confirm "dangerous" actions such as =delete-file=, it is better 534 to implement confirmation by adding the =embark--confirm= function to 535 the appropriate entry of a different hook alist, namely, 536 =embark-pre-action-hooks=. 537 538 Besides =embark--allow-edit=, Embark comes with another function that is 539 of general utility in action setup hooks: =embark--ignore-target=. Use 540 it for commands that do prompt you in the minibuffer but for which 541 inserting the target would be inappropriate. This is not a common 542 situation but does occasionally arise. For example it is used by 543 default for =shell-command-on-region=: that command is used as an action 544 for region targets, and it prompts you for a shell command; you 545 typically do /not/ want the target, that is the contents of the region, 546 to be entered at that prompt! 547 548 ** Running hooks before, after or around an action 549 550 Embark has three variables, =embark-pre-action-hooks=, 551 =embark-post-action-hooks= and =embark-around-action-hooks=, which are 552 alists associating commands to hooks that should run before or after 553 or as around advice for the command when used as an action. As with 554 =embark-target-injection-hooks=, there are two special keys for the 555 alists: =t= designates the default hook to run when no specific hook is 556 specified for a command; and the hook associated to =:always= runs 557 regardless. 558 559 The default values of those variables are fairly extensive, adding 560 creature comforts to make running actions a smooth experience. Embark 561 comes with several functions intended to be added to these hooks, and 562 used in the default values of =embark-pre-action-hooks=, 563 =embark-post-action-hooks= and =embark-around-action-hooks=. 564 565 For pre-action hooks: 566 567 - =embark--confirm= :: Prompt the user for confirmation before executing 568 the action. This is used be default for commands deemed "dangerous", 569 or, more accurately, hard to undo, such as =delete-file= and 570 =kill-buffer=. 571 572 - =embark--unmark-target= :: Unmark the active region. Use this for 573 commands you want to act on the region contents but without the 574 region being active. The default configuration uses this function as 575 a pre-action hook for =occur= and =query-replace=, for example, so that 576 you can use them as actions with region targets to search the whole 577 buffer for the text contained in the region. Without this pre-action 578 hook using =occur= as an action for a region target would be 579 pointless: it would search for the the region contents /in the 580 region/, (typically, due to the details of regexps) finding only one 581 match! 582 583 - =embark--beginning-of-target= :: Move to the beginning of the target 584 (for targets that report bounds). This is used by default for 585 backward motion commands such as =backward-sexp=, so that they don't 586 accidentally leave you on the current target. 587 588 - =embark--end-of-target= :: Move to the end of the target. This is used 589 similarly to the previous function, but also for commands that act 590 on the last s-expression like =eval-last-sexp=. This allow you to act 591 on an s-expression from anywhere inside it and still use 592 =eval-last-sexp= as an action. 593 594 - =embark--xref-push-markers= :: Push the current location on the xref 595 marker stack. Use this for commands that take you somewhere and for 596 which you'd like to be able to come back to where you were using 597 =xref-pop-marker-stack=. This is used by default for =find-library=. 598 599 For post-action hooks: 600 601 - =embark--restart= :: Restart the command currently prompting in the 602 minibuffer, so that the list of completion candidates is updated. 603 This is useful as a post action hook for commands that delete or 604 rename a completion candidate; for example the default value of 605 =embark-post-action-hooks= uses it for =delete-file=, =kill-buffer=, 606 =rename-file=, =rename-buffer=, etc. 607 608 For around-action hooks: 609 610 - =embark--mark-target= :: Save existing mark and point location, mark 611 the target and run the action. Most targets at point outside the 612 minibuffer report which region of the buffer they correspond to 613 (this is the information used by =embark-highlight-indicator= to 614 know what portion of the buffer to highlight); this function marks 615 that region. It is useful as an around action hook for commands that 616 expect a region to be marked, for example, it is used by default for 617 =indent-region= so that it works on s-expression targets, or for 618 =fill-region= so that it works on paragraph targets. 619 620 - =embark--cd= :: Run the action with =default-directory= set to the 621 directory associated to the current target. The target should be of 622 type =file=, =buffer=, =bookmark= or =library=, and the associated directory 623 is what you'd expect in each case. 624 625 - =embark--narrow-to-target= :: Run the action with buffer narrowed to 626 current target. Use this as an around hook to localize the effect of 627 actions that don't already work on just the region. In the default 628 configuration it is used for =repunctuate-sentences=. 629 630 - =embark--save-excursion= :: Run the action restoring point at the end. 631 The current default configuration doesn't use this but it is 632 available for users. 633 634 ** Creating your own keymaps 635 636 All internal keymaps are defined with the standard helper macro 637 =defvar-keymap=. For example a simple version of the file action keymap 638 could be defined as follows: 639 640 #+BEGIN_SRC emacs-lisp 641 (defvar-keymap embark-file-map 642 :doc "Example keymap with a few file actions" 643 :parent embark-general-map 644 "d" #'delete-file 645 "r" #'rename-file 646 "c" #'copy-file) 647 #+END_SRC 648 649 These action keymaps are perfectly normal Emacs 650 keymaps. You may want to inherit from the =embark-general-map= if you 651 want to access the default Embark actions. Note that =embark-collect= 652 and =embark-export= are also made available via =embark-general-map=. 653 654 ** Defining actions for new categories of targets 655 656 It is easy to configure Embark to provide actions for new types of 657 targets, either in the minibuffer or outside it. I present below two 658 very detailed examples of how to do this. At several points I'll 659 explain more than one way to proceed, typically with the easiest 660 option first. I include the alternative options since there will be 661 similar situations where the easiest option is not available. 662 663 *** New minibuffer target example - tab-bar tabs 664 665 As an example, take the new [[https://www.gnu.org/software/emacs/manual/html_node/emacs/Tab-Bars.html][tab bars]] from Emacs 27. I'll explain how 666 to configure Embark to offer tab-specific actions when you use the 667 tab-bar-mode commands that mention tabs by name. The configuration 668 explained here is now built-in to Embark (and Marginalia), but it's 669 still a good self-contained example. In order to setup up tab actions 670 you would need to: (1) make sure Embark knows those commands deal with 671 tabs, (2) define a keymap for tab actions and configure Embark so it 672 knows that's the keymap you want. 673 674 **** Telling Embark about commands that prompt for tabs by name 675 676 For step (1), it would be great if the =tab-bar-mode= commands reported 677 the completion category =tab= when asking you for a tab with 678 completion. (All built-in Emacs commands that prompt for file names, 679 for example, do have metadata indicating that they want a =file=.) They 680 do not, unfortunately, and I will describe a couple of ways to deal 681 with this. 682 683 Maybe the easiest thing is to configure [[https://github.com/minad/marginalia][Marginalia]] to enhance those 684 commands. All of the =tab-bar-*-tab-by-name= commands have the words 685 "tab by name" in the minibuffer prompt, so you can use: 686 687 #+begin_src emacs-lisp 688 (add-to-list 'marginalia-prompt-categories '("tab by name" . tab)) 689 #+end_src 690 691 That's it! But in case you are ever in a situation where you don't 692 already have commands that prompt for the targets you want, I'll 693 describe how writing your own command with appropriate =category= 694 metadata looks: 695 696 #+begin_src emacs-lisp 697 (defun my-select-tab-by-name (tab) 698 (interactive 699 (list 700 (let ((tab-list (or (mapcar (lambda (tab) (cdr (assq 'name tab))) 701 (tab-bar-tabs)) 702 (user-error "No tabs found")))) 703 (completing-read 704 "Tabs: " 705 (lambda (string predicate action) 706 (if (eq action 'metadata) 707 '(metadata (category . tab)) 708 (complete-with-action 709 action tab-list string predicate))))))) 710 (tab-bar-select-tab-by-name tab)) 711 #+end_src 712 713 As you can see, the built-in support for setting the category 714 meta-datum is not very easy to use or pretty to look at. To help with 715 this I recommend the =consult--read= function from the excellent 716 [[https://github.com/minad/consult/][Consult]] package. With that function we can rewrite the command as 717 follows: 718 719 #+begin_src emacs-lisp 720 (defun my-select-tab-by-name (tab) 721 (interactive 722 (list 723 (let ((tab-list (or (mapcar (lambda (tab) (cdr (assq 'name tab))) 724 (tab-bar-tabs)) 725 (user-error "No tabs found")))) 726 (consult--read tab-list 727 :prompt "Tabs: " 728 :category 'tab)))) 729 (tab-bar-select-tab-by-name tab)) 730 #+end_src 731 732 Much nicer! No matter how you define the =my-select-tab-by-name= 733 command, the first approach with Marginalia and prompt detection has 734 the following advantages: you get the =tab= category for all the 735 =tab-bar-*-bar-by-name= commands at once, also, you enhance built-in 736 commands, instead of defining new ones. 737 738 **** Defining and configuring a keymap for tab actions 739 740 Let's say we want to offer select, rename and close actions for tabs 741 (in addition to Embark general actions, such as saving the tab name to 742 the kill-ring, which you get for free). Then this will do: 743 744 #+begin_src emacs-lisp 745 (defvar-keymap embark-tab-actions 746 :doc "Keymap for actions for tab-bar tabs (when mentioned by name)." 747 :parent embark-general-map 748 "s" #'tab-bar-select-tab-by-name 749 "r" #'tab-bar-rename-tab-by-name 750 "k" #'tab-bar-close-tab-by-name) 751 752 (add-to-list 'embark-keymap-alist '(tab . embark-tab-actions)) 753 #+end_src 754 755 What if after using this for a while you feel closing the tab 756 without confirmation is dangerous? You have a couple of options: 757 758 1. You can keep using the =tab-bar-close-tab-by-name= command, but have 759 Embark ask you for confirmation: 760 #+begin_src emacs-lisp 761 (push #'embark--confirm 762 (alist-get 'tab-bar-close-tab-by-name 763 embark-pre-action-hooks)) 764 #+end_src 765 766 2. You can write your own command that prompts for confirmation and 767 use that instead of =tab-bar-close-tab-by-name= in the above keymap: 768 #+begin_src emacs-lisp 769 (defun my-confirm-close-tab-by-name (tab) 770 (interactive "sTab to close: ") 771 (when (y-or-n-p (format "Close tab '%s'? " tab)) 772 (tab-bar-close-tab-by-name tab))) 773 #+end_src 774 775 Notice that this is a command you can also use directly from =M-x= 776 independently of Embark. Using it from =M-x= leaves something to be 777 desired, though, since you don't get completion for the tab names. 778 You can fix this if you wish as described in the previous section. 779 780 *** New target example in regular buffers - short Wikipedia links 781 782 Say you want to teach Embark to treat text of the form 783 =wikipedia:Garry_Kasparov= in any regular buffer as a link to Wikipedia, 784 with actions to open the Wikipedia page in eww or an external browser 785 or to save the URL of the page in the kill-ring. We can take advantage 786 of the actions that Embark has preconfigured for URLs, so all we need 787 to do is teach Embark that =wikipedia:Garry_Kasparov= stands for the URL 788 =https://en.wikipedia.org/wiki/Garry_Kasparov=. 789 790 You can be as fancy as you want with the recognized syntax. Here, to 791 keep the example simple, I'll assume the link matches the regexp 792 =wikipedia:[[:alnum:]_]+=. We will write a function that looks for a 793 match surrounding point, and returns an improper list of the form 794 ='(url actual-url-of-the-page beg . end)= where =beg= and =end= are the 795 buffer positions where the target starts and ends, and are used by 796 Embark to highlight the target (if you have =embark-highlight-indicator= 797 included in the list =embark-indicators=). 798 799 #+begin_src emacs-lisp 800 (defun my-short-wikipedia-link () 801 "Target a link at point of the form wikipedia:Page_Name." 802 (save-excursion 803 (let* ((beg (progn (skip-chars-backward "[:alnum:]_:") (point))) 804 (end (progn (skip-chars-forward "[:alnum:]_:") (point))) 805 (str (buffer-substring-no-properties beg end))) 806 (save-match-data 807 (when (string-match "wikipedia:\\([[:alnum:]_]+\\)" str) 808 `(url 809 ,(format "https://en.wikipedia.org/wiki/%s" 810 (match-string 1 str)) 811 ,beg . ,end)))))) 812 813 (add-to-list 'embark-target-finders 'my-short-wikipedia-link) 814 #+end_src 815 816 * How does Embark call the actions? 817 818 Embark actions are normal Emacs commands, that is, functions with an 819 interactive specification. In order to execute an action, Embark 820 calls the command with =call-interactively=, so the command reads user 821 input exactly as if run directly by the user. For example the 822 command may open a minibuffer and read a string 823 (=read-from-minibuffer=) or open a completion interface 824 (=completing-read=). If this happens, Embark takes the target string 825 and inserts it automatically into the minibuffer, simulating user 826 input this way. After inserting the string, Embark exits the 827 minibuffer, submitting the input. (The immediate minibuffer exit can 828 be disabled for specific actions in order to allow editing the 829 input; this is done by adding the =embark--allow-edit= function to the 830 appropriate entry of =embark-target-injection-hooks=). Embark inserts 831 the target string at the first minibuffer opened by the action 832 command, and if the command happens to prompt the user for input 833 more than once, the user still interacts with the second and further 834 prompts in the normal fashion. Note that if a command does not 835 prompt the user for input in the minibuffer, Embark still allows you 836 to use it as an action, but of course, never inserts the target 837 anywhere. (There are plenty of examples in the default configuration 838 of commands that do not prompt the user bound to keys in the action 839 maps, most of the region actions, for instance.) 840 841 This is how Embark manages to reuse normal commands as actions. The 842 mechanism allows you to use as Embark actions commands that were not 843 written with Embark in mind (and indeed almost all actions that are 844 bound by default in Embark's action keymaps are standard Emacs 845 commands). It also allows you to write new custom actions in such a 846 way that they are useful even without Embark. 847 848 Staring from version 28.1, Emacs has a variable 849 =y-or-n-p-use-read-key=, which when set to =t= causes =y-or-n-p= to use 850 =read-key= instead of =read-from-minibuffer=. Setting 851 =y-or-n-p-use-read-key= to =t= is recommended for Embark users because 852 it keeps Embark from attempting to insert the target at a =y-or-n-p= 853 prompt, which would almost never be sensible. Also consider this as 854 a warning to structure your own action commands so that if they use 855 =y-or-n-p=, they do so only after the prompting for the target. 856 857 Here is a simple example illustrating the various ways of reading 858 input from the user mentioned above. Bind the following commands to 859 the =embark-symbol-map= to be used as actions, then put the point on 860 some symbol and run them with =embark-act=: 861 862 #+begin_src emacs-lisp 863 (defun example-action-command1 () 864 (interactive) 865 (message "The input was `%s'." (read-from-minibuffer "Input: "))) 866 867 (defun example-action-command2 (arg input1 input2) 868 (interactive "P\nsInput 1: \nsInput 2: ") 869 (message "The first input %swas `%s', and the second was `%s'." 870 (if arg "truly " "") 871 input1 872 input2)) 873 874 (defun example-action-command3 () 875 (interactive) 876 (message "Your selection was `%s'." 877 (completing-read "Select: " '("E" "M" "B" "A" "R" "K")))) 878 879 (defun example-action-command4 () 880 (interactive) 881 (message "I don't prompt you for input and thus ignore the target!")) 882 883 (keymap-set embark-symbol-map "X 1" #'example-action-command1) 884 (keymap-set embark-symbol-map "X 2" #'example-action-command2) 885 (keymap-set embark-symbol-map "X 3" #'example-action-command3) 886 (keymap-set embark-symbol-map "X 4" #'example-action-command4) 887 #+end_src 888 889 Also note that if you are using the key bindings to call actions, 890 you can pass prefix arguments to actions in the normal way. For 891 example, you can use =C-u X2= with the above demonstration actions to 892 make the message printed by =example-action-command2= more emphatic. 893 This ability to pass prefix arguments to actions is useful for some 894 actions in the default configuration, such as 895 =embark-shell-command-on-buffer=. 896 897 ** Non-interactive functions as actions 898 899 Alternatively, Embark does support one other type of action: a 900 non-interactive function of a single argument. The target is passed 901 as argument to the function. For example: 902 903 #+begin_src emacs-lisp 904 (defun example-action-function (target) 905 (message "The target was `%s'." target)) 906 907 (keymap-set embark-symbol-map "X 4" #'example-action-function) 908 #+end_src 909 910 Note that normally binding non-interactive functions in a keymap is 911 useless, since when attempting to run them using the key binding you 912 get an error message similar to "Wrong type argument: commandp, 913 example-action-function". In general it is more flexible to write 914 any new Embark actions as commands, that is, as interactive 915 functions, because that way you can also run them directly, without 916 Embark. But there are a couple of reasons to use non-interactive 917 functions as actions: 918 919 1. You may already have the function lying around, and it is 920 convenient to simply reuse it. 921 922 2. For command actions the targets can only be simple string, with 923 no text properties. For certain advanced uses you may want the 924 action to receive a string /with/ some text properties, or even a 925 non-string target. 926 927 * Embark, Marginalia and Consult 928 929 Embark cooperates well with the [[https://github.com/minad/marginalia][Marginalia]] and [[https://github.com/minad/consult][Consult]] packages. 930 Neither of those packages is a dependency of Embark, but both are 931 highly recommended companions to Embark, for opposite reasons: 932 Marginalia greatly enhances Embark's usefulness, while Embark can help 933 enhance Consult. 934 935 In the remainder of this section I'll explain what exactly Marginalia 936 does for Embark, and what Embark can do for Consult. 937 938 ** Marginalia 939 940 Embark comes with actions for symbols (commands, functions, variables 941 with actions such as finding the definition, looking up the 942 documentation, evaluating, etc.) in the =embark-symbol-map= keymap, and 943 for packages (actions like install, delete, browse url, etc.) in the 944 =embark-package-keymap=. 945 946 Unfortunately Embark does not automatically offers you these keymaps 947 when relevant, because many built-in Emacs commands don't report 948 accurate category metadata. For example, a command like 949 =describe-package=, which reads a package name from the minibuffer, 950 does not have metadata indicating this fact. 951 952 In an earlier Embark version, there were functions to supply this 953 missing metadata, but they have been moved to Marginalia, which 954 augments many Emacs command to report accurate category metadata. 955 Simply activating =marginalia-mode= allows Embark to offer you the 956 package and symbol actions when appropriate again. Candidate 957 annotations in the Embark collect buffer are also provided by the 958 Marginalia package: 959 960 - If you install Marginalia and activate =marginalia-mode=, Embark 961 Collect buffers will use the Marginalia annotations automatically. 962 963 - If you don't install Marginalia, you will see only the annotations 964 that come with Emacs (such as key bindings in =M-x=, or the unicode 965 characters in =C-x 8 RET=). 966 967 ** Consult 968 969 The excellent Consult package provides many commands that use 970 minibuffer completion, via the =completing-read= function; plenty of its 971 commands can be considered enhanced versions of built-in Emacs 972 commands, and some are completely new functionality. One common 973 enhancement provided in all commands for which it makes sense is 974 preview functionality, for example =consult-buffer= will show you a 975 quick preview of a buffer before you actually switch to it. 976 977 If you use both Consult and Embark you should install the 978 =embark-consult= package which provides integration between the two. It 979 provides exporters for several Consult commands and also tweaks the 980 behavior of many Consult commands when used as actions with =embark-act= 981 in subtle ways that you may not even notice, but make for a smoother 982 experience. You need only install it to get these benefits: Embark 983 will automatically load it after Consult if found. 984 985 The =embark-consult= package provides the following exporters: 986 987 - You can use =embark-export= from =consult-line=, =consult-outline=, or 988 =consult-mark= to obtain an =occur-mode= buffer. As with the built-in 989 =occur= command you use that buffer to jump to a match and after that, 990 you can then use =next-error= and =previous-error= to navigate to other 991 matches. You can also press =e= to activate =occur-edit-mode= and edit 992 the matches in place! 993 994 - You can export from any of the Consult asynchronous search commands, 995 =consult-grep=, =consult-git-grep=, or =consult-ripgrep= to get a 996 =grep-mode= buffer. Here too you can use =next-error= and =previous-error= 997 to navigate among matches, and, if you install the [[http://github.com/mhayashi1120/Emacs-wgrep/raw/master/wgrep.el ][wgrep]] package, 998 you can use it to edit the matches in place. 999 1000 In both cases, pressing =g= will rerun the Consult command you had 1001 exported from and re-enter the input you had typed (which is similar 1002 to reverting but a little more flexible). You can then proceed to 1003 re-export if that's what you want, but you can also edit the input 1004 changing the search terms or simply cancel if you see you are done 1005 with that search. 1006 1007 The =embark-consult= also contains some candidates collectors that allow 1008 you to run =embark-live= to get a live-updating table of contents for 1009 your buffer: 1010 1011 - =embark-consult-outline-candidates= produces the outline headings of 1012 the current buffer, using =consult-outline=. 1013 - =embark-consult-imenu-candidates= produces the imenu items of 1014 the current buffer, using =consult-imenu=. 1015 - =embark-consult-imenu-or-outline-candidates= is a simple combination 1016 of the two previous functions: it produces imenu items in buffers 1017 deriving from =prog-mode= and otherwise outline headings. 1018 1019 The way to configure =embark-live= (or =embark-collect= and =embark-export= 1020 for that matter) to use one of these function is to add it at the end 1021 of the =embark-candidate-collectors= list. The =embark-consult= package by 1022 default adds the last one, which seems to be the most sensible 1023 default. 1024 1025 Besides those exporters and candidate collectors, the =embark-consult= 1026 package provides many subtle tweaks and small integrations between 1027 Embark and Consult. For example, if you run =embark-collect= from any of 1028 the the =consult-yank= family of commands, you'll see the Embark Collect 1029 buffers has full multi-line kill-ring entries with zebra stripes, so 1030 you can easily tell where they start and end. 1031 1032 Some examples of little tweaks provided by =embark-consult= to the 1033 behavior of Consult commands when used as Embark actions are: 1034 1035 - The asynchronous search commands will start in the directory 1036 associated to the Embark target if that target is a file, buffer, 1037 bookmark or Emacs Lisp library. 1038 1039 - For all other target types, a Consult search command (asynchronous 1040 or not) will search for the text of the target but leave the 1041 minibuffer open so you can interact with the Consult command. 1042 1043 - =consult-imenu= will search for the target and take you directly to 1044 the location if it matches a unique imenu entry, otherwise it will 1045 leave the minibuffer open so you can navigate among the matches. 1046 1047 * Resources 1048 1049 If you want to learn more about how others have used Embark here are 1050 some links to read: 1051 1052 - [[https://karthinks.com/software/fifteen-ways-to-use-embark/][Fifteen ways to use Embark]], a blog post by Karthik Chikmagalur. 1053 - [[https://protesilaos.com/dotemacs/][Protesilaos Stavrou's dotemacs]], look for the section called 1054 "Extended minibuffer actions and more (embark.el and 1055 prot-embark.el)" 1056 1057 And some videos to watch: 1058 1059 - [[https://protesilaos.com/codelog/2021-01-09-emacs-embark-extras/][Embark and my extras]] by Protesilaos Stavrou. 1060 - [[https://youtu.be/qpoQiiinCtY][Embark -- Key features and tweaks]] by Raoul Comninos on the 1061 Emacs-Elements YouTube channel. 1062 - [[https://youtu.be/WsxXr1ncukY][Livestreamed: Adding an Embark context action to send a stream 1063 message]] by Sacha Chua. 1064 - [[https://youtu.be/qk2Is_sC8Lk][System Crafters Live! - The Many Uses of Embark]] by David Wilson. 1065 - [[https://youtu.be/5ffb2at2d7w][Using Emacs Episode 80 - Vertico, Marginalia, Consult and Embark]] by 1066 Mike Zamansky. 1067 1068 * Contributions 1069 1070 Contributions to Embark are very welcome. There is a [[https://github.com/oantolin/embark/issues/95][wish list]] for 1071 actions, target finders, candidate collectors and exporters. For other 1072 ideas you have for Embark, feel free to open an issue on the [[https://github.com/oantolin/embark/issues][issue 1073 tracker]]. Any neat configuration tricks you find might be a good fit 1074 for the [[https://github.com/oantolin/embark/wiki][wiki]]. 1075 1076 Code contributions are very welcome too, but since Embark is now on 1077 GNU ELPA, copyright assignment to the FSF is required before you can 1078 contribute code. 1079 1080 * Acknowledgments 1081 1082 While I, Omar Antolín Camarena, have written most of the Embark code 1083 and remain very stubborn about some of the design decisions, Embark 1084 has received substantial help from a number of other people which this 1085 document has neglected to mention for far too long. In particular, 1086 Daniel Mendler has been absolutely invaluable, implementing several 1087 important features, and providing a lot of useful advice. 1088 1089 Code contributions: 1090 1091 - [[https://github.com/minad][Daniel Mendler]] 1092 - [[https://github.com/clemera/][Clemens Radermacher]] 1093 - [[https://codeberg.org/jao/][José Antonio Ortega Ruiz]] 1094 - [[https://github.com/iyefrat][Itai Y. Efrat]] 1095 - [[https://github.com/a13][a13]] 1096 - [[https://github.com/jakanakaevangeli][jakanakaevangeli]] 1097 - [[https://github.com/mihakam][mihakam]] 1098 - [[https://github.com/leungbk][Brian Leung]] 1099 - [[https://github.com/karthink][Karthik Chikmagalur]] 1100 - [[https://github.com/roshanshariff][Roshan Shariff]] 1101 - [[https://github.com/condy0919][condy0919]] 1102 - [[https://github.com/DamienCassou][Damien Cassou]] 1103 - [[https://github.com/JimDBh][JimDBh]] 1104 1105 Advice and useful discussions: 1106 1107 - [[https://github.com/minad][Daniel Mendler]] 1108 - [[https://gitlab.com/protesilaos/][Protesilaos Stavrou]] 1109 - [[https://github.com/clemera/][Clemens Radermacher]] 1110 - [[https://github.com/hmelman/][Howard Melman]] 1111 - [[https://github.com/astoff][Augusto Stoffel]] 1112 - [[https://github.com/bdarcus][Bruce d'Arcus]] 1113 - [[https://github.com/jdtsmith][JD Smith]] 1114 - [[https://github.com/karthink][Karthik Chikmagalur]] 1115 - [[https://github.com/jakanakaevangeli][jakanakaevangeli]] 1116 - [[https://github.com/iyefrat][Itai Y. Efrat]] 1117 - [[https://github.com/mohkale][Mohsin Kaleem]]